Help us understand the problem. What is going on with this article?

Rails on GKE (Google Kubernetes Engine) 入門

More than 1 year has passed since last update.

本記事の目的

  • 細かいことは置いておき、Rails5.1+PostgresqlのアプリケーションをGKEで公開するところまでを目的とする
  • 今回使用したサンプルアプリケーションは、以下に置いておきます

jwako/rails-gke-sample

Rails5.1プロジェクトの作成

$ rails new rails-gke-sample --webpack=vue

開発環境の設定

Dockerize Rails application

  • 開発環境は、docker-composeで開発できるようにしておく

ビルド

$ docker-compose build

DB作成

$ docker-compose run web rake db:create
$ docker-compose run web rake db:migrate

起動

$ docker-compose up
  • http://localhost:3000 にアクセスする

kubectlのインストール

  • kubectlは、Kubernetesのクライアント
$ gcloud components update
$ gcloud components install kubectl
$ kubectl version --short
Client Version: v1.8.6
The connection to the server localhost:8080 was refused - did you specify the right host or port?

GCPプロジェクトの作成

  • GCPコンソールより、プロジェクトを作成
    • rails-gke-sample-project

APIの有効化

  • GCPコンソールより、作成したプロジェクトで以下のAPIを有効化しておく
Google Container Engine API
Google Cloud Container Builder API
Google Cloud SQL API

Cloud SQL

  • RailsをGCPで動かす場合、DBは、Cloud SQLでMySQL/PostgreSQLインスタンスを立てるのがよい
  • GCPコンソールより、Cloud SQLで、インスタンスの作成からDBの作成までをする
    • Instance: rails-gke-sample-production
    • DBMS: PostgreSQL
    • User: postgres
    • DB: rails_gke_sample_production

アクティブなプロジェクトの設定

  • gcloudコマンドでアクティブなプロジェクトを設定しておく
$ gcloud config set project rails-gke-sample-project
Updated property [core/project].
$ gcloud config set compute/zone us-central1-a
Updated property [compute/zone].

クラスタの作成

  • クラスタは、複数のノードの集合体
  • ノードは、AWSでいうインスタンスに相当
  • ポッドは、1個以上のコンテナの集合体.デプロイの最小単位
  • GKEでクラスタを起動すると、masterとnode(defaultだと3台)が立ち上がる
    • kubectl get nodesでNodesが3台起動していることが確認できる
    • この時点では、Podsは作成されていない
$ gcloud container clusters create rails-gke-sample-cluster --machine-type=n1-standard-1 --zone=us-central1-a

クラスタ情報の取得

$ gcloud container clusters list
NAME                      LOCATION       MASTER_VERSION  MASTER_IP      MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
rails-gke-sample-cluster  us-central1-a  1.8.8-gke.0     35.188.82.xxx  n1-standard-1  1.8.8-gke.0   3          RUNNING

kubectlで確認

  • kubectl cluster-infoでもGKEのクラスタ情報を確認できる
$ kubectl cluster-info
  • ノードの確認
$ kubectl get nodes
NAME                                                  STATUS    ROLES     AGE       VERSION
gke-rails-gke-sample-clu-default-pool-bc05e197-9dd8   Ready     <none>    1m        v1.8.8-gke.0
gke-rails-gke-sample-clu-default-pool-bc05e197-9hx8   Ready     <none>    1m        v1.8.8-gke.0
gke-rails-gke-sample-clu-default-pool-bc05e197-tvt2   Ready     <none>    1m        v1.8.8-gke.0

コンテナのビルド/Container Registryへの登録

  • docker-compose upでローカルで起動できるようにしておく
  • 以下のコマンドで、Container Builderを利用してコンテナのビルドを実施する
  • ビルドに成功するとContainer Registryにイメージが登録される
  • rails-gke-sample部分は、適当に名前をつければ良い
$ gcloud container builds submit --tag gcr.io/rails-gke-sample-project/rails-gke-sample .

