freeeの開発情報ポータルサイト

ArgoCDバージョンアップを安全かつ迅速に行うための取り組み

概要

freeeではAmazon Web Services (AWS) Elastic Kuerbentes Service (EKS) 上にほとんどのアプリケーションが載っており、EKSへのデプロイ基盤としてはOSSの ArgoCD を利用しています。

ArgoCDから各クラスタにデプロイを行うため、非常に中央集権的なアーキテクチャとなっています。そのため、ArgoCDのバージョンアップは安全かつ迅速に行う必要があります。 本記事では、ArgoCDのバージョンアップの際に行っている取り組みをいくつか紹介します。

かなりマニアックですが、イントロダクションとまとめだけでも読んでいただければ幸いです。

イントロダクション

2023/04からfreeeでPlatform Deliveryチームに所属している gussan です。 Platform DeliveryチームはCI/CD全般のPlatform Engineeringを行うチームです。他社さんだとDeveloper eXperienceチームとか、開発者体験チームとかが近いかもしれません。

さて、freee 基盤チーム Advent Calendar 2023 3日目です。 今回はArgoCDのバージョンアップ行う際に私たちが工夫していることを紹介します。

Kubernetes (K8s)は 非常に優れたコンテナオーケストレーションプラットフォームであり、エコシステムも豊富です。 ただ、もちろん全てのユースケースに採用できる基盤ではありません。運用負荷が大きく、事実上専任のSREやPlatformチームが必要になります。 この「運用負荷」にはそもそものK8sの難しさ、アプリケーションデプロイの複雑やマイクロサービス化することによる認知負荷、ミドルウェアのインストール・設定変更・アップデート、さらにはコントロールプレーンの管理やアップデートなど、多種多様な認知レイヤやライフサイクルを持ったものが含まれます。

開発者のデプロイ時の運用負荷を下げるために、freeeではArgoCDというGitOpsに基づくOSSを利用しています。 ArgoCDがデプロイされているEKSから全てのEKSクラスタを中央集権的に管理することにより、SRE・開発者双方の運用・認知負荷を下げています。

freeeにおけるArgoCDアーキテクチャの概念図。1つのArgoCD EKSクラスタから、全てのプロダクトのEKSクラスタにKubernetesリソースをデプロイしている
ArgoCDアーキテクチャ概念図

ArgoCDはfreeeでのCI/CDの中核を担う素晴らしいOSSです。 ArgoCDの力を借り、全てのプロダクトのデプロイを一括して管理することで、開発者・SRE双方に以下のメリットがあります。

  • 開発者として
    • デプロイの抽象化 - GitHubにK8sマニフェストをpushし、PRをmergeし、ArgoCDのGUIでSYNCボタンを押すだけでデプロイが完了する
    • 迅速なデプロイ - K8sレイヤを抽象化してデプロイできるため、デプロイ速度が向上する
    • リッチなGUI - 何か問題があった場合、ArgoCDのリッチなGUIから各リソースの稼働状況やLogなどを確認し、迅速にデバッグできる
  • SREとして
    • 権限統制・監査 - ArgoCDには豊富なRBAC機能やSSO機能、さらにはそれらに基づいたK8s eventを用いた監査機能がある。これにより、権限制御や監査が容易
    • 認知負荷の軽減 - 全てのプロダクトを横断的に1つのインターフェースから確認できるため、認知負荷が下がる
    • 宣言的デプロイの強制 - 全てのリソースはGitOpsを用いて宣言デプロイされており、Gitリポジトリを参照すればどのようなリソースがどのような設定でデプロイされているか明確
    • 手法の共通化 - 単一の手法を用いてデプロイしてるためコンテキストが最小限に抑えられ、有事の際に迅速に対応できる

これにより、かなり大きなプロダクトでも一日に2回以上のデプロイが行われ、 4Keys 指標でもかなり良いパフォーマンスが出ています。 障害やアラート対応の際は開発者とSREが一体となって迅速にロールバックやhotfixなどの対応を行っています。

しかし、全てのアーキテクチャはトレードオフであり、このような中央集権的なアーキテクチャにはArgoCDが単一障害点になることによる以下の欠点があります。

  • ArgoCDが停止すると、全てのアプリケーションのデプロイができなくなる
  • パフォーマンスの問題があると、全ての開発者の開発者体験が悪くなる
  • ArgoCDの設定ミスやバグがあった場合、freeeのシステム全体に影響を及ぼし、最悪の場合お客様に影響が出る可能性がある

これは、ArgoCD自体に変更を加える場合に大きな問題となります。例えば、今回の議題のArgoCDのバージョンアップを行う場合です。 運用担当者の人的ミスや考慮もれ、そもそもArgoCD自体がバグや想定外の挙動をする可能性があります。 もちろん私たちも細心の注意を払って運用しますし、ArgoCDをはじめとするArgo FamilyのOSSコミュニティには適切なレビュープロセスがあり、バグが生じないように最大限配慮されています。

しかし、人間は必ず間違えます。

例えば、最近でもArgoCDのApplicationが全損するといったissueがいくつか報告されています[ 1, 2, 3 ]。 これらは必ずしもArgoCD側の問題ではなく、利用者側の考慮漏れによるものも含まれます。

基盤を管理するチームとして、どのような想定外の挙動をArgoCDがしようが、あるいは運用者がどんなミスをしようが、freeeを利用していただいているエンドユーザに影響が及ぶことがないようにしていくのが責務です。 また、メンテナンス期間はデプロイを止めてしまいます。ArgoCDというプラットフォームを利用する、私たちのチームにとっての大切なユーザであるfreeeのプロダクトチームに対する影響も最小限にするのがDeliveryチームのミッションです。

以上により、ArgoCDのバージョンアップは安全に、かつ迅速に行う必要があります。 本記事ではfreeeにおけるArgoCDのバージョンアップ時の主要な取り組みを、組織・インフラストラクチャ・ArgoCDのレベルに分けて紹介します。 読者の方で、何か他に工夫している事項があれば、ぜひコメントまでお寄せください。

組織レベルでの取り組み

技術というよりは、アップデートする前の事前準備部分です。

アップデートのロードマップを作成し、プロダクトチームに共有する

バージョンアップ作業時はデプロイを止めてもらっていますので、事前に告知します。 ただし、ほぼ全てのプロダクトに影響が出るため、単純にその時間帯デプロイできないというだけではありません。

Production環境が利用できなければリリースロードマップに影響が出るかもしれません。 Staging環境が利用できなければhotfix時の確認作業ができず、hotfixリリースが遅れ、結果としてお客様への影響範囲が広がるかもしれません。 EKSクラスターアップデートは各プロダクトチームに移管しているため、EKSクラスタのアップデートロードマップにも影響が出るかもしれません。

このような理由から、可能な限り早くアップデートのロードマップを提示し、各プロダクトチームに認識してもらう必要があります。 例えば今回はStaging環境とProduction環境で計8回のメンテナンスを予定していましたので(いろいろ工夫して結局6回に納めました)、10月の初め時点で12月末までのメンテナンス期間を提示しました。

今後は月単位で定期メンテナンス期間を設け、よりプロダクトチームがコントロールしやすいように工夫していきたいと考えています。

リリースノートを調べ、SRE・開発者チーム双方に共有する

ArgoCDのUpgradingブログなどを調べどのような変更があるかを調べます。

Platformチーム的な観点としては、新機能や破壊的変更がないかチェックし、チーム内に共有します。 チーム内で対応方針を検討し、ロードマップの中のどこかで頑張って対処します。

もう一つ大事だと思うのは、アップデートによってユーザ視点でどのような利点があるのか、開発者チームに連携することです。 アップデートによって何が嬉しいのか、どのような価値を開発者に提供できるのか、Platformチームから伝えることが大切だと考えています。 主にGUIの観点から便利な機能が追加されていないか検討し、社内向けの記事にして共有します。

Platformチームやセキュリティチームの観点からすれば、セキュリティパッチやサポートバージョンの観点からアップデートが必要なのは明らかですが、開発者チームにとってはアップデートはコストの側面もあると思います。 もちろんfreeersは皆さん優しいので応援してくれますが、お互いにインセンティブが明確な状況が一番物事が円滑にいくであろうと考えます。 そのような状況を実現するために、今後も工夫していきたいです。

インフラストラクチャレベルでの取り組み

インフラストラクチャのレベルでの取り組みを紹介します。

Staging環境を用意して十分にテストする

まず、staging環境で十分にバージョンアップを確認します。 確認対象には単純に動いているかどうかや、ログ、メトリクスが含まれます。 本当に設定レベルで同一か、妥当なメトリクスを監視できているかが重要な点だと考えています。 わずか(と想定しているよう)な設定差分が本番環境での障害を引き起こすことがあるのはよくある話だと思います。メンテナンス時は全Applicationをメンテナンス用の設定に強制的に切り替えるようにしています。

また、メトリクスに関してはPodのCPUやメモリだけでなく、ArgoCD固有のメトリクスも調べています。 例えば、ApplicationのReconciliation queue数を表す app_controller.workqueue.depthapp_reconciliation_queue や、 Syncのqueue数を表す app_sync_queue などが面白い振る舞いをしていました。

ArgoCDクラスタの権限を制限する

常時運用時はArgoCDクラスタに無邪気に強い権限を与えていることも多いと思います。 しかし、バージョンアップなどの特殊運用時はArgoCDの権限を絞っておくようにしています。 例えばK8s RBACレベルでArgoCDの update, delete 権限を削除しておけば、ArgoCDがいかなる挙動をしようがリソースの変更・削除を防ぐことができます。

具体的にはどうやるかですが、freeeではIRSAを用いてArgoCDのIAM権限を切り替えています。 IRSAはPodの K8s ServiceAccount (SA) と AWS IAMロールを紐付ける方法です。 また、EKSではIAMロールを用いてK8sのRBACを設定することができます (aws-auth)。

具体的には以下のようにメンテナンス時にK8s ServiceAccountを切り替えています。 これにより、基盤レベルでArgoCDクラスタの権限を簡単に切り替えることができます。

IRSAを用いたIAMロール切り替えの概念図。KubernetesのServiceAccountを切り替えることで、ArgoCDの権限を強いロール・弱いロールに割り当てている
IRSAを用いたIAMロール切り替えの概念図

ArgoCDレベルでの取り組み

ArgoCDのレイヤで安全弁を設けます。

ApplicationSetsの設定を変更する

まず基本ですが、ApplicationSetsの設定で preserveResourcesOnDeletion を有効化しておきます。 これにより、ApplicationSetをうっかり削除しても、K8sのリソースは残されたままになるため、エンドユーザーへの影響は最小限に抑えられます。 上記のIRSAの設定と合わせて、多層防御になります。

さらに厳密に制御する場合、以下の方法も有力です。

AutoSyncを切る

ArgoCDにはAutoSyncというSyncを自動的に行ってくれる機能がありますが、バージョンアップ時はこれを切っておくのが安全です。 例えばテンプレートエンジン (helm, kustomize) の設定を間違えたり、バグがあると、意図しないマニフェストを生成したりリソースが削除されてしまう可能性があります。 (実際一度バグを踏んで、意図しないマニフェストが生成されるというヒヤリハットがありました)。 AutoSyncは強制的に切っておくようにしています。また、再テンプレート化を強制するため、マニフェストは必ずhard refreshしています。

開発者のSync権限を制限する

メンテナンス期間中は明示的にArgoCDのRBACでSyncを禁止しておくと不慮の事故が防げます。 いくら事前告知しても見落としというのはあるので、仕組みでうっかりSyncがないようにしています。

まとめ

ArgoCDのバージョンアップを行う際のいくつかの工夫を紹介しました。 上記の設定変更の多くは自動化しており、現在はメンテナンス告知〜終了まで2時間程度の時間を告知し、1時間半程度で作業完了します。

最初から完成形を述べているため単純に聞こえるかもしれませんが、現在の形に落ちつくまでには多くの試行錯誤と議論がありました。 安全性が不十分な方向に振れたり、逆に安全性に振り切って利便性が低下し、社内からこれはどうなの?という意見が出る時期もありました。 その中でも、率直かつ前向きな議論ができたのはfreeeの組織文化のおかげだと思います。 議論の中ではSREチームはもちろん開発者チームの方からも有益な指摘をいただきました。この場を借りて感謝します。

いったん上記の方法でArgoCD v2.5からv2.8までアップデートを終えましたが、すでにv2.9がリリースされており、なかなか終わりがないなと思います。 もちろんまだ手順には改善の余地が多くあると感じています。今後も現状に満足せず改善を続けていきたいと思います。

尚、偉そうに書いている私ですが、破壊的変更に対応しようとしてArgoCDのパフォーマンスに悪影響を及ぼしてしまい、開発者が集まるslack チャンネルでごめんなさいしたことを付記しておきます。 Platform Engineerこそ、率先してSLOなどのSREプラクティスを実践しないといけないと強く感じました。

次のアドベントカレンダー

次回、4日目の基盤チームアドベントカレンダーは、てららさんによる インフラ爆速構築記〜freeeの場合〜 です。 EKSやK8sの知識がほとんどないところから、EKS上に新規マイクロサービスを何と数日で構築したという、驚きのスピード感を味わえる記事です。

SRE+開発チームでのコラボレーションがどのように行われているか、どんな段階を踏んで新サービスが立ち上がるかなど、面白い観点がたくさんありました。 私も実はちょっと構築に関わりたかった。ぜひご覧ください。