Gunosy Tech Blog

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

管理画面にGitOpsを導入しました 〜GitOpsとは編〜

はじめに

こんにちは。広告技術部のjohnmanjiroです。普段は広告配信のAPIや管理画面を作っています。

広告技術部では、広告配信に関わる様々なアプリケーションを管理しており、その多くがEKSのKubernetesクラスタ上で動作しています。 広告の入稿や審査を行う管理画面もそのうちの一つです。フレームワークにはRailsを使っています。

管理画面をEKSに移行する際の記事はいくつか本ブログにも上がっているので、興味があればぜひご覧ください。

tech.gunosy.io

tech.gunosy.io

今回、その管理画面のCDにGitOpsを導入したので、何回かの記事にわけてご紹介しようと思います。 まずは初回なので、管理画面が抱えていた課題と、そもそもGitOpsとはなんなのか、導入によって課題は解決されるのかについてご紹介します。

また、チーム内でGitOpsの共有に使用したスライドを社外にも出せる形にしてSpeakerDeckにアップロードしておいたので、ご興味のある方は参考にしていただけると幸いです。

speakerdeck.com

管理画面の課題

管理画面のデプロイは下記のフローで行なっており、これによっていくつか課題を抱えていました。

  1. featureブランチをdevelopブランチにマージ
  2. developブランチでCIが発火し、skaffoldでstgクラスタへデプロイ
  3. developブランチでリリースPRが作成される
  4. リリースPRをmasterブランチにマージ
  5. masterブランチでCIが発火し、skaffoldでprdクラスタへデプロイ
  6. データベースのマイグレーションがあれば適宜手動で実行

具体的な課題は下記のようなものです。

  • 遅いCI
    • RSpecの実行に30分近くかかる
    • ロールバック時はRevert PRを作成することで対応するが、緊急時はCIを待てないので権限のある人が強制的にマージしている
  • CI上でのデプロイの失敗
    • podが多いタイミングでデプロイするとCluster Autoscalerが走るためにCIの実行時間が延び、タイムアウトしたりする
  • 手動でのマイグレーション
    • 人的ミスがおこりやすい

これらを解決したいと思い、GitOpsの導入を検討しました。

GitOpsとは

GitOpsとは、GitリポジトリをSingle source of truthとしてアプリケーションとインフラの両方を管理するCD手法です。 2017年にWeaveworksが提唱しました

あくまでCD手法の名称なので、環境によらず実施することができます。とはいえ、実際はKubernetesの文脈で使われることが多い印象です。 この記事でもKubernetesでの利用を前提として紹介します。

GitOps(というよりCD全般)にはPush型とPull型の2種類が存在します。

Push型とPull型

Push型

Push型は、kubectlやskaffoldなどを利用してKubernetesクラスタ外から文字通りPushする形でデプロイする手法です。 既存のデプロイフローはskaffoldを使ってCI経由でデプロイしているので、まさにPush型の一例と言えます。

この場合の構成は下図のようになります。

Push型の構成

Pull型

Pull型は、Kubernetesクラスタ内に Gitリポジトリを監視して差分をapplyする君*1 を置き、Gitリポジトリの変更を検知して変更内容をデプロイする手法です。 デプロイ先であるKubernetesクラスタから変更点をPullしてきているのでPull型というわけですね。

この場合の構成は下図のようになります。

Pull型の構成

一般的にGitOpsと言われているものはPull型です。

なぜPush型よりPull型なのか

GitOpsといえばPull型という話をしましたが、なぜなのでしょうか。 ここでは、Push型におけるデメリットと、Pull型におけるメリットについて述べます。

Push型のデメリット

Push型のデメリットとして、下記が挙げられます*2

  • CIの権限が強すぎる
    • 外からKubernetesクラスタへデプロイするため、認証情報をCIに持たせる必要がある
    • CIを乗っ取られた場合に危険
  • CIとCDを分離できない
    • CIのフロー中(テストの実行後など)でデプロイを発火させるため
    • アプリケーションの開発とインフラ基盤の運用が別チームの場合に運用しづらい
  • Kubernetesのリソースを直接変更したときにGitリポジトリに追従できない
    • 現在の状態を気にしないため
    • Single source of truthにならない

Pull型のメリット

対して、Pull型のメリットには下記が挙げられます。

  • CIのデプロイに関する権限が不要
    • CIがデプロイを行わなくなるため
  • CIとCDを明確に分離できる
    • CIがデプロイを行わなくなるため
  • Gitリポジトリを見ているので、リソースが変わってもGitリポジトリに追従できる
  • 緊急Revert時にアプリケーションのCIを待つ必要がない(後述)

特に開発と運用でチームが分かれている場合は、CIとCDを分けられるということが大きいメリットなのではないでしょうか。 広告技術部では開発と運用を同じチームが担っているのでそこまで大きなメリットというわけではありませんが、ほかの点を踏まえても、Pull型にするメリットは大きいと感じています。

以上のことから、GitOpsではPush型ではなくPull型が使われるというのが一般的です。

GitOpsにおけるPull型の構成

ここまで、Push型とPull型について見てきました。それでは、実際にGitOpsを行う際のPull型の構成はどうなるのでしょうか。 結論から述べると、下図のような構成になります*3

GitOpsでの構成

大きな特徴として、アプリケーションとマニフェストのリポジトリが分かれていることが挙げられます。 これはアプリケーションとマニフェストではライフサイクルやCIの内容が異なるためで、GitOpsのプラクティスとして推奨されている方法です*4

具体的なデプロイフローは下記のようになります。

  1. アプリケーション側でPRをマージ
  2. アプリケーション側でCIが発火し、docker build & pushを行う
  3. アプリケーション側のCIでマニフェスト側のタグを書き換えるPRを作成
  4. マニフェスト側のPRをマージ
  5. マニフェストの変更を検知し、Kubernetes上へ差分をデプロイ

この構成によって、前述したPull型のメリットのうちの「緊急Revert時にアプリケーションのCIを待つ必要がない」が実現できます。

今まではRevert PRでロールバックを行う際、アプリケーションの変更をRevertしていました。そのため、アプリケーションのテストを行うCIが走ってしまいます。 しかし、アプリケーションとマニフェストのリポジトリが分かれることで、マニフェストをRevertするだけでKubernetesリソースのロールバックを行うことができるようになります。 実際の挙動としてはコンテナイメージのタグが1つ前のものに戻るため、イメージのビルドも不要で比較的迅速にロールバックを行えます。

一方で、マニフェストだけをRevertしてもアプリケーションのコードには残っているため、マニフェストのRevert後にアプリケーション側でもRevert PRを作成する必要があります。

GitOpsで課題は解決されるのか

さて、GitOpsについて簡単にご紹介してきましたが、導入によって管理画面の課題は解決できるのでしょうか。

再掲になりますが、もともとの課題は下記でした。

  • 遅いCI
    • RSpecの実行に30分近くかかる
    • ロールバック時はRevert PRを作成することで対応するが、緊急時はCIを待てないので権限のある人が強制的にマージしている
  • CI上でのデプロイの失敗
    • podが多いタイミングでデプロイするとCluster Autoscalerが走るためにCIの実行時間が延び、タイムアウトしたりする
  • 手動でのマイグレーション
    • 人的ミスがおこりやすい

これに対して、GitOpsを導入した場合は下記のようになります。

  • 遅いCI
    • RSpecの実行に30分近くかかる(未解決
    • CIを待てないので強制マージ(解決。マニフェストの短いCIだけを待てばいい)
  • CI上でのデプロイの失敗(解決。CIからのデプロイは行わない)
  • 手動でのマイグレーション(解決。次回以降にご紹介しますが、ArgoCDのHooksを利用します)

アプリケーションのCIに関してはデプロイとは別の文脈なため解決できませんが、それ以外の部分に関しては解決することができます。 以上のことから、既存の課題をある程度解決することができそうだと思い、導入することを決めました。

まとめ

この記事では、GitOpsとはなんなのか、導入によって管理画面の課題は解決されるのかについてご紹介しました。

GitOpsとはGitリポジトリをSingle source of truthとしたCD手法であり、Kubernetesの文脈で使われることが多いです。 Push型とPull型の2種類がありますが、セキュリティやCI/CDの分離などのメリットから、Pull型のものがGitOpsとして認識されています。

検討の結果、既存の課題をある程度解決することができそうだと思い、導入することを決めました。

次回からは実際に管理画面にGitOpsを導入した際の構成等をご紹介できればと思います。お楽しみに!

参考リンク

Guide To GitOps

5 GitOps Best Practices. GitOps has been on the scene for some… | by Alex Collins | Argo Project

*1:具体的にはArgoCDやFluxがこれにあたります

*2:逆にメリットとしては、構成が簡単で実施しやすいということが挙げられます

*3:GunosyではCIにCircleCI、レジストリにECRを使用しているため、それらを使用した構成になっています

*4:https://blog.argoproj.io/5-gitops-best-practices-d95cb0cbe9ff