環境変数の設定

  • 以下のコマンドで環境変数を登録できる
  • 環境変数は、クラスタに対して登録する (クラスタを削除したら登録し直す必要がある)
  • 設定内容は、
    • GCPコンソールのワークロード > 名前 > 設定
    • ProxyのOverview > Config and Storage > シークレットで確認できる
$ kubectl create secret generic <name> --from-literal=<key>=<value>

Rails

SecretKeyの設定

$ kubectl create secret generic rails --from-literal=secret-key-base=3825d****

DB

サービスアカウントの作成

  • IAMと管理 > サービス アカウントより、サービスアカウントを作成する
    • rails-gke-sample-admin
    • この時、[役割] で、[Cloud SQL] > [Cloud SQL Client] を選択する
  • ダウンロードした秘密鍵を~/.gcloud-secret/に配置しておく

CloudSQLのクレデンシャルに指定

  • ダウンロードした秘密鍵をCloudSQLのクレデンシャルに指定する
$ kubectl create secret generic cloudsql-oauth-credentials --from-file=credentials.json=/Users/hogehoge/.gcloud-secret/rails-gke-sample-project-d0c6a11a46eb.json
secret "cloudsql-oauth-credentials" created
  • 削除する場合
$ kubectl delete secret cloudsql-oauth-credentials

DBアクセスのためのSecretを設定

$ kubectl create secret generic cloudsql-password --from-literal=username=postgres --from-literal=password=fugafuga

アプリケーションのデプロイ

Deploymentオブジェクト

  • Deploymentオブジェクトは、新しいバージョンのリリースを管理するための仕組み
  • マニフェストファイル(deployment.yml)を作成する
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: sample-app
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - image: gcr.io/rails-gke-sample-project/rails-gke-sample
          name: web
          env:
            - name: RAILS_DB_HOST
              value: 127.0.0.1
            - name: RAILS_DB_USER
              valueFrom:
                secretKeyRef:
                  name: cloudsql-password
                  key: username
            - name: RAILS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: cloudsql-password
                  key: password
            - name: SECRET_KEY_BASE
              valueFrom:
                secretKeyRef:
                  name: rails
                  key: secret-key-base
            - name: RAILS_ENV
              value: production
            - name: RACK_ENV
              value: production
            - name: RAILS_SERVE_STATIC_FILES
              value: 'true'
          ports:
            - containerPort: 3000
              name: sample-app
          command: ["bundle", "exec", "rails", "server", "-p", "3000", "-b", "0.0.0.0"]
        - image: b.gcr.io/cloudsql-docker/gce-proxy:1.11
          name: cloudsql-proxy
          command: ["/cloud_sql_proxy",
                    "-instances=rails-gke-sample-project:us-central1:rails-gke-sample-production=tcp:5432",
                    "-credential_file=/secrets/cloudsql/credentials.json"]
          volumeMounts:
            - name: cloudsql-oauth-credentials
              mountPath: /secrets/cloudsql
              readOnly: true
            - name: ssl-certs
              mountPath: /etc/ssl/certs
      volumes:
        - name: cloudsql-oauth-credentials
          secret:
            secretName: cloudsql-oauth-credentials
        - name: ssl-certs
          hostPath:
            path: /etc/ssl/certs

コマンド実行

  • 登録内容は、Proxyのデプロイメントから確認できる
$ kubectl create -f kube/deployment.yml
deployment "sample-app" created

コマンドによる確認

  • Podsが起動するまでに、初回は数分時間がかかる
$ kubectl get deployments
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
sample-app   2         2         2            2           2m
$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
sample-app-c6854f5d6-hvpfm   2/2       Running   0          2m
sample-app-c6854f5d6-th5xc   2/2       Running   0          2m

外部への公開

Serviceオブジェクト

  • Serviceオブジェクトは、クラスタの内外に対してサービスを公開するための仕組み
  • マニフェストファイル(service.yml)を作成
    • ここでは、80ポートを3000ポートと結びつける
apiVersion: v1
kind: Service
metadata:
  name: sample-app
  labels:
    app: sample-app
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 3000
      protocol: TCP
  selector:
    app: sample-app

コマンド実行

$ kubectl create -f kube/service.yml

