- バックエンド / リーダー候補
- PdM
- Webエンジニア(シニア)
- Other occupations (17)
- Development
- Business
Wantedly における漸進的な Argo CD 導入の取り組み
Photo by Alessia Cocconi on Unsplash
こんにちは。 Infrastructure Squad でエンジニアをしている千葉 (@tomoasleep) です。
Wantedly では、Kubernetes (以下 k8s と表記) をサービス基盤として、k8s クラスタ上で、ほぼ全てのサービスを運用しています。
Wantedly では早くから k8s を採用していたため、独自の自動化によって運用の効率化を図ってきました。当時はこれにより解決した問題もある一方、
- k8s クラスタへの Delivery 方法が複数存在し、手動のものと自動のものが混在している
- 自分たち独自の仕組みに合わせて k8s manifest 管理方法もやや特殊な方法になっている
というやや癖の強い運用となっていたり、この独自の運用でカバーできていない課題も多い状態でした。
今回これらのカバー出来ていない課題を解決するべく、今回 Argo CD の導入を行いました。また導入にあたっては、Argo CD のベストプラクティスに合わせて、既存の仕組みをリプレイスする、という導入方法ではなく、既存の基盤の課題解決に重点を起き、既存の基盤と Argo CD をうまく融合させるように、連続性を重視した形で導入を行いました。
この記事では、Wantedly における Argo CD の導入の背景としてあった課題、それを解決するためにどう Argo CD を導入したか、導入してどうだったかを紹介していきます。
Wantedly におけるマイクロサービスの k8s manifest 管理とその課題
Wantedly における、マイクロサービスとリポジトリ、 CI/CD の構成
最初に Wantedly での k8s の構成と、その設定 (k8s manifest) の管理方法について説明します。
Wantedly のサービスはマイクロサービスアーキテクチャで構成されており、全てのマイクロサービスを1つの k8s クラスタ上に収納するマルチテナント方式で稼働しています。
また、各マイクロサービス毎に、
- 1つの GitHub リポジトリを所有するソースコードの他に、そのマイクロサービスに必要となる k8s manifest もそのリポジトリに収納する
- 1つの Kubernetes namespace を所有する
- 1つの Docker Image を所有する各 commit 毎に、その ID と同名の Docker tag を用意する
という規約を設けて管理しています。
Wantedly では k8s resource の変更が部分的に自動化されていた
Wantedly 内では、こうした構成の各マイクロサービスで k8s に関わる変更を行う操作として、大きく2種類が存在します。この記事では、便宜上、以下のように定義します。
- Deploy: k8s クラスタの Deployment resource の参照する Docker Image Tag を変更
- 「アプリケーションのデプロイ」に相当
- Apply: k8s クラスタの各種 resource を kubectl apply (相当のコマンド) によって変更
前者の Deploy は頻繁に発生する作業であるため、k8ship というツールを開発し、社内 CLI ツールの kube に組み込むことで、アプリケーションエンジニアまたは CI が kube <クラスタ名> deploy と実行すればデプロイが行える仕組みを提供していました。この際に GitHub リポジトリ内の k8s manifest の内容は変更せず、ソースコードの変更を master branch に push すれば、自動で Docker Image が入れ替わる、という体験を開発者に提供していました。
ただ、後者の Apply に関しては、k8s manifest の内容を変更したのち、手動で kubectl apply を実行する必要がありました。Wantedly が k8s の利用を始めた当初は、 世間的にも k8s manifest の CD を行うベストプラクティスがまだ広まっておらず、当時は Apply の頻度も少ないということで、これの自動化は行っていませんでした。
ただ、Apply 作業が自動化されていないことが、マイクロサービスプラットフォームを運用していく上での大きな課題となっていきました。
手動 Apply の課題
手動で Apply することによる課題はもちろん様々ありますが、 Wantedly において特に大きな課題は以下の2つでした。
- サービス基盤の変更を各マイクロサービスに波及させるための作業コストが大きくなること
- 作業ミスなどによって、一部アプリケーションの k8s manifest が git リポジトリと乖離すること
各マイクロサービスの k8s resource の変更に手間がかかる
手での Apply で大きく問題になるのは「各マイクロサービスの k8s resource の変更に手間がかかる」ということです。
開発者がよく行うオペレーションとしては、「CronJob や Argo Workflow などの特定のタイミングで処理を行う k8s resource を追加すること」で、この際に Apply が必要になるのですが、Apply は普段行わない作業が必要であることから、学習コストがかかったり、Infrastructure Squad からのサポートが必要になることがありました。
また、Infrastructure Squad としても、Wantedly ではマイクロサービスアーキテクチャでの開発を行っているため、「各マイクロサービスの k8s resource を変更する」ということは、度々発生し、ここに手間がかかることは、基盤の改善のボトルネックとなっていました。
GitHub リポジトリと k8s クラスタの状態の乖離
また、「GitHub リポジトリと k8s クラスタの状態の乖離」も大きな課題としてありました。
やはり手動となると、apply, delete を行うのをし忘れたり、開発時や、障害対応時に一時的に手で設定を変更した場合にそれを戻し忘れることによる乖離というのは、一定数発生していました。
これにより、意図とは異なる挙動が発生する状況が発生し、時にはサービス稼働への影響につながるという事故も発生していました。
手でやっているのでこういったオペレーションミスが発生する、というのは当然避けられないのですが、特に Wantedly においては、
- k8s resource に対する操作が複数種類あり、一部が自動化されているため、かえって混乱しやすい、正しいオペレーションを把握するのが難しい
- k8s resource に対する操作が行えるメンバーを Infrastructure Squad に限定せず、 (kube) などの社内ツールを通して) 開発者が広く行えるようにしている
ということから、こういったオペレーションミスも発生しやすい要素がありました。
手動 Apply の課題解決のために Argo CD を導入する
これらの「手動 Apply による課題」を解決するために Apply の自動化を行うことにしました。そのために、Argo CD の導入を行うことにしました。
Argo CD は、 Kubernetes における CD (Continous Delivery) ツールです。
Argo CD の特徴は、その CD の手法です。 Argo CD は k8s クラスタ内で稼働しながら、指定した Git リポジトリと k8s resource を参照し続け、Git リポジトリと k8s resource に差分が生じたら、Git リポジトリの状態を k8s resource に Apply して、Git リポジトリの状態に k8s resource の状態を近づける、という方法で CD を実現しています。 (この手法は GitOps と呼ばれています。)
これまでの運用の課題であった、「GitHub リポジトリと k8s クラスタの状態の乖離」に対して、差分を検知して、自動で状態の乖離を修正する、この GitOps という手法は非常に効果的だと考えました。
GitOps を採用しているツールはいくつかありますが、国内外の利用実績、Web 管理画面を備えているわかりやすさ、 Apply の行う条件の柔軟性などから、 Wantedly では Argo CD を採用することにしました。
導入における課題: 自動化による Apply と Deploy の競合
ところで、Apply を自動化する際にネックになるのは、現状の k8s resource 変更ワークフローが自動化のために最適化されていないこと、より具体的には、「Deploy によって加えられる変更が、Apply によって上書きされてしまうこと」です。
この2種類の作業は、
- Deploy は GitHub リポジトリ の k8s manifest に変更を加えず、k8s resource に直接変更を加える作業
- Apply は GitHub リポジトリの k8s manifest の内容で、 k8s resource の内容を上書きする作業
であることから、 Apply は Deploy の行った変更を上書きしてしまいます。
これまでは、 Apply は手作業で、限られたタイミングで実行するオペレーションだったため、大きく問題になることはありませんでしたが、Apply を自動化する際にはこれまでよりも頻繁に繰り返し実行することになるため、 Deploy の変更が意図しないタイミングで戻されないようにするのに留意が必要になります。
Argo CD の導入のアプローチ: 全てを置き換えるか、一部のみ置き換えるか
Apply と Deploy の競合を念頭に、Argo CD を導入するにあたって、考えられる導入のアプローチは大まかに以下の2つのアプローチです。
- Deploy も (手動で行っていた) Apply も全て Argo CD が行うように置き換える
- (手動で行っていた) Apply を Argo CD が行うように置き換えるその際、Deploy と Apply の競合が発生しないための防止策を行う
最終的には Wantedly では後者のアプローチを採用し、あくまで既存の操作の自動化、という形で導入することにしました。なぜ、そういったアプローチを採用していたかを説明していきます。
採用しなかったアプローチ: 全ての操作を Argo CD が行うように置き換える
まず前者のアプローチの典型例としてあるのは、 k8s manifest を保管するリポジトリ (マニフェストリポジトリ) を用意し、k8s resource を操作したい場合は、マニフェストリポジトリに対して変更を加える、というものです。
Argo CD で推奨されているリポジトリ運用 (ref) として、アプリケーションコードを格納するリポジトリと Argo CD が参照する (k8s manifest 用の) リポジトリを分ける、というものがあります。
この構成はそのプラクティスに沿っていて、複数種類の k8s resource の操作が、「マニフェストリポジトリを介して Argo CD が自動適用する」という形にシンプルになり、 Apply と Deploy の競合問題も解決することが出来ます。
ただし、この構成にする場合、 Argo CD 自体の導入に加えて、
- マニフェストリポジトリ自体の運用ワークフローの構築
- Deploy のワークフローを、マニフェストリポジトリを利用する形に置き換え
などを独自に行う必要が出てきます。これらの運用は Argo CD 自体は解決してくれるものではなく、構築及び運用に必要なコストも、決して小さいものではありません。
現状の Wantedly の CD に関しての課題を整理すると、
- Apply は、サービス基盤開発を行う上でボトルネックとなりうるような、大きな課題が多い
- Deploy は、操作が複数種類存在するなどの認知負荷はあるものの、なにかのボトルネックになるような課題にはなっていない
ことを考えると、まずは手動で Apply を行っている状況を脱することが優先、と判断し、k8s resource の変更作業を Argo CD が行う形に統一するのではなく、「Deploy 自体には手を加えず、人がやっている Apply を Argo CD が代わりに行う」という状態を目指すことにしました。
採用したアプローチ: Deploy と両立するように Argo CD を導入する
「Deploy 自体には手を加えず、人がやっている Apply を Argo CD が代わりに行う」となると、以下のような構成になります。
こうした構成でネックになるのは、先程紹介したとおり、「Deploy によって加えられる変更が、Apply によって上書きされてしまうこと」です。
特に、Argo CD は実質的に自動で Apply を行い続けるため、開発者及び CI が Deploy を行い、Deployment resource を直接書き換えたとしても、 Argo CD が Apply を行うことで戻されて、全く Deploy が機能しなくなってしまいます。
ignoreDifferences を利用して、Deploy への上書きを回避
その対策として利用できるのが、 Argo CD の ignoreDifferences という設定です。
これは、「Argo CD が Apply を特定の条件で行わないようにする」ことが行える設定です。
これにより、例えば以下の記述で Deployment の image が変更された場合に Argo CD が上書きしないようにする箇所を指定することが出来ます。
spec:
ignoreDifferences:
# Prvent Argo CD from detecting changes of these fields.
- group: apps
kind: Deployment
jsonPointers:
- /spec/template/spec/containers/0/image
- /spec/template/spec/containers/1/image
- /spec/template/spec/containers/2/image
- /spec/template/spec/containers/3/image
- /spec/template/spec/containers/4/image
# Prevent Argo CD from overwriting ignored fields.
syncPolicy:
syncOptions:
- RespectIgnoreDifferences=true
より厳密には、 ignoreDifferences は 「Argo CD が Apply を特定の条件で行わないようにする」ための設定で、Argo CD が差分を検出し apply するべきかの判定に干渉する設定で、別の要因で Argo CD が apply を行うとなった場合には ignoreDifferences で設定した箇所も上書きされてしまいます。
ただし、RespectIgnoreDifferences=true の設定を行っていると、 何らかの原因で apply されたとしても ignoreDifferences で設定した箇所は上書きされないようにできます。
導入して改善された点、良かった部分
以上の構成で、Wantedly では、既存の k8s manifest の操作フローを大きく変えず、手動の Apply の自動化として、 Argo CD の導入を行いました。これによって改善された部分、今後の課題などを紹介していきます。
Continous Delivery による、Apply の簡易化と、乖離の抑止
Argo CD を導入することでやはり大きかったのは、「k8s manifest の変更を master branch に push すると k8s クラスタに反映される」という体験を提供することが出来たことです。
これにより、これまで手動で kubectl apply を実行しなくて良くなり、操作ミスなどによる乖離の発生などの心配も少なくなったことと、アプリケーションのソースコードと k8s manifest で、変更方法の体験がほとんど同じものになり、分かりやすい基盤とすることが出来ました。
サービス基盤開発の場面でも、Apply 作業が自動になったことで、これまでよりも開発や改善が行いやすくなりました。
特に、Wantedly では、各マイクロサービスの k8s manifest 管理を行いやすくするために、「k8s manifest の標準化、パッケージ化」を進めてきたのですが、それとの相乗効果により、サービス基盤の改善を各マイクロサービスに波及させることが非常に容易になりました。
GUI により説明が行いやすかった
これは、導入後、というよりは、導入のタイミングで良かった話になりますが、Argo CD が Web 管理画面を持っていることは、チームや組織に導入する際に、プラスになる点が多かったです。
主に、以下の点が Argo CD 導入初期に、チームで使ってもらう際の理解の補助に役に立ちました。
- Argo CD がどのように動いているかがアニメーションから理解しやすい
- Argo CD がどの k8s resource を管理しているかがわかりやすい
- Argo CD の Apply で何らかのエラーがある場合に、その原因がわかりやすい
導入後の課題
Argo CD に関するオペレーションを行う権限の開発者への開放
Argo CD の運用上の課題として、Argo CD は性質上 k8s クラスタに対して非常に強力な権限を持ち、 Argo CD が提供する Application, AppProject などの Custom Resource についても、これへのアクセス権の付与は慎重に検討する必要があります。そのため、現状ではこれらの操作権限は Infra Squad などごくごく限られたメンバーにのみ付与を行っています。
ただ、Wantedly では社内の開発者のためのプラットフォームとして k8s cluster を提供していること、また緊急時の対応などのシーンで Application resource への操作が必要になるシーンが少なからず存在します。これらの操作を行える権限を、社内の開発者に提供しつつ、セキュアな状態を保てるようにすることの両立は今後の課題となります。
GitOps と動作検証の容易さの両立
Argo CD 導入後も、一時的な設定変更などの開発中の動作検証を行いやすくするのも、導入後の課題となっています。
Argo CD で管理するようにしていると、何らかの変更を加える際は、それが一時的なものであっても、 master branch への push が必要になってしまいます。
これだと動作検証のハードルが上がってしまうので、一時的な Argo CD の無効化、あるいは Argo CD が参照するブランチを一時的に変更する方法を提供して、動作検証が容易になるようにしています。
頻繁に k8s resource の変更を行う Infrastructure Squad のメンバーはこれを使うことで、動作検証を行いやすくしていますが、この方法は Application custom resource を変更することから、セキュリティ上、開発者全般に利用を広めることに一定の課題があります。
まとめ
この記事では Wantedly で Argo CD をどのような背景で導入したか、導入にあたってどのような構成を選択したかを紹介しました。
今回の導入で選択した構成は「Argo CD の提示するベストプラクティス」ではなく、潜在的な課題も含め、全ての課題を解決するものではありません。ただ、これらの技術は全て、「何らかの課題を解決するためのもの」で、自分たちの基盤の課題を理解し、全てではないが少しずつでも課題を解決する、物事をインクリメンタルに前に進める、という選択も時には重要になると考えます。
また、今回導入した Argo CD は、運用においては一部課題となるところもありつつも、課題をシンプルな方法で解決する、設定によって現状に合わせた柔軟な導入が行える、という点で優れたツールだと感じました。今回の導入では、「手動 Apply による課題の解決」にフォーカスを当てて導入を行ったため、採用しなかった機能や設計も多くあるのですが、良い機能、良い設計を取り入れつつ、今後も一歩ずつ改善を重ねていこうと考えています。