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 full-size slide



  2. 䓛⛳
    @elct9620
    WEB DEVELOPER
    GAME DEVELOPER

    View full-size slide

  3. Why Kubernetes?

    View full-size slide

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

    View full-size slide

  5. Google Kubernetes Engine

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. FROM
    FROM ruby:2.4.3

    View full-size slide

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

    View full-size slide

  11. RUN
    RUN mkdir -p $APP_HOME

    View full-size slide

  12. ADD
    ADD Gemfile $APP_HOME/Gemfile
    ADD Gemfile.lock $APP_HOME/Gemfile.lock

    View full-size slide

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

    View full-size slide

  14. ADD AGAIN…
    ADD . $APP_HOME

    View full-size slide

  15. Before Start Application
    RUN rake assets:precompile

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  21. 其實就是 Google Bucket
    Google Container Registry

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  24. 回到正題⋯⋯
    Kubernetes

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  30. Service
    Pod Pod
    Pod Pod
    rails.svc.cluster.local

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  38. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  41. 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 full-size slide

  42. 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 full-size 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 full-size 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 full-size 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 full-size slide

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

    View full-size slide

  47. 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 full-size slide

  48. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  54. gem install kubec

    View full-size slide

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

    View full-size slide

  56. 跟 cap install 一樣
    kubec install

    View full-size slide

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

    View full-size slide

  58. 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 full-size slide

  59. 跟 cap staging deploy 一樣
    kubec staging deploy

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  62. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  65. 自動化?
    CI/CD

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  68. Build Docker Image
    Push to Registry
    Apply Config

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide