Argo CDによる継続的デリバリーのベストプラクティスとその実装

こんにちは。Necoの池添(@zoetro)です。 現在San Diegoで開催されているKubeCon 2019に参加しているのですが、時差ボケで寝付けないのでこんなブログを書いています。

さて、現在我々はKubernetes上のアプリケーションの継続的デリバリーを実現するためにArgo CDというツールを利用しています。

github.com

本記事ではArgo CDについて簡単に解説した後、継続的デリバリーのベストプラクティスと具体的な実践例を紹介したいと思います。

Argo CD とは

Kubernetes向けの継続的デリバリーツールとしては、SpinnakerJenkins Xなどが有名です。 これらのツールは継続的デリバリーのパイプラインを統合的に管理・実行するためのツールになっています。

一方のArgo CDは、パイプライン全体を管理するのではなくパイプラインの中の1つの処理として動くコンポーネントになります。 このようなツールは継続的デリバリーコンポーネントと呼ばれることもあります。

今年の3月には、SpinnakerやJenkinsなどのプロジェクトを対象にContinuous Delivery Foundationが発足しました。 一方のArgo CDを開発しているIntuite社は、競合プロダクトであるFluxを開発しているWeave Works社と協力して、GitOpsの継続的デリバリーツールを開発していくようです。

https://www.intuit.com/blog/technology/introducing-argo-flux/amp/www.intuit.com

これからの継続的デリバリーツール界隈は面白くなっていきそうですね。

さて、Argo CDの仕組みを簡単に解説したいと思います。

Argo CD continuous deployments
Introducing Argo CD — Declarative Continuous Delivery for Kubernetes | by Mukulika Kapas | Argo Projectより引用

図に示すように、開発者がアプリケーションのコードをGitリポジトリにPushすると、CIによってビルドされ、 コンテナイメージがコンテナリポジトリに登録されます。 そしてアプリケーションをデプロイするための設定(マニフェスト)をGitリポジトリにPushすると、 Argo CDはそのマニフェストをKubernetesクラスタに適用します。

このようにGitリポジトリに登録されている設定に基づいてデプロイする手法を GitOpsと呼びます。

Best Practices

先日、Argo CDのブログにて、5 GitOps Practicesという記事が公開されました。

この記事では以下の5つの項目をGitOpsのベストプラクティスとして紹介しています。詳細については上記の記事をご覧ください。

  1. Two Repos: One For App Source Code, Another For Manifests
  2. Choose The Right Number Of Deployment Config Repos
  3. Test Your Manifests Before You Commit
  4. Git Manifests Should Not Change Due To External Changes
  5. Plan How You’ll Manage Secrets

NecoプロジェクトではGitOpsによる継続的デリバリーの方法を試行錯誤していたのですが、 幸いにもこれらのプラクティスをすべて実践していました。

ここでは、我々がこれらのプラクティスをどのように実装しているのかを具体的に説明していきたいと思います。

1. Two Repos: One For App Source Code, Another For Manifests

1つ目は、アプリケーションのソースコードのリポジトリと、マニフェストを管理するリポジトリを分離せよというプラクティスです。

Necoプロジェクトでは、マニフェストをneco-appsというリポジトリで管理し、 アプリケーションのソースコードはそれぞれのアプリケーションのリポジトリで管理しています。

neco-apps

Argo CDはHelmやKustomizeなど、いくつかのマニフェストレンダリングツールに対応しています。 neco-appsでは環境ごとの差分管理や、後述するOff-the-Shelf Configurationの利用のしやすさを考慮して、 Kustomizeを採用しています。

また、Gitブランチを利用して環境ごとの適用戦略を定めています。

masterブランチに適用されたマニフェストは、毎晩テストが実行されstageブランチにマージされます。 stageブランチにマージされたマニフェストは、Argo CDによりステージング環境に自動的にデプロイされます。

ステージング環境でしばらくの間、問題なく動作することが確認できたら、手動でstageブランチをreleaseブランチにマージします。 releaseブランチにマージされたマニフェストは、Argo CDにより本番環境に自動的にデプロイされます。

このような戦略により、各環境への継続的デリバリーが実現できています。

2. Choose The Right Number Of Deployment Config Repos

2つ目はマニフェストを管理するリポジトリの数を適切に選ぶというプラクティスです。

サイボウズではKubernetesクラスタの構築と運用をおこなっているNecoプロジェクトのメンバーと、 アプリケーションを開発しKubernetesクラスタ上で運用するメンバーでチームがわかれます。

これらのチームごとにマニフェストを管理するリポジトリを用意しています。

また、Argo CDにはProjectという、 アプリケーションのデプロイ設定をグルーピングして管理する仕組みがあります。

Projectでは、利用可能なリポジトリやデプロイ先のKubernetesクラスタやnamespaceを制限することが可能です。 開発チームは特定のnamespaceにしかアプリケーションをデプロイできないように制限しています。

このようにマニフェストのリポジトリを分離しProjectの機能を活用することで、 各チームは他のチームに影響されることなく、自分たちのタイミングで自由にデプロイをおこなうことが可能になっています。

3. Test Your Manifests Before You Commit

3番目はコミット前にマニフェストをテストせよというプラクティスです。

Necoプロジェクトでは、マニフェストのテストとして三段階のテストを用意しています。

1つはマニフェストのレンダリングを実行し、そのマニフェストのバリデーションをおこなうテストです。

2番目はkindを利用した簡易テストです。 マニフェストがKubernetesクラスタにデプロイできることや、デプロイしたソフトウェアの基本的な機能が利用できることを確認しています。

最後の1つは、以前紹介した仮想データセンター上でのテストです。 データセンターを模擬した仮想環境を利用して、本番とそっくりな環境でのテストが可能になっています。

この仮想データセンター上で、kindで実施している基本的なテストに加え、マニフェストのアップグレードテストもおこなっています。 アップグレードテストでは、現在ステージング環境や本番環境に適用されているマニフェストを用いて環境を構築し、 そこに最新のマニフェストにアップグレードして、環境が壊れないかどうかを確認しています。 これまでこのテストで数多くの不具合を検出することができており、非常に有用なテストであると感じています。

ただし、この仮想データセンターでのテストは実行に時間を要するため、基本的にはstageブランチにマージする前だけに 実行するようにしています。

4. Git Manifests Should Not Change Due To External Changes

4つ目は、外部の変化の影響を受けて、マニフェストが変わってしまわないようにするというプラクティスです。

Necoプロジェクトでは、自前アプリケーションだけでなく外部のOSSのアプリケーションについても、 DockerHubなどに登録されているコンテナイメージを利用せず、neco-containersという リポジトリで管理し、自前でビルドして利用しています。

コンテナをビルドする際には、latestタグは付与せず必ず固定のタグをつけるようにしています。 そして、マニフェストではこの固定タグを指定しています。

これにより、一度リリースされたneco-appsのマニフェストは、いつ利用しても必ず 同じコンテナイメージを指すことが保証できます。

5. Plan How You’ll Manage Secrets

最後は秘密情報を適切に管理せよというプラクティスです。

GitOpsにおける秘密情報管理の決定的な方法がまだなく、様々な手法が提案されている状況です。

我々はまず秘密情報を下記の2つに分類しました。

  1. 漏洩した場合にデータセンターに侵入されたり顧客情報の流出につながる可能性のある秘密情報
  2. 1.に該当しない秘密情報

1.に関してはGitリポジトリでの管理は諦めることにしました。 手動のオペレーションが発生してしまうのですが、そもそも1.に該当する秘密情報は数が少なく 変更することもほとんどないため、運用でそれほど困ることはありません。

一方、2.に関してはGitHubのプライベートリポジトリで暗号化せずに管理し、 Argo CDで自動的にデプロイするようにしています。

Deep Dive into Argo CD

ここからは「5 Best Practices」では紹介されていない、我々がおこなっているプラクティスを紹介したいと思います。

App of Apps Pattern

Argo CDでは、Gitリポジトリから取得してKubernetesにデプロイするマニフェストの単位をアプリケーションと呼びます。 このアプリケーション設定自体もKubernetesリソースであるため、Argo CDで管理することが可能です。

また、複数のアプリケーションを管理するアプリケーションを作ることを App of Apps Pattern と呼びます。

neco-appsでは、以下のようにApp of Apps Patternのマニフェストを用意しています。

App of Apps Patternでアプリケーションリソースを管理すると、Argo CDで管理するアプリケーションが増減したとしても、 Web UIやコマンドラインでArgo CDを操作する必要はなく、マニフェストを追加してGitにPushするだけですみます。

Self Management

Argo CDもKubernetes上で動作するアプリケーションの一つであるため、Argo CDでArgo CD自身を継続的デリバリーすることが可能です。

Self Managementにより、Argo CDの更新も他のアプリケーションと同様におこなえるようになります。

マニフェストの適用状況をモニタリングする

前述したようなテストを実施していたとしても、実際にKubernetesクラスタにデプロイしてみると失敗することがあります。

Argo CDではPrometheus形式のメトリクスを公開しており、アプリケーションのヘルス情報や同期の状態を監視することができます。

Necoプロジェクトでは、Argo CD自体が一定期間ダウンしている場合や、同期の成功や失敗した情報をSlackで通知するようにしています。

Off-the-Shelf Configuration

neco-appsには、自社開発のアプリのマニフェストだけではなく、 Prometheusやcert-manager、Contourなど数多くのOSSのマニフェストが含まれています。

このようなOSSのマニフェストは、GitHub上のファイルとして配置されているもの、 Helm Chartとして配布されているもの、ドキュメントの中に埋め込まれているものなど、 配布方法は様々です。

また、配布されているマニフェストがそのまま利用できることは稀であり、マニフェストになんらかの変更を加えてから、 自分たちのリポジトリに追加することになります。 このように他から持ってきたマニフェストを取り込んで利用することをOff-the-Shelf Configurationと呼びます。

しばらく運用していると、このようなマニフェストはアップストリームのバージョンアップに 追従することが大変手間だと分かってきました。 配布方式に応じて変更点を確認し、自分たちが加えた変更を考慮しつつマニフェストのアップデートをおこなうのは骨が折れます。

Kustomizeでは、既存のマニフェストに変更点をパッチとして適用することができます。 そこでOSSで配布されているマニフェストを変更せず、そのまま自分たちのリポジトリに取り込み、 変更点のみをパッチで管理する方式を模索しています。

この方式であれば、アップストリームでマニフェストが変更されたとしても、そのマニフェストをそのまま持ってきて 上書きしてしまえばアップデートは完了します。

まとめ

本記事では、Argo CDを利用したGitOpsの実践例を紹介しました。 我々が試行錯誤してたどり着いたプラクティスなので、ぜひ参考にしてみてください。