コマンドによる確認

  • しばらくすると、EXTERNAL-IPで、IPアドレスが付与されるのを確認できる
$ kubectl get services
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
kubernetes   ClusterIP      10.63.240.1    <none>          443/TCP        46m
sample-app   LoadBalancer   10.63.241.63   35.188.172.xxx   80:30516/TCP   1m

外部への公開

  • http://35.188.172.xxx でアクセス

DBのマイグレーション

  • rake db:migrateをいつやるか問題
    • a) コンテナにSSHした後、rake db:migrateコマンドを実行
    • b) Jobを使用する
  • 今回は、簡単のため(a)でやる

アセットのプリコンパイル

  • rake assets:precompileをいつやるか問題
    • a) Dockerfileに含めてしまう
    • b) Jobを使用する
  • 今回は、簡単のため(a)でやる

後始末

Deploymentの削除

$ kubectl delete deployment sample-app
deployment "sample-app" deleted
$ kubectl delete service sample-app
service "sample-app" deleted

クラスタの削除

$ gcloud container clusters delete rails-gke-sample-cluster

CloudSQLの停止

  • GCPコンソールから停止

Tips

コンテナにSSHする方法

  • rails c や rails dbが使える
$ kubectl exec -it <POD NAME> -c <CONTAINER NAME> bash
root@sample-app-6b9f746b6c-5ct48:/my_app#

ログを確認する方法

  • sternを使用すると、複数のPodのログをまとめて参照できるので便利
$ stern sample-app

kubernetes使いは全員 stern を導入すべき – Daisuke Maki – Medium

Kubernetes関連の便利ツール: stern - そんな今日この頃の技術ネタ

wercker/stern: ⎈ Multi pod and container log tailing for Kubernetes

トラブルシューティングの方法

  • Kubernetesにおけるデプロイの失敗は通常、特定のPodが立ち上がらないという状態で現れる。
    • 存在しない、あるいは権限的な問題でアクセスできないコンテナイメージの指定
    • アプリケーション実行時のConfigMapあるいはSecretが存在しない
    • Specオブジェクトが無効
    • リソース制限超過 : Podとコンテナにはそれぞれ、CPUおよびメモリ使用量の制限が設定されていて、これらの制限を超過するとPodの生成が行われない
    • リソースクオータ超過 : リソースクオータは、ノード数の固定されたクラスタを複数チームが共有する場合に、名前空間毎のリソース消費を制限するためのメカニズム
    • アプリのクラッシュ : ‘CrashLoopBackOff’メッセージを伴うローンチエラーで検出可能
    • 起動状態チェックに対するURLからの応答に時間がかかると、タイムアウトが発生してデプロイに失敗
  • 根本原因の特定には‘kubectrl describe’コマンドが有効
    • kubectl describe pod <pod名> を実行すれば、エラーの原因を記述したイベントログが表示される
    • kubectl logs <Pod名> <コンテナ名>

Kubernetesのデプロイに失敗する10の一般的理由

10 Most Common Reasons Kubernetes Deployments Fail (Part 1)

10 Most Common Reasons Kubernetes Deployments Fail (Part 2)

Refs.

RailsをGKEで動かす際に参考にしたアプリケーションのリンク集

  • 別途以下にまとめました

RailsをGKEで動かす際に参考にしたアプリケーションのリンク集 - Qiita

その他記事

RailsアプリをGoogle Container Engineで動かす - Qiita

これでもかって言うくらいコピペでKubernetes(Google Kubernetes Engine)に環境変数の設定からRailsアプリケーションのmigrateも考慮したデプロイが動くコマンドを書いていく - Qiita

Kubernetesでのデプロイ中に'db:migrate'や'db:seed'などのRailsタスクを管理する(翻訳)

Managing Rails tasks such as 'db:migrate' and 'db:seed' on Kubernetes while performing rolling deployments | BigBinary Blog

Deploying Rails on Kubernetes – Adwerx Engineering

Google Container Engine (GKE, Kubernetes) を使ってサービスを外部公開する | つかびーの技術日記

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away