Argo CDによってGKEでGitOpsをする
はじめに
最近読んだ鎌倉時代の歌人、鴨長明の『方丈記』にも
ゆく河の流れは絶えずして、しかももとの水にあらず。
とありますが、私たちのソフトウェアも然りです。
毎日更新され、デプロイされ、時に不可逆に破壊され。そして、ちぐはぐな形に落ち着くまで絶えず変更されているように感じます。
そのようなことにならないためにもOpsやCDについて注目しています。
本記事
本記事はKubernetes Advent Calendarの15日目の記事になっています。
コメントや間違いなどがあればDMやリプを軽く飛ばしてもらえると嬉しいです。
今回は、GitOpsを実現するためのツールとしてArgo CDが注目を集めているので、GitOpsについて考えていこうと思っています。
また今回はたまたまArgo CDを使ってみますが、だいたいのGitOpsに導入しやすいソフトウェアは、似たような構成なので、体系的に学べる記事にできれば嬉しいと思っています。他にもWeave FluxやJenkins Xなどがありますが、それにも通用する知識をつけられれば何よりです。
コンテンツ
本記事の目次は以下の通りです。
興味がある項目だけでも、ぜひ読んでみてください。
GitOpsについて
GitOpsの定義
Weave社のブログではGitOpsの定義とは
Operation by Pull Request = プルリクによるオペレーション
であると書かれています。もともとGitOpsは、Weave社が最初に提唱したもので、以下の原文で定義されています。
GitOps - Operations by Pull Request
これらは概念であって、現実世界では、何かしらのツールを使って実現することがほとんどです。
多くの企業が採用していることを踏まえると、別の見方をすると
GitOps = Cloud Native + Continuous Delivery
としても捉えることができるのではないでしょうか。
プロダクションとして使っていくには、正しいCloud Native技術を使って継続的デリバリーをすることが非常に大事です。
Cloud Nativeと継続的デリバリー
例えば、両者は以下のような技術があります。
- Cloud Native: GitHub, GitLab, Docker, Kubernetesなど
- 継続デリバリー: 今回紹介するArgo CDや、以前の記事で紹介したSpinnakerなど
この図では、CIツールでCDできるものも一緒にしました(タスクを書けば複雑なデリバリーをするのもできるといえばできるので)。CIツールとCDツールは排他的な関係にないことに留意してください。
Cloud Nativeについては財団があるので、一回参照するといいかもしれません。
Home Page - Cloud Native Computing Foundation
スクリーンショットで撮ってもあふれるくらいのCloud Native技術はたくさんあります。
これらを用いて宣言的で、変更しやすく、チームで運用できるオペレーション手法としてGitを用いるGitOpsが注目されています。
構成
GitOpsを成すアーキテクチャは、大まかに以下のようなgitリポジトリが二つあって、
- アプリケーションリポジトリ: アプリケーションのリポジトリ
- コンフィグリポジトリ: 宣言的なマニフェストファイル
で構成されています。
用途は以下のように対応しています。
リポジトリ | 用途 |
---|---|
アプリケーション | アプリそのものを管理 |
コンフィグ | デプロイ環境などの設定を管理 |
図にすると、以下のように対応しています。
特にコンフィグファイルがデプロイ環境を定義しています。例えばKubernetesの状態などです。
また、GitOpsの大きな原則としては以下の3つがあります。
- 記述できるすべてのものはgitに保存されてないといけない
- Kubectlは直接使用されるべきではない
- Operatorパターンに従うKubernetesコントローラーを使用する
第一の原則はつまりgitですべてを管理しろということです。
アプリケーションは、元からgitで管理されていることがほとんどでしょう。それはReactでもRailsでもGoサーバーでも関係ありません。特に新しいことはありません。
しかしながら、環境を記述するコンフィグファイルが別のリポジトリで、git管理であることは珍しいでしょう。
どのクラスタに、どのValue(設定値)で、どのように、、、など記述できるすべてを記述します。
つまり、このリポジトリを見れば現在の状態が監視できるというわけです。
この恩恵は逆も然りです。
デプロイメント環境はすべてgitで管理されているということもできます。
ただ言い方を変えたように捉えられますが、例えばReplica数がおかしいとか、何かデプロイメントされていない、バージョンが違うなどの問題もマニフェストファイルで宣言を間違えているということができるかもしれないからです。
次に第二の原則は宣言する以外、人間が介入するなということです。
特に、この書籍が参考になると思います。
SRE サイトリライアビリティエンジニアリング ―Googleの信頼性を支えるエンジニアリングチーム
- 作者: 澤田武男,関根達夫,細川一茂,矢吹大輔,Betsy Beyer,Chris Jones,Jennifer Petoff,Niall Richard Murphy,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/08/12
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
例えば、誰かが毎回毎回、手動で設定すると
- 何をしたのか覚えてない
- スケールさせにくい
- 管理者が必要
などなど大変、問題があります。
実際に、いまだこれをしているという話は少ないと思います。AnsibleやChef, Puppetの台頭で構成管理がだいぶ簡単になりました。
しかし、Kubernetesだとkubectl
を使って、さっと変更してしまうことが多くあったり、マニフェストファイルをgit管理していかなったりします。
なのでこのように人が直接操作をやめようという、古くからの教訓を再度、強調しているようにも思えます。
第三の原則は具体的に分かっていないので、教えていただけると嬉しいです。
Argoについて
Argoには大きく分けて二つの機能があります。
- ArgoCI
- ArgoCD
これを分けて解説します。
まずArgoとは
Argoとは、まとめて説明すると
Kubernetesのためのオープンソースなコンテナネイティブワークフローエンジンです
以下のようなことができます。
- それぞれのステップがコンテナで動くワークフローを定義できる
- マルチステップワークフローを定義できる
- 機械学習やデータ処理などの重い処理もKubernetesで動かすことができる
- Kubernetes上でCI/CDパイプラインを簡単に実行することができます。
先ほども説明しましたが、Argo CIとArgo CDの二つの機能があって、これらがCI/CD機能に対応しています。
公式リポジトリは以下のようになっています。
今回はArgo CDについてフォーカスするので注意してください。
Argo CDとは
Argo CDとはKubernetesのための宣言的なGitOpsのためのデリバリーツール(コントローラー)です
GitOpsのパターンに従うので、gitリポジトリを使って望む状態を宣言します。
以下のようなフローになります。
つまりGitの状態がデプロイ環境の状態です。
使えるKubernetesのマニフェストファイルは以下の通りになっています。
ksonnet
kustomize
helm
- プレーンなYAML/jsonマニフェストファイル
現時点ではPlainなYAMLを取得することができませんでした。
どうやら何かしらのテンプレートを使った方がいいみたいです。
本題に戻して、Argo CDはデプロイを自動化します。もちろんCDツールとして可視化や通知などといったようなCDの概念に必要な機能ももちろんあります。
特徴としては
- デプロイを自動化
- いろんなマニフェストの書き方(上記)に対応
- WebUIやCLIツールが用意されていて、要求状態と現在の状態を可視化
- gitリポのどの状態へもロールバック
- Webhookインテグレーション
- 戦略的なデプロイ(ブルーグリーン/カナリアアップグレード)に対応
- Helmやksonnetなどのパラメータを上書きする機能
などがあります。
構成アーキテクチャ
GitOpsを実現するためにArgo CDを使ったアーキテクチャは以下のようになります。
これから少し解説をします。
1. GitOpsを実現する
以下のようなデプロイメントパイプラインの構築を目指します。
今までも私は数々の会社にインターンとして働いていましたがどれもCIを使ってデプロイしているCIOpsでした。
CircleCIやTravisなどのCIがテストして、デプロイして、、、と何もかもしていた状況です。CIがオペレーションの中心になっていました。
CIOpsをしない方法としてgitリポジトリとしてマニフェストファイルなどのデプロイメントに関するファイルを集めてデプロイする手法がGitOpsです。
先ほどのアーキテクチャ図では以下の主要な部分が提供しています。
例えばproduction-cluster-config
のようなリポジトリがあって、それを参照するような形です。
デフォルトではArgo CDはGithubリポジトリを3分おきにポーリングしています。これをリポジトリに変更があるとすぐ反映をしたければWebhookを設定する必要があります。
以下のよう直接CIツールからKubernetesコンテナにデプロイするのではなくて、以下のようにGitリポジトリから同期を取るようにします。
2. CIと接続
この図ではJenkinsやCircleCIなどのCIツールが書かれています。
GitOpsの中では、CIは境界のある明確な概念として定義されます。
CIではユニットテストをするほか、Argo CDへのAPIをトリガーするだけで、とても責任が明確です。
最終的にはKubernetesにトリガーします。
3. CDとしてDeployする
CDといえばあらゆる環境に戦略的なデプロイメントをすることが必要でしょう。
もちろん手動でもできますが第二の原則でもあったように、CDの観点からArgo CDによって自動化をします。
いまさらですが、CDについてわからなければ以下の本が非常にためになります。とてもいい本だと思います。
継続的デリバリー 信頼できるソフトウエアリリースのためのビルド・テスト・デプロイメントの自動化 (アスキードワンゴ)
- 作者: JezHumble,DavidFarley,和智右桂,高木正弘
- 出版社/メーカー: ドワンゴ
- 発売日: 2017/08/09
- メディア: Kindle版
- この商品を含むブログを見る
準備
すこし準備が必要です。
もしすでに済んでいる人は飛ばしてください。
GCPにCLIからログインする
以下のようにログインをすることができます。
gcloud auth login
Projectを作成して設定
以下のようにプロジェクトを適当に作成します。
gcloud projects create test-argo-cd --name test-argo-cd
そして設定します。
gcloud config set project test-argo-cd
テストクラスタを作成
以下のようにテストクラスタを作成します。
gcloud cluster container test-argo-cd --region=asia-northeast1-a
Credentialを取得
KubectlやArgoCDのCLIにはクラスタにアクセスするために認証情報が必要なので以下のように取得します。
gcloud container cluster get-credential test-argo --region=asia-northeast
以下のようにノードが作成されているのを確認できます。
kubectl get nodes NAME STATUS ROLES AGE VERSION gke-test-argo-cluster-pool-1-cbf3d941-8nkg Ready <none> 56s v1.9.7-gke.11 gke-test-argo-cluster-pool-1-cbf3d941-kr8h Ready <none> 3m v1.9.7-gke.11 gke-test-argo-cluster-pool-1-cbf3d941-mt1w Ready <none> 3m v1.9.7-gke.11
Argo CDをインストール、基本を理解する
ClusterRoleBindingを作る
ClusterRoleBindingを作成します。
kubectl create clusterrolebinding YOURNAME-cluster-admin-binding --clusterrole=cluster-admin --user=YOUREMAIL@gmail.com
そして--user
に自分のアドレスを入れてください。
Namespace作成してArgo CDを入れる
まずはargocd
Namespaceを作成します。
kubectl create namespace argocd
すると作成されたので以下のように確認できます。
kubectl get ns NAME STATUS AGE argocd Active 8s default Active 4m kube-public Active 4m kube-system Active 4m
そしてArgo CDをインストールします。
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v0.10.6/manifests/install.yaml
問題なく終了できればargocd
Namespace以下にこのようなものが見えるはずです。
Serviceは
kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE argocd-metrics ClusterIP 10.31.243.134 <none> 8082/TCP 6m argocd-repo-server ClusterIP 10.31.247.251 <none> 8081/TCP 6m argocd-server ClusterIP 10.31.250.9 <none> 80/TCP,443/TCP 6m dex-server ClusterIP 10.31.254.142 <none> 5556/TCP,5557/TCP 6m
Dexだけアーキテクチャ図にはなかったのですが、OpenIDを使うためのものらしいです。
Deploymentsは
kubectl get deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE application-controller 1 1 1 1 7m argocd-repo-server 1 1 1 1 7m argocd-server 1 1 1 1 7m dex-server 1 1 1 1 7m
Argo CD CLIをインストールします
CLIツールをいれます。
brew install argoproj/tap/argocd
インストールされたことを確認します。
which argocd /usr/local/bin/argocd
Argo CD API サーバーにアクセス
デフォルトではArgo CDのAPIサーバーは外部IPを持っていないです。
なのでkubectl patch
コマンドを実行して外部IPを取得できるようにtype: LoadBalancer
にします。
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
Port転送でも行うことができます。
kubectl port-forward service/argocd-server 8080:443
すると以下のように外部IPがあります。
kubectl get svc | grep "argocd-server" argocd-server LoadBalancer 10.31.250.9 34.213.32.91 80:31249/TCP,443:31763/TCP 1h
そしてPod名前を取得します。
公式ドキュメントでは以下のように
kubectl get pods -n argocd -l app=argocd-server -o name | cut -d'/' -f 2
としていますがこっちの方がわかりやすいので--filter
を使って行います。
kubectl get pods -n argocd -l app=argocd-server -o=jsonpath="{..items[].metadata.name}"
これがArgoCDの初期パスワードです。ユーザー名はadmin
です。
そして以下のようにログインします。
argocd login [外部IP] Username: admin Password: 'admin' logged in successfully
そしてパスワードを変えてください。
argocd account update-password *** Enter current password: *** Enter new password: *** Confirm new password: Password updated
再度、ログインします。
argocd relogin
これらはkubectl
のようにContext
がCLIツールが使えるように保存されます。
WebUIからGithub Hookの設定をする
先ほどの外部IPを開きます。
open 34.213.32.91
すると以下のようなページが開きます。
Usernameにadmin
、Passworkに先ほど設定したパスワードを入力してください。ログインできると以下のようになります。
以下のような項目になっています。
設定項目を見てみましょう。Repository
を選択します。
そして次にConnect Git Repo
で設定をします。
すると以下のような画面が開きます。
ここではサンプルリポジトリをフォークして使ってみます。
このリンクのURLを入力します。Publicなので何も他に入力する必要はありません。
以下のように接続することができました。
アプリケーションを設定する
次にまたアプリケーションページに戻って、プラスボタンで新しくアプリケーションを設定します。
先ほどのリポジトリを選択します。
すると再帰的にYAMLファイルがあるディレクトリを表示してくれます。
最初の説明にも
gitリポのどの状態へもロールバック
という特徴があるといいました。
以下のフィールドにcommit IDを入力することによって、その状態のマニフェストファイルを参照することができます。
どうやらキャレット^
やチルダ~
は使えないようです。HEAD
を追従してGitOpsして行きたいので、必要ないのでいいですが。
どれかを設定すると以下の項目を入力します。
Application Name
: アプリケーションの名前ですCluster URL
: どのクラスタにデプロイするかを選択しますNamespace
: どのNamespaceにデプロイするかを選択しますPath
: k8sのマニフェストファイルがどこにあるかを指定
もしかしたらまずこちらの画面がでるケースで設定を入力できるものもあります。Helm
やkustomize
によって変化します。
Create
できると以下のようになります。
しかし、ここではまだ同期していないのでOutOfSync
になっています。
ここからはksonnet
のでやっていこうと思います。
もちろんCLIツールからもできます。
argocd app create guestbook-default --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --env default
ksonnetだったら上のコマンドなのですが、Helmならばvalue
ファイルを指定します。
argocd app set helm-guestbook --values values-production.yaml
同期する
GitOpsのためにGitリポジトリとクラスタが同期するようにします。
GUIでは以下のようにActionsを押すと出てくるSync
を押します。
Applicationを選択してからもSyncはできます。
エラーが出ました。
解決するためにprod
名前空間を作ります。
kubectl create ns prod
もう一回やってみると以下のように同期が成功しています。
CLIからは以下のように同期を実行することができます。
argocd app sync guestbook-default KIND NAME STATUS HEALTH HOOK OPERATIONMSG Service ks-guestbook-ui service/ks-guestbook-ui unchanged Deployment ks-guestbook-ui deployment.apps/ks-guestbook-ui unchanged Application: guestbook-prod Operation: Sync Phase: Succeeded Start: 2018-12-06 03:36:01 +0900 JST Finished: 2018-12-06 03:36:23 +0900 JST Duration: 22s Message: successfully synced KIND NAME STATUS HEALTH HOOK OPERATIONMSG Service ks-guestbook-ui Synced Healthy service/ks-guestbook-ui unchanged Deployment ks-guestbook-ui Synced Healthy deployment.apps/ks-guestbook-ui unchanged
状態をCLIから取得するにはapp get
コマンドを実行します。
argocd app get guestbook-prod | pbcopy Name: guestbook-prod Server: https://kubernetes.default.svc Namespace: prod URL: https://34.232.34.31/applications/guestbook-prod Repo: https://github.com/argoproj/argocd-example-apps.git Target: HEAD Path: ksonnet-guestbook Environment: prod Sync Policy: <none> KIND NAME STATUS HEALTH Service ks-guestbook-ui Synced Healthy Deployment ks-guestbook-ui Synced Healthy
ここでSTATUS
が
OutOfSync
: 同期が取れていないSynced
: 同期されている
ということなので、CLIから適宜状態をみることができます。
またGUI上のアプリケーションの構成要素はそれぞれ詳細をみることができ、また編集できます。
実際にGitOpsになっているかを確認
まずYAMLに何かしらの変更を加えます。今回はreplicas
を1
から2
に変更しました。
spec: - replicas: 1 + replicas: 2 selector:
そしてgit push
すると以下のようにOutOfSync
になりました。
しばらく待つと以下のようになりました。
次は6にします。
以下のようになります。
機能のDeep dive
リアルタイム同期のためのWebhook
「リアルタイム」という言葉が強いのですが、Argo CDは3分おきにリポジトリの変更をみてデプロイしています。
これをGitに変更があるたびに設定を変えるにはWebhookを設定しなければなりません。これはGithub側で行います。
Argo CDの記事に直接的に関係ないので解説しません。
Application(リポジトリ)をまとめるためのProject機能
例えば一つの会社で複数のサービスを抱えている場合、サービスごと、かつ機能ごとにリポジトリを管理することがおおいと思います。
そのようなものを、サービスごとや意味のある集合として定義できるのがProjects
です。
何も設定をしないとdefault
Projectに入ります。ここらへんはKubernetesとよく似ていると思います。
ここではSourceとDestinationとして設定します。
APIドキュメントをみる
http://外部IP/swagger-ui
でAPIドキュメントをみることができます。
Hookを設定する
KubernetesのJobとしてHookを設定することができます。
Hook | いつトリガーされる? |
---|---|
PreSync |
同期される前 |
Sync |
すべてのPreSync が成功して完了したら |
Skip |
Manifestファイルのapplyをスキップした時 |
PostSync |
Sync フックがすべて終了してすべてがHealthy になったら行う |
HookPolicyというものがあり、どのような状態のときに設定されたHook(Job)を削除されるかを定義する
HookPolicy | どんなルールなのか |
---|---|
HookSucceeded |
Hookが成功したら |
HookFailed |
Hookが失敗したら |
HookとHookPolicyを合わせると以下のようなマニフェストファイルをデプロイするといいです。
apiVersion: batch/v1 kind: Job metadata: generateName: integration-test- annotations: argocd.argoproj.io/hook: PostSync argocd.argoproj.io/hook-delete-policy: HookSucceeded
例えばこれを使うとSlackなどに通知を送るなどすることができます。
argocdコマンド一覧
以下のようなコマンドが用意されています。
コマンド | 何をするのか |
---|---|
acount |
アカウントの設定 |
app |
Argo CD上でのアプリケーションを管理 |
cluster |
クラスタの認証をする |
context |
コンテクスを切り替える |
help |
ヘルプコマンド |
login |
Argo CDにログインする |
proj |
プロジェクトを管理する |
relogin |
ログアウトしてログインする |
repo |
リポジトリの認証をする |
version |
バージョンを確認する |
まとめ
GitOpsだとマニフェストファイルがあるリポジトリがクラスタの状態であり、そのリポジトリのコミット履歴がクラスタの履歴でもあるので管理をするという面では楽でした。
またフックなども設定することができたり、CDとしては機能が最低限あります。
しかしながら、GitOpsではありませんがSpinnakerの方が利便性が高く、より高度なデプロイメントパイプラインを構築できると思うので、少し比較すると機能不足ではないかと思いました。
しかしながらCIとうまく機能を分離しながらArgo CDとして一つクラスタを用意してGitOpsを実装するのもArgo CDだと簡単にできるし、Helmだけでなくてksonnetやkustomizeにも対応しているので既存の(たぶん)CIOpsの状態との親和性が高いのではないかと思います。
似たものでWeave FluxというGitOpsを実現するためのOSSもあるのでまた使ってみようと思います。
参考文献
Argo公式ドキュメント
Japan Container Daysであった発表
www.slideshare.net