こんにちは。Engimo インフラチームの夏目です。 この記事はEnigmo Advent Calendar 2019の22日目の記事です。
最近はこちらのインタビューでも触れたとおりKubernetesクラスタを作ったり壊したりしていまして、今日の記事はKubernetesにおけるアプリケーションデプロイに関してのお話です。
Kubernetesの継続的デリバリ、どうしてますか?
Kubernetesをプロダクション環境で利用されているそこのあなた!アプリケーションをどうやってデプロイしていますか?
- ローカルでDockerImageをビルド
- DockerHubのプライベートリポジトリへプッシュ
kubectl edit
でDeploymentsのイメージタグを最新のものへ変更
といった人の手による温かみのあるデプロイをしている?
それはそれで心がこもった良いやり方かもしれませんが、おそらく少数派ですし、システムに心は必要ありませんのでやめましょう。みなさん基本的にはSpinnakerやJenkinsXといったCDツールを利用されているかと思います。
現在私達が開発中のシステムにおいては、デプロイパイプラインのCDツールとしてArgoCDを利用しています。
以下のような特徴があり、シンプルにGitOpsデプロイを実現することができるツールです。
そもそもGitOpsとはどういった概念なのか、という点に関しては提唱元であるWeaveworksのblogがわかりやすいのでご参照ください。
なお、Weaveworksが開発しているFluxもGitOpsを実現するためのCDツールなのですが、ArgoCDと比べると公式ドキュメントがややわかりづらい印象があります。
また、kustomizeには対応しているものの、他の機能(イメージタグ更新検知)とあわせて利用しようとするとmanifestの構成が複雑になる(選定時の実装では)、といった理由もあって採用には至りませんでした。
EnigmoにおけるArgoCDを使ったGitOpsデプロイフロー
ArgoCDのアーキテクチャは公式ドキュメント記載の以下の図のように、GitOpsの全ての領域をカバーするわけではなく、他のCIツールと併用することを前提としています。
CIツールについては図のようにTravisCIやCircleCI、最近であればGithub Actionsなども候補になるかと思いますが、EnigmoではメインのGitサービスとしてGitLabでソースコードを管理しており、GitLabにビルトインされたCI機能であるGitLabCIをフローに組み込みました。
GitLabCIとArgoCDを組み合わせたデプロイフローは以下のような構成です。
ArgoCDの提唱するBestPracticeに則り、アプリケーションのコードリポジトリとKubernetesのmanifestリポジトリは分離させています。
以下にフェーズごとの具体的な流れを書いてみます。
Application Image Build Phase
アプリケーションリポジトリのmaster
ブランチにDockerイメージのバージョンアップMRをマージすると、GitLabCIで以下のジョブが実行されます。
- Dockerイメージのビルド・タグ設定
- ECRへDockerイメージをPush
これでアプリケーション側のデプロイ準備は終わりました。
Application/Kubernetes Config Deployment Phase
更新したイメージタグを利用するようmanifestファイルを修正し、manifestリポジトリにMRを作成→マージすると、以下のフローで処理が走ります。
- GitLabのmanifestリポジトリをCodeCommitRepositoryへミラーリング(参考:GitLab Repository Mirroring)
- Kubernetes上で稼働しているArgoCDがCodeCommitRepositoryを参照し、クラスタの状態とmanifestファイル定義を比較
- イメージタグがクラスタとmanifestで異なることをArgoCDが検知して、クラスタのDeploymentsを更新
このように、アプリケーションとKubernetes manifestのコードをそれぞれGitにマージするだけで、kubectlを使うことなくデプロイが実行されました。
なお、ArgoCDのチュートリアルや概要的な部分は公式ドキュメントにわかりやすくまとめられているため省略させて頂きます。
ArgoCDを使ったデプロイフローのPros/Cons
Pros
デプロイ作業の省力化
システム開発の初期は冒頭で記載したような、manifestファイルを修正→kubectl diff
でクラスタとmanifestの差分を確認→kubectl apply
でクラスタへ適用!という原始時代のようなオペレーションを行っていました。有り得ませんね。
継続的デリバリという方式なので当たり前ではありますが、このフローを構築してからはGitのマージ操作のみでデプロイ作業が完結し、タイトルのようにおよそ5分でアプリケーションがデプロイされるようになりました。
柔軟なデプロイフローの実装
開発中のシステムはRailsアプリケーションで構成されているのですが、Railsアプリケーションにつきもののdb:migrate
をどうやって実施するか?という点についても、ArgoCDのSync Waveで解決することができました。
db:migrate
を実行するJob
を作成し、annotationで他のDeploymentよりも先にSyncが実行されるように設定することで、他のアプリケーションよりも先に確実にdb:migrate
が実行され、スキーマ関連のエラーが回避できます。
また、現時点では上記デプロイフローには実装していませんが、Hookの仕組みを使うことでデプロイ後にSlackへ通知を飛ばしたり、正常終了したJobを削除する、といった振る舞いを加えることもできます。
Cons
デプロイスピード
これはArgoCDの短所ではないのですが、このデプロイフローは構成図でもわかるようにオンプレミスのGitLabと、AWSのマネージドサービス群の2つにわかれています。
本来であればArgoCDから直接GitLabのmanifestリポジトリを参照し、GitLabのContainerRegistryからDockerImageをPullするようにすれば、オンプレミスからのイメージPushやRepositoryミラーリングが必要なくなり、もっとシンプルなフローになります。
ただ、AWS側からオンプレミスのGitLabへアクセスするよう設定すると、オンプレミス側への依存が発生することと、KubernetesクラスタからはあくまでAWSのサービスのみとやりとりをするのが、リソースアクセス権限設定の観点からもわかりやすいだろう、という理由からこういった構成になっています。
なお、manifestリポジトリのミラーリングはリアルタイムではなくおよそ5分間隔で実行されます。これに加えて、ArgoCDがクラスタとmanifestの差分を3分間隔(調整可能)でチェックしているため、マージしてから最長8分待たないとデプロイされない、という状態になっています。
いざデプロイしようと思ってマージをしてから実際にアプリケーションが更新されるまでの時間がやはり長過ぎるのではないか、という印象は否めないため、前述した理屈を否定する形にはなりますが、GitLabをAWSへ移行してArgoCDから直接参照させる、といった方法の改善を検討しています。
イメージタグ更新修正の手間
デプロイフローに記載したように、アプリケーションリポジトリの更新だけではなく、manifestファイルのイメージタグも都度修正しなければなりません。アプリケーションのコードを更新したら即デプロイ!ということにはならず、もうワンアクションが必要になります。
プロダクション環境であれば、意図しないデプロイを防ぐためにもそういったアクションが挟まるのも良いかもしれませんが、テスト環境のようにスピーディーにデプロイして検証をしたい!という場合は手間でしかありませんね。
ArgoCDの競合プロダクトであるFluxはそういった手間が省略できる、イメージタグの自動検知・適用機能があるため、同じような機能がほしい!というIssueがArgoCDのリポジトリに報告されていました。
FluxとArgoCDは設計思想が違うから、というコメントとともにあえなくクローズされる……かと思いきや、ArgoCDとFluxがそれぞれの機能を統合したGitOpsツールの開発をすすめる旨の発表をしたため、緩やかに期待してArgoCDを使い続けよう、という状況です。
まとめ
- KubernetesのGitOpsツールとしてArgoCDを利用しています
- Dockerイメージのビルドとプッシュ用CIツールとして、GitLabCIを利用しています
- ArgoCDを利用することで柔軟なデプロイフローを実現することできます
この記事では我々のシステムではどのようにGitOpsデプロイを実現しているか?という構成を紹介させて頂きました。
Kubernetesの運用ツールはまだまだデファクトと呼べるようなものが揃っていない状況ですが、日々新しい機能が盛り込まれたり統廃合される様子は、ウォッチしていて楽しいものでもありますね。
EnigmoではKubernetesをはじめとしたCloud Native Computingの運用に一緒に立ち向かう仲間を募集しています。
明日の記事の担当はサーバサイドエンジニアの @hokita222 さんです。おたのしみに。