Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

管理画面にGitOpsを導入しました 〜DBマイグレーション編〜

こんにちは。広告技術部の yamaYu です。 広告サービスのバックエンド〜インフラを中心に触っています。 最近は専らパルデアの大地を駆け回る日々です。

今回の記事ですが、Kubernetes 上で管理している Rails 製システムの DB マイグレーションの扱いについて書きました。 下の記事の続編になっているため、こちらも参考にしていただけると幸いです。

tech.gunosy.io tech.gunosy.io

Kubernetes 上でいいかんじに DB マイグレーションしたい

前回までの記事で、Rails 製の管理画面が現状抱える CI/CD の課題の整理と GitOps で解決できるかの検討を行い、 Kubernetes 上で GitOps パターンを実現するツールである Argo CD を実際に導入することでその課題の一部を解決しました。 この記事では前回までで未解決の課題であった DB マイグレーション の扱いにフォーカスします。

DB スキーマに変更があった場合、新しいバージョンの Pod をデプロイする前に DB マイグレーションを実行する必要があります。 CI/CD ツールには DB へのアクセス権限を持たせない場合、Kubernetes の Job 等で DB マイグレーションのプロセスを走らせることになると思いますが、 Kubernetes 上のリソース同士は基本的に非同期にしか連携できないため、DB マイグレーション → 新しいバージョンの Pod の起動という順序を保証する仕組みが必要になります。

  • DB マイグレーションが完了してから新しいバージョンの Pod を起動する

というのが今回やりたいことです。

Sync Phases, Waves, Resource Hooks

結論としては Argo CD の機能でこれを実現することができました。

Argo CD には Sync Phase という概念があり、pre-syncsyncpost-sync の三段階にデプロイのタイミングが分かれています*1Resource Hooks で Sync Phase を指定したアノテーションを各 Kubernetes リソースに付与することでデプロイ順序を設定できます。 もっと詳細な設定が必要な場合には Sync Wave を用いることで同一 Phase 内でのより細かい順序を整数値で定義することも可能です。

metadata:
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/sync-wave: "5"

Resource Hooks を用いた DB マイグレーション

今回は hook: PreSync を設定することでデプロイ時に最初にDBマイグレーションJobが実行されるようにしました。 また Job が削除されるタイミングも指定でき、hook-delete-policy: BeforeHookCreation とすることで次回 sync 実行時まで Job を残しています。 これにより、ログが追いやすくなります。 余談ではありますが、args の部分ではマイグレーション結果を SlackのIncoming Webhook で通知もしています。

apiVersion: batch/v1
kind: Job
metadata:
  name: rails-migration
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
︙
spec:
  template:
    spec:
      containers:
        - name: rails-migration
          image: rails-image
          command: ["/bin/sh", "-c"]
          args:
            - |
              RESULT=$(bundle exec rails db:migrate);
              RESULT=${RESULT:-"No DB migration"};
              TEXT="DB migration result\n*environment*: ${RAILS_ENV:-development}\n"'```\n'"${RESULT}\n"'```';
              curl -X POST -H 'Content-type: application/json' \
                --data '{"channel": "#deploy_channel", "username": "Rail DB Migration", "icon_emoji": ":rails:", "text": "'"${TEXT}"'" }' \
                ${SLACK_WEB_HOOK_URL};
              echo $TEXT
︙

Slack通知の例

まとめ

Rails のサービスを Kubernetes 上にデプロイする際に問題になる DB マイグレーションについて、Argo CD の Sync Phase と Resource Hooks を用いて同期的に実行する方法を扱いました。 本記事が読者様の一助になれば幸いです。

*1:マニフェストファイルと実リソースの同期の意味で sync という単語が使われてます