Tech Racho エンジニアの「?」を「!」に。
  • 開発

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

こんにちは、hachi8833です。BigBinaryシリーズ、今回はKubernetesとRailsの翻訳記事をお送りします。

morimorihoge: アプリケーションログの集約方法(DockerのSTDOUTから取るのかfluentd等で飛ばすのか)などについて、既存の「普通のRailsアプリ」をKubernetesに持っていってproductionで利用するにはまだまだ知見が必要そうかな、と思いました。

概要

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

本記事では、poddeploymentといった用語を含むKubernetesの基本部分を理解していることを前提とします。

問題

RailsアプリをKubernetesでデプロイする状況を考えます。その際、Docker imageのビルドプロセスの一部としてasset:precompileタスクを実行したいとします。

最初のデプロイではdb:migratedb:seedなどのタスクを実行し、後のデプロイではdb:migrateタスクだけを実行したいと考えています。

Docker imageのビルド中はデータベースに接続できないため、その間はこれらのタスクを実行できません。

タスクを実行するうまい方法はないものでしょうか。

解決方法

ここでは、myorg/myapp:v0.0.1という名前のDocker imageがあり、そこにRailsアプリのソースコードが含まれているとします。

Docker imageの中には、データベースへの接続設定に必要なdatabase.ymlマニフェストを配置しておきます。

以下の内容を含むKubernetes deploymentが必要です。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
      - image: myorg/myapp:v0.0.1
        name: myapp
        imagePullPolicy: IfNotPresent
        env:
        - name: DB_NAME
          value: myapp
        - name: DB_USERNAME
          value: username
        - name: DB_PASSWORD
          value: password
        - name: DB_HOST
          value: 54.10.10.245
        ports:
        - containerPort: 80
      imagePullSecrets:
        - name: docker_pull_secret

このテンプレートファイルをmyapp-deployment.ymlという名前で保存します。

テンプレートのオプションや環境変数は必要に応じて変更できます。ここで指定した環境変数はRailsアプリから利用できます。

テンプレートをKubernetesに初めて適用する場合は、次のコマンドを実行します。

$ kubectl create -f myapp-deployment.yml

Docker image名や環境変数などを変更した後で同じテンプレートを適用するには、次のコマンドを実行します。

$ kubectl apply -f myapp-deployment.yml

deploymentテンプレートが適用されると、Kubernetes上にアプリを収容するpodが作成されます。

podを表示するには次のコマンドを実行します。

$ kubectl get pods

アプリは、ここではmyapp-4007005961-1st7sという名前のpod上で動作しています。

db:migrateなどのrakeタスクをこのpodに対して実行するには、次のコマンドを使います。

$ kubectl exec myapp-4007005961-1st7s                              \
          -- bash -c                                               \
          'cd ~/myapp && RAILS_ENV=production bin/rake db:migrate'

db:seed rakeタスクも同じ要領で実行できます。

Kubernetesでのdeploymentの自動化フローが既にあれば、これを応用することでrakeタスクを必要に応じて自動実行したり条件に応じて実行したりできます。

Kubernetesのjobを使わない理由

私たちのところでKubernetesのjobでマイグレーションやseedを実行してみたところ、いくつかの問題が生じました。

  1. rakeタスクがゼロ以外のexitコードを返すと、コマンドがexitコードとしてゼロを返すまでKubernetesのJobがpodをspawnし続けます。

  2. 1.の問題を回避するために、jobのステータスやspawnされたすべてのpodのステータスをチェックする余分なカスタムロジックを追加実装しなければなりませんでした。

  3. KubernetesのjobでコマンドのSTDOUTやSTDERRをキャプチャするのは困難でした。

  4. jobが成功しなかった場合は、手動で終了させるなどの余分な手間をかける必要がありました。これをやっておかないと、同じ名前でKubernetesのjobを作成できなくなります。後のdeploymentでは同じ名前でこれを行うことになるので、これは不都合です。

こうした問題が生じたため、Kubernetesのjobを使わずに問題を解決することにしました。

関連記事


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。