Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Taipei.rb 像 Capistrano 一樣用 Kubernetes 部署 Rails

蒼時弦や
February 14, 2018

Taipei.rb 像 Capistrano 一樣用 Kubernetes 部署 Rails

蒼時弦や

February 14, 2018
Tweet

More Decks by 蒼時弦や

Other Decks in Programming

Transcript

  1. 像 Capistrano 一樣
    用 Kubernetes 部署 Rails

    View Slide



  2. 䓛⛳
    @elct9620
    WEB DEVELOPER
    GAME DEVELOPER

    View Slide

  3. View Slide

  4. Why Kubernetes?

    View Slide

  5. 找不到 Clone 機器的選項 (/‵Д′)/~ ╧╧
    Google Cloud Platform

    View Slide

  6. Google Kubernetes Engine

    View Slide

  7. Automated container deployment, scaling, and management
    Container Orchestration

    View Slide

  8. 想要用 Kuberneters 要先會做 (Docker) Image
    Container

    View Slide

  9. View Slide

  10. 把安裝環境的指令都寫進去就對了⋯⋯
    Dockerfile

    View Slide

  11. FROM
    FROM ruby:2.4.3

    View Slide

  12. ENV
    ENV LC_ALL C.UTF-8
    ENV TZ Asia/Taipei
    ENV APP_HOME /usr/src/app
    ENV RAILS_ENV production

    View Slide

  13. RUN
    RUN mkdir -p $APP_HOME

    View Slide

  14. ADD
    ADD Gemfile $APP_HOME/Gemfile
    ADD Gemfile.lock $APP_HOME/Gemfile.lock

    View Slide

  15. RUN AGAIN…
    RUN cd $APP_HOME && bundle install --without
    development test --deployment

    View Slide

  16. ADD AGAIN…
    ADD . $APP_HOME

    View Slide

  17. Before Start Application
    RUN rake assets:precompile

    View Slide

  18. EXPOSE / CMD
    WORKDIR $APP_HOME
    EXPOSE 3000
    CMD rails server

    View Slide

  19. 簡單的 Dockerfile 當寫部署伺服器的 Shell Script 就好
    Shell Script

    View Slide

  20. 這會大大影響封裝的時間,穩定後可以把 RUN 合併處理
    但是要注意順序

    View Slide

  21. 封裝 Image 用 -t 給名字
    docker build -t example/app .

    View Slide

  22. docker tag example/app example/app:0.1.0
    用 tag 上版號

    View Slide

  23. 其實就是 Google Bucket
    Google Container Registry

    View Slide

  24. 要上傳到 Google Container Registry 就要明確指定伺服器和專案
    gcr.io/example-1234/app:0.1.0

    View Slide

  25. 因為 GCR 需要登入驗證,所以可以透過 gcloud 指令自動填入認證
    gcloud docker -- push [IMAGE_NAME]

    View Slide

  26. 回到正題⋯⋯
    Kubernetes

    View Slide

  27. 因為會自動分配資源,所以硬碟也會被隨機分配需要另外設定
    今天只討論 Stateless 的情況

    View Slide

  28. 用來定義啟動一個環境的時候需要做什麼,所以會有一個 template 設定
    Deployment 設定

    View Slide

  29. Deployment 建出來的是一個 Pod 單位,可能是多個容器組成
    Pod 的觀念

    View Slide

  30. Deployment 建出來的 Pod 是無法直接被他人使用的,需要定義成服務
    Service 設定

    View Slide

  31. 看幾張圖當範例
    Deployment + Service = ?

    View Slide

  32. Service
    Pod Pod
    Pod Pod
    rails.svc.cluster.local

    View Slide

  33. Service
    rails.svc.cluster.local
    Volume
    Sidekiq
    Rails 5
    Volume
    Sidekiq
    Rails 4

    View Slide

  34. Service
    rails.svc.cluster.local
    Volume
    Sidekiq
    Rails 5
    Volume
    Sidekiq
    Rails 4
    Selector: #app
    #app #v2 #app #v1

    View Slide

  35. 透過 Label / Selector 機制選擇
    Service 對應的不一定是相同的 Deployment

    View Slide

  36. 需要對外暴露才行
    還是只能在 Kubernetes 內部取用

    View Slide

  37. 目前 AWS/GCP 有支援,其他需要透過 Nginx 模擬
    LoadBalancer

    View Slide

  38. GKE 連不上 (/‵Д′)/~ ╧╧
    CloudSQL

    View Slide

  39. 設定檔很複雜,所以我們用 Rake Task 生成
    所以怎麼用?

    View Slide

  40. wc -l vendor/template/*
    33 vendor/template/cronjob.yaml
    70 vendor/template/app.yaml
    62 vendor/template/app_admin.yaml
    49 vendor/template/elasticsearch.yaml
    41 vendor/template/memcached.yaml
    59 vendor/template/mysql.yaml
    49 vendor/template/redis.yaml
    363 total

    View Slide

  41. 先要有 Kuberentes 的 CLI 工具
    gcloud components install kubectl

    View Slide

  42. 用前面在本機封裝的 Dockerfile 生成 example/rails Image
    來啟動一個 Rails 專案

    View Slide

  43. apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: rails
    labels:
    app: web
    spec:
    replicas: 1
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    - name: rails
    image: example/rails
    ports:
    - containerPort: 3000

    View Slide

  44. apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: rails
    labels:
    app: web
    spec:
    replicas: 1
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    - name: rails
    image: example/rails
    ports:
    - containerPort: 3000

    View Slide

  45. apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: rails
    labels:
    app: web
    spec:
    replicas: 1
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    - name: rails
    image: example/rails
    ports:
    - containerPort: 3000

    View Slide

  46. apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: rails
    labels:
    app: web
    spec:
    replicas: 1
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    - name: rails
    image: example/rails
    ports:
    - containerPort: 3000

    View Slide

  47. apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: rails
    labels:
    app: web
    spec:
    replicas: 1
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    - name: rails
    image: example/rails
    ports:
    - containerPort: 3000

    View Slide

  48. Service
    web.svc.cluster.local
    Rails 5 PostgreSQL
    Selector: #app
    #app #db
    Service
    db.svc.cluster.local
    Selector: #db

    View Slide

  49. apiVersion: v1
    kind: Service
    metadata:
    name: web
    labels:
    app: web
    spec:
    type: LoadBalancer
    loadBalancerIP: 172.31.1.10
    ports:
    - port: 80
    targetPort: 3000
    selector:
    app: web

    View Slide

  50. apiVersion: v1
    kind: Service
    metadata:
    name: web
    labels:
    app: web
    spec:
    type: LoadBalancer
    loadBalancerIP: 172.31.1.10
    ports:
    - port: 80
    targetPort: 3000
    selector:
    app: web

    View Slide

  51. apiVersion: v1
    kind: Service
    metadata:
    name: web
    labels:
    app: web
    spec:
    type: NodePort
    ports:
    - port: 80
    targetPort: 3000
    selector:
    app: web

    View Slide

  52. 寫設定檔是為了可以用 -f 直接操作
    kubectl apply -f deploy.yaml

    View Slide

  53. 之後大概寫個 Rake Task 就可以收工
    rake k8s:staging:deploy

    View Slide

  54. 所以要寫 ERB Template 去更新設定檔
    不用改 Image 的版本嗎?

    View Slide

  55. (/‵Д′)/~ ╧╧

    View Slide

  56. View Slide

  57. gem install kubec

    View Slide

  58. View Slide

  59. 寫起來比較親切
    用 Ruby 的方法解決

    View Slide

  60. 跟 cap install 一樣
    kubec install

    View Slide

  61. 跟 config/deploy.rb 一樣
    vim config/kubec.rb

    View Slide

  62. deployment :web do
    label :app, :web
    template do
    label :app, :web
    container :web do
    image fetch(:image, 'elct9620/example')
    port 3000
    env 'DATABASE_URL', 'postgres://...'
    end
    end
    end
    service :web do
    select :app, :web
    node_port
    port 80, 3000
    end

    View Slide

  63. 跟 cap staging deploy 一樣
    kubec staging deploy

    View Slide

  64. 總覽 Kubernetes 部署的狀況
    kubec staging status

    View Slide

  65. 如果有設定檔需要上傳呢?
    cap staging config:push

    View Slide

  66. config :example do
    file './config/application.yaml'
    end
    deployment :web do
    label :app, :ruby
    template do
    label :app, :ruby
    container :web do
    # ...
    config_file 'application.yaml',
    path: '/usr/src/app/config',
    from: :config
    end
    volume :config do
    config :configs,
    'application.yaml' => 'application.yaml'
    end
    end
    end

    View Slide

  67. 利用 Kubernetes 的 ConfigMap/Secret 掛載到 Container 中
    kubec staging config:push

    View Slide

  68. 目前還處於早期開發階段,希望大家協助後續的開發
    https://github.com/5xRuby/kubec

    View Slide

  69. 自動化?
    CI/CD

    View Slide

  70. 和傳統的流程沒什麼差異
    CI

    View Slide

  71. 現階段用現成的服務比較簡單
    CD

    View Slide

  72. Build Docker Image
    Push to Registry
    Apply Config

    View Slide

  73. Jenkins / Gitlab CI 基本上都能做到
    Build Docker Image

    View Slide

  74. 主要難點在於傳到 GCP/AWS 的認證保存
    Push to Registry

    View Slide

  75. 除了認證保管之外還多了 kubectl 環境安裝的問題
    Apply Config

    View Slide

  76. View Slide

  77. 想自己弄就要再多花時間
    Build/Push Image 都支援

    View Slide

  78. 有 Set Image 的選項,不過設定多就不方便
    Apply Config

    View Slide

  79. 直接出設定檔,然後用 apply 的方式更新
    kubec staging deploy:dump > config.yaml

    View Slide

  80. 如果是大量使用 Container 會很方便,不過學習曲線偏高
    Production 環境 Cluster 一般是三台開始,用量不大也暫時不需要考慮
    結論

    View Slide

  81. View Slide