はじめに
本記事ではGitOps CDツールの一つであるArgoCDの概要と利用方法について紹介いたします。
ArgoCDとは
ArgoCDはKubernetesクラスター向けのContinuous Deliveryを実現するツールです。ArgoCDでは、Kubernetesマニフェストファイルが格納されたGitHub / Helmリポジトリを監視し、リポジトリ上で変更が発生したらその差分を検出して、Kubernetesクラスターに反映します。
GitOpsとは
ArgoCDは、いわゆるGitOpsを実現するツールとして注目されています。GitOpsとは、以下のような特徴を備えたContinuous Deliveryの手法です。
GitをSingle Source of Truth(信頼できる唯一の情報源)として扱い、バージョン管理や変更履歴、ピアレビュー、ロールバックなどを、kubectlのようなツールを利用せずに実現する
クラウドやKubernetesを利用するシステムと相性が良い
- コードで表現することのできるクラウドやコンテナリソースはGitをSingle Source of Truthとして使うのと相性が良く、コード化することでバージョン管理ができる。これによりシステムに対する操作・回復・監視をより簡単に実現できる。
図:Weaveworks Blogより参照
※参考ドキュメント:
ArgoCDの構成
ArgoCDは、以下のように複数のサービスから成り立っています。
API Server
ArgoCDにアクセスするWeb UI・CLI・CI/CDに利用するAPIを提供するサーバーで、アプリケーションの状態報告や管理・操作、Credential管理やGit Webhookイベントの受け取りなどを行います。
Repository Server
マニフェストファイルを管理するGitリポジトリの情報をローカルキャッシュとして保持するサーバーで、リポジトリURLなどの情報をインプットとして、Kubernetesマニフェストファイルの生成を行います。
Repository Serverは/tmp
配下にリポジトリをCloneします。リポジトリの数やファイル数が多い場合はPersistent Volumeをマウントすることでエラー無く実行することが可能になります。
Repository Serverはデフォルトで3分ごとにマニフェストの更新がないかチェックします。ArgoCDでは、リポジトリに変更があったときのみマニフェストが変更されると想定しており、生成されたマニフェストを24時間キャッシュします。
一つのRepository Serverは、一つのリポジトリに対する操作は同時に一つしか実行しません。同じリポジトリに複数のアプリケーションを所有する場合、Repository Serverのレプリカ数を増加します。
Repository Serverでは、リポジトリの設定時にHEAD
revisionのような設定をすると、リポジトリの更新を確認するためにgit ls-remote
を頻繁に実行します。
Application Controller
Kubernetes Controllerとして、起動中のアプリケーションを監視し、実際に稼働するアプリケーションの状態とあるべき状態とを比較します。アプリケーションがOutOfSync
の状態になったことを検知すると適切な操作を行ったり、ユーザーの定義した通りにライフサイクルイベントを実行したりします。
Controllerは、アプリケーションの reconcilliationとアプリケーションの同期のために2種類のQueueを利用します。これらは実行時間に差があり(reconcilliation < Sync)、また利用者がコントロールすることができます。
Controllerは内部でkubectl
コマンドを実行し、クラスターへのリソース作成や変更を行います。PodのOOM Killを引き起こす場合は--kubectl-parallelism-limit
を利用し、同時に実行するkubectl
fork/execの数を制限することができます。
※参考ドキュメント:
ArgoCDの機能
ArgoCDでは、リポジトリとの同期・差分検出を行うだけでなく、それに関連した様々な機能を提供します。
手動・自動でのアプリケーション同期
ArgoCDではGitHubリポジトリを登録し、リポジトリに格納されたファイルを同期することで、マニフェストファイルの変更を検知します。リポジトリの状態と実際の起動したアプリケーションとを同期するには、自動・手動のいずれかを利用できます。
自動同期はsyncPolicy
を設定することで有効になります。これを利用すると、CI/CDパイプラインがArgoCD API Serverと直接通信することなく、アプリケーションのデプロイを実行することができます。またGitリポジトリ上のリソースが削除されたとき、デフォルトではそれらを削除するがありませんが、自動的にpruneするよう設定することも可能です。
自動同期をするタイミングはSync Windows
という機能で制限することができます。Sync Windows
ではCronの形式で、同期を許可・拒否する時間帯を指定します。Sync Windows
を利用するには、CLIから設定を行うか、AppProject
というマニフェストを作成します。
手動同期では、UI上で同期を行うリソースを選択することができます。
また自動検知はデフォルトで3分毎に実行しますが、Git Provider Webhookを設定することで、Webhook イベントを受け取ることができます。これによりポーリングの間隔と実際の変更のタイミングとのずれによる遅延が発生しなくなります。
※参考ドキュメント:
Web UIを備える
ArgoCDにはWeb UIがはじめから備わっており、GitHubリポジトリやKubernetesクラスターの登録、アプリケーションの同期やロールバック、起動状態の確認などを行うことができます。
アプリケーションには、GitHubリポジトリに格納されたアプリケーションのバージョンが表示され、指定したバージョンへのロールバックを実行することができます。
アプリケーションに対しては、Kubernetesリソースに対するヘルスチェックを通じてリアルタイムでの起動状態を表示します。またヘルスチェックをカスタムすることも可能(Luaで記述)で、ArgoCDが対応していないCustom Resourceや、アプリケーションに既知の問題が含まれる場合に対応することが可能です。
また、CSSファイルを用意してUIをカスタマイズすることも可能なようです。
※参考ドキュメント:
複数のKubernetesマニフェスト管理ツールに対応
ArgoCDは、Kubernetesの素のマニフェストファイルに加え、以下のようなマニフェスト管理ツールに対応しています。
またConfig Management Pluginを利用することで、より多くのツールを利用することができます。
※参考ドキュメント:
複数のアプリケーション・Kubernetesクラスターに対応
ArgoCDは複数のアプリケーションを同時に管理することが可能です。現在は1000以上のアプリケーションを利用するとUIの速度が大きく低下する様ですが、将来的には2000以上のアプリケーションに対応できるよう検討されているようです。
またArgoCDは複数のKubernetesクラスターを管理対象として登録することができます。現在対応しているクラスター数の上限は不明ですが、将来的には1つのArgoCD Controllerで100クラスター以上を管理できるよう、Controllerの水平スケールやシャーディングの実装が検討されているようです。
※参考ドキュメント:
ユーザー管理
ArgoCDは初期ユーザーとしてadminが登録されており、ユーザーを追加する場合はConfigMap
を利用します。
またArgoCDはSSOにも対応しています。ArgoCDをデプロイする際に利用できるinstall.yml
には、ArgoCDのほかにDex Serverが定義されており、OIDC Providerとしてこちらを利用することができます。また、既に別のOIDC Providerを利用している場合はそちらも利用できます。対応するOIDC Providerは以下の通りです。
※参考ドキュメント:
Sync Operationの設定
ArgoCDはGitHubリポジトリとのSync(同期)はResource Hookを利用して行われます。Syncを行う過程では、その前後で複数の操作を行うことが可能です。ArgoCDで定義するアプリケーションに含まれるマニフェストに指定のAnnotationを付与することでこの操作は可能であり、利用できるHookには以下の種類があります。
PreSync
: アプリケーションのマニフェストファイルを利用する前に実行します。新しいアプリケーションをデプロイする前にDBスキーマの移行を行う場合などに利用されます。Sync
:PreSyn
Hookがすべて完了・成功した後に実行されます。アプリケーションのマニフェストファイルを利用するのと同じタイミングです。Kubernetesで利用できるRolling Updateよりも複雑なデプロイ方法をとる場合などに利用できます。Skip
: アプリケーションのマニフェストファイルをスキップします。PostSync
:Sync
Hookがすべて完了・成功し、アプリケーションの状態がHealthy
になった後で実行されます。アプリケーションのデプロイが完了した後にヘルスチェックなどを別途行う場合などに利用されます。SyncFail
: Sync操作が失敗したときに実行されます。デプロイに失敗した場合にリソースのクリーンアップを行う場合などに利用できます。
なおBlue-Green DeploymentやCanary Releaseを利用したい場合は、同プロジェクトにあるArgo Rolloutを利用することで実現できます。
※参考ドキュメント:
その他
- Audit: Kubernetesクラスター上でのアプリケーションのイベント情報を確認することができるので、GitHub上の履歴だけでなく、実際に稼働したアプリケーションの情報も利用することができます。
- CLI:
argocd
CLIを利用することで、自動化及びCIとの統合が可能になります。 - Prometheus metrics: アプリケーション向け・ArgoCD API Server向けのメトリクスが公開されています。
ArgoCDの利用方法
ArgoCDの概要について紹介したので、次は実際にArgoCDを動かしてみます。今回は公式ドキュメントにあるGetting Startedに従って利用します。
構築環境
今回利用するKubernetesの環境は以下の通りです。
- Kubernetes Cluster:
Amazon EKS
- 構築方法:
eksctl
を利用 - 作業環境: WSL (Ubuntu 18.04.4)
※参考ドキュメント:
ArgoCDのデプロイ
クラスターが用意できたので、まずはArgoCDをクラスター上にデプロイします。ここでは事前に用意されたinstall.yml
を使用します。install.yml
には、ArgoCDを動作するうえで必要な3つのサービスに加え、redis-server
dex-server
の2つが定義されています。
$ kubectl get ns NAME STATUS AGE default Active 15m kube-node-lease Active 15m kube-public Active 15m kube-system Active 15m # “argocd” Namespaceの作成 $ kubectl create namespace argocd namespace/argocd created # ArgoCDのデプロイ $ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io created serviceaccount/argocd-application-controller created serviceaccount/argocd-dex-server created serviceaccount/argocd-server created role.rbac.authorization.k8s.io/argocd-application-controller created role.rbac.authorization.k8s.io/argocd-dex-server created role.rbac.authorization.k8s.io/argocd-server created clusterrole.rbac.authorization.k8s.io/argocd-application-controller created clusterrole.rbac.authorization.k8s.io/argocd-server created rolebinding.rbac.authorization.k8s.io/argocd-application-controller created rolebinding.rbac.authorization.k8s.io/argocd-dex-server created rolebinding.rbac.authorization.k8s.io/argocd-server created clusterrolebinding.rbac.authorization.k8s.io/argocd-application-controller created clusterrolebinding.rbac.authorization.k8s.io/argocd-server created configmap/argocd-cm created configmap/argocd-gpg-keys-cm created configmap/argocd-rbac-cm created configmap/argocd-ssh-known-hosts-cm created configmap/argocd-tls-certs-cm created secret/argocd-secret created service/argocd-dex-server created service/argocd-metrics created service/argocd-redis created service/argocd-repo-server created service/argocd-server-metrics created service/argocd-server created deployment.apps/argocd-application-controller created deployment.apps/argocd-dex-server created deployment.apps/argocd-redis created deployment.apps/argocd-repo-server created deployment.apps/argocd-server created # デプロイ後の確認 $ kubectl get crd NAME CREATED AT applications.argoproj.io 2020-09-15T05:54:39Z★ appprojects.argoproj.io 2020-09-15T05:54:39Z★ eniconfigs.crd.k8s.amazonaws.com 2020-09-15T05:38:20Z securitygrouppolicies.vpcresources.k8s.aws 2020-09-15T05:38:22Z $ kubectl get sa -n argocd NAME SECRETS AGE argocd-application-controller 1 6m55s argocd-dex-server 1 6m55s argocd-server 1 6m55s default 1 7m10s $ kubectl get role -n argocd NAME AGE argocd-application-controller 9m10s argocd-dex-server 9m10s argocd-server 9m10s $ kubectl get rolebinding -n argocd NAME AGE argocd-application-controller 9m17s argocd-dex-server 9m17s argocd-server 9m17s $ kubectl get clusterrole -n argocd NAME AGE admin 25m argocd-application-controller 9m24s argocd-server 9m24s aws-node 25m $ kubectl get clusterrolebinding -n argocd NAME AGE argocd-application-controller 10m argocd-server 10m aws-node 26m $ kubectl get cm -n argocd NAME DATA AGE argocd-cm 0 5m47s argocd-gpg-keys-cm 0 5m47s argocd-rbac-cm 0 5m47s argocd-ssh-known-hosts-cm 1 5m47s argocd-tls-certs-cm 0 5m47s $ kubectl get secret -n argocd NAME TYPE DATA AGE argocd-application-controller-token-c7kh2 kubernetes.io/service-account-token 3 10m argocd-dex-server-token-2pnlw kubernetes.io/service-account-token 3 10m argocd-secret Opaque 5 10m argocd-server-token-kvdr4 kubernetes.io/service-account-token 3 10m default-token-ctgsz kubernetes.io/service-account-token 3 11m $ kubectl get svc -n argocd NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE argocd-dex-server ClusterIP 10.100.252.138 <none> 5556/TCP,5557/TCP,5558/TCP 11m argocd-metrics ClusterIP 10.100.0.152 <none> 8082/TCP 11m argocd-redis ClusterIP 10.100.56.122 <none> 6379/TCP 11m argocd-repo-server ClusterIP 10.100.67.88 <none> 8081/TCP,8084/TCP 11m argocd-server ClusterIP 10.100.114.29 <none> 80/TCP,443/TCP 11m argocd-server-metrics ClusterIP 10.100.150.172 <none> 8083/TCP 11m $ kubectl get deployment -n argocd NAME READY UP-TO-DATE AVAILABLE AGE argocd-application-controller 1/1 1 1 11m argocd-dex-server 1/1 1 1 11m argocd-redis 1/1 1 1 11m argocd-repo-server 1/1 1 1 11m argocd-server 1/1 1 1 11m $ kubectl get replicaset -n argocd NAME DESIRED CURRENT READY AGE argocd-application-controller-6bf955dd55 1 1 1 11m argocd-dex-server-7c8f5cc655 1 1 1 11m argocd-redis-54b6ff7bf6 1 1 1 11m argocd-repo-server-56966df94f 1 1 1 11m argocd-server-cf8dbb7bd 1 1 1 11m $ kubectl get pods -n argocd NAME READY STATUS RESTARTS AGE argocd-application-controller-6bf955dd55-9wtrg 1/1 Running 0 11m argocd-dex-server-7c8f5cc655-vkztr 1/1 Running 0 11m argocd-redis-54b6ff7bf6-98hl7 1/1 Running 0 11m argocd-repo-server-56966df94f-rqkg6 1/1 Running 0 11m argocd-server-cf8dbb7bd-bnl96 1/1 Running 0 11m
ArgoCD CLIインストール
次にargocd
CLIをインストールします。この時点ではArgoCD API Serverとの疎通が取れない状態なので、argocd version
コマンド実行時にエラーが発生します。
# CLIインストール $ wget https://github.com/argoproj/argo-cd/releases/download/v1.7.4/argocd-linux-amd64 $ sudo cp -p argocd-linux-amd64 /usr/local/bin/argocd $ sudo chmod +x /usr/local/bin/argocd # インストール後の確認 $ argocd version argocd: v1.7.4+f8cbd6b BuildDate: 2020-09-05T02:44:27Z GitCommit: f8cbd6bf432327cc3b0f70d23b66511bb906a178 GitTreeState: clean GoVersion: go1.14.1 Compiler: gc Platform: linux/amd64 FATA[0000] Argo CD server address unspecified
ArgoCD API Serverへのアクセス
つぎにArgoCD API Serverへのアクセスができるよう、argocd-server
Serviceを一部変更します。
# LoadBalancerに変更 $ kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}' service/argocd-server patched # 変更後の確認 $ kubectl get svc -n argocd NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE argocd-dex-server ClusterIP 10.100.252.138 <none> 5556/TCP,5557/TCP,5558/TCP 66m argocd-metrics ClusterIP 10.100.0.152 <none> 8082/TCP 66m argocd-redis ClusterIP 10.100.56.122 <none> 6379/TCP 66m argocd-repo-server ClusterIP 10.100.67.88 <none> 8081/TCP,8084/TCP 66m argocd-server LoadBalancer 10.100.114.29 a36182a4c9e57495c8e0f245b2d2d8a8-995334307.ap-northeast-1.elb.amazonaws.com 80:30629/TCP,443:30865/TCP 66m argocd-server-metrics ClusterIP 10.100.150.172 <none> 8083/TCP 66m
ArgoCDへのログイン(CLI)
つぎにargocd
CLIからログインし、ArgoCDでデプロイを行うクラスターを指定します。ここでログインをしておかないと、クラスターの登録などが実行できません。
# ログイン前にクラスターを登録しようとすると失敗する $ argocd cluster add ubuntu-cli-user@eks-work-cluster.ap-northeast-1.eksctl.io INFO[0000] ServiceAccount "argocd-manager" created in namespace "kube-system" INFO[0000] ClusterRole "argocd-manager-role" created INFO[0000] ClusterRoleBinding "argocd-manager-role-binding" created FATA[0001] Argo CD server address unspecified # ログインパスワードの確認 # 初期アカウントは”admin”のみ、ログインパスワードは”argocd-server”Pod名 $ kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2 argocd-server-cf8dbb7bd-bnl96 # CLI経由でログイン (先ほど作成したLBのEXTERNAL-IPを指定) $ argocd login --insecure a36182a4c9e57495c8e0f245b2d2d8a8-995334307.ap-northeast-1.elb.amazonaws.com:443 Username: admin Password: 'admin' logged in successfully Context 'a36182a4c9e57495c8e0f245b2d2d8a8-995334307.ap-northeast-1.elb.amazonaws.com:443' updated # パスワードのアップデート $ argocd account update-password *** Enter current password: *** Enter new password: *** Confirm new password: Password updated Context 'a36182a4c9e57495c8e0f245b2d2d8a8-995334307.ap-northeast-1.elb.amazonaws.com:443' updated # ログイン後の確認 # 先ほどはエラー表示だったArgoCD Serverの情報が確認できる $ argocd version argocd: v1.7.4+f8cbd6b BuildDate: 2020-09-05T02:44:27Z GitCommit: f8cbd6bf432327cc3b0f70d23b66511bb906a178 GitTreeState: clean GoVersion: go1.14.1 Compiler: gc Platform: linux/amd64 argocd-server: v1.7.3+b4c79cc BuildDate: 2020-09-01T23:19:02Z GitCommit: b4c79ccb88173604c3786dcd34e83a9d7e8919a5 GitTreeState: clean GoVersion: go1.14.1 Compiler: gc Platform: linux/amd64 Ksonnet Version: v0.13.1 Kustomize Version: {Version:kustomize/v3.6.1 GitCommit:c97fa946d576eb6ed559f17f2ac43b3b5a8d5dbd BuildDate:2020-05-27T20:47:35Z GoOs:linux GoArch:amd64} Helm Version: version.BuildInfo{Version:"v3.2.0", GitCommit:"e11b7ce3b12db2941e90399e874513fbd24bcb71", GitTreeState:"clean", GoVersion:"go1.13.10"} Kubectl Version: v1.17.8 # クラスター登録 $ argocd cluster add ERRO[0000] Choose a context name from: CURRENT NAME CLUSTER SERVER * ubuntu-cli-user@eks-work-cluster.ap-northeast-1.eksctl.io eks-work-cluster.ap-northeast-1.eksctl.io https://987C1007C84B9FEEA7CC9F1D529C3393.yl4.ap-northeast-1.eks.amazonaws.com $ argocd cluster add ubuntu-cli-user@eks-work-cluster.ap-northeast-1.eksctl.io INFO[0000] ServiceAccount "argocd-manager" already exists in namespace "kube-system" INFO[0000] ClusterRole "argocd-manager-role" updated INFO[0000] ClusterRoleBinding "argocd-manager-role-binding" updated Cluster 'https://987C1007C84B9FEEA7CC9F1D529C3393.yl4.ap-northeast-1.eks.amazonaws.com' added
この時点でWeb UIからログインをしている場合は、以下の画像のように新規クラスターが登録されたことが確認できます。
ArgoCDへのログイン(UI)
次にWeb UIからログインをします。先ほど作成したLBのExternal-IPを指定して、Webブラウザからアクセスをすると、ログイン画面が表示されます。
先ほど変更したパスワードとadmin
ユーザーを指定してログインをします。この時点ではまだ何のアプリケーションも登録されていません。
サンプルアプリケーションの作成
次にWeb UIからアプリケーションを作成します。まずはNEW APP
を選択します。
すると、以下のように入力画面が表示されます。
Application Name
には作成するアプリケーションの名称を指定します。Project
は複数のアプリケーションを論理的にグルーピングしたものを指し、特に複数のチームが共通のArgoCDを利用する場合に役立ちます。ここではdefault
を指定しますが、特に指定しないアプリケーションはdefault
Projectに属することになります。
SYNC POLICY
ではManual
Automatic
から選択することができます。ここではManual
を選択しますが、Automatic
を選択した場合は以下のように追加の選択オプションが表示されます。
またSYNC OPTIONS
は特に変更せず、次に進みます。
※参考ドキュメント:
次に同期元となるGitリポジトリを指定します。
今回はArgoCDのサンプル用マニフェストファイルの格納されているこちらを利用します。利用するマニフェストファイルはリポジトリのguestbook
に含まれるため、path
にはこれを指定します。またrevision
はHEAD
を指定します。
次にアプリケーションをデプロイするクラスターを指定します。
ここでは、ArgoCDが稼働しているのと同じクラスターを表すhttps://kubernetes.default.svc
を指定します。なおクラスターを事前に登録することで、この項目の選択肢としてクラスターの情報が表示されます。
必要な情報はすべて設定したので、画面上部のCREATE
を選択します。すると以下の画面のように遷移し、アプリケーションが登録されたことがわかります。
この時点ではOutOfSync
と表示されている通り、まだGitリポジトリとの同期が行われておらず、クラスター上にもアプリケーションは存在しません。UI上で作成したアプリケーションを選択しても、アプリケーションを構成するKubernetesリソースの構成は見えるものの、やはりOutOfSync
状態であることが確認できます。
この時コマンドライン上で確認をすると、以下のように表示されます。
# アプリケーションは登録されている $ argocd app list NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET guestbook https://kubernetes.default.svc default default OutOfSync Missing <none> <none> https://github.com/argoproj/argocd-example-apps.git guestbook HEAD # アプリケーションの詳細 $ argocd app get guestbook Name: guestbook Project: default Server: https://kubernetes.default.svc Namespace: default URL: https://a36182a4c9e57495c8e0f245b2d2d8a8-995334307.ap-northeast-1.elb.amazonaws.com/applications/guestbook Repo: https://github.com/argoproj/argocd-example-apps.git Target: HEAD Path: guestbook SyncWindow: Sync Allowed Sync Policy: <none> Sync Status: OutOfSync from HEAD (6bed858) Health Status: Missing GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE Service default guestbook-ui OutOfSync Missing apps Deployment default guestbook-ui OutOfSync Missing # クラスター上にはアプリケーションリソースが存在しない $ kubectl get pods No resources found in default namespace. kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 3h35m # “Application”というCustom Resouceは作成されている $ kubectl get app -n argocd NAME AGE guestbook 37m
次にSync
を実行します。今回はargocd
CLIからSyncを実行します。
# 同期の実行 $ argocd app sync guestbook TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE 2020-09-15T18:14:25+09:00 Service default guestbook-ui OutOfSync Missing 2020-09-15T18:14:25+09:00 apps Deployment default guestbook-ui OutOfSync Missing 2020-09-15T18:14:25+09:00 Service default guestbook-ui Synced Healthy 2020-09-15T18:14:25+09:00 Service default guestbook-ui Synced Healthy service/guestbook-ui created 2020-09-15T18:14:25+09:00 apps Deployment default guestbook-ui OutOfSync Missing deployment.apps/guestbook-ui created 2020-09-15T18:14:25+09:00 apps Deployment default guestbook-ui Synced Progressing deployment.apps/guestbook-ui created Name: guestbook Project: default Server: https://kubernetes.default.svc Namespace: default URL: https://a36182a4c9e57495c8e0f245b2d2d8a8-995334307.ap-northeast-1.elb.amazonaws.com/applications/guestbook Repo: https://github.com/argoproj/argocd-example-apps.git Target: HEAD Path: guestbook SyncWindow: Sync Allowed Sync Policy: <none> Sync Status: Synced to HEAD (6bed858) Health Status: Progressing Operation: Sync Sync Revision: 6bed858de32a0e876ec49dad1a2e3c5840d3fb07 Phase: Succeeded Start: 2020-09-15 18:14:25 +0900 JST Finished: 2020-09-15 18:14:26 +0900 JST Duration: 1s Message: successfully synced (all tasks run) GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE Service default guestbook-ui Synced Healthy service/guestbook-ui created apps Deployment default guestbook-ui Synced Progressing deployment.apps/guestbook-ui created # 同期後の確認 $ argocd app get guestbook Name: guestbook Project: default Server: https://kubernetes.default.svc Namespace: default URL: https://a36182a4c9e57495c8e0f245b2d2d8a8-995334307.ap-northeast-1.elb.amazonaws.com/applications/guestbook Repo: https://github.com/argoproj/argocd-example-apps.git Target: HEAD Path: guestbook SyncWindow: Sync Allowed Sync Policy: <none> Sync Status: Synced to HEAD (6bed858) Health Status: Healthy GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE Service default guestbook-ui Synced Healthy service/guestbook-ui created apps Deployment default guestbook-ui Synced Healthy deployment.apps/guestbook-ui created # 他のリソースも作成される $ kubectl get all NAME READY STATUS RESTARTS AGE pod/guestbook-ui-65b878495d-cs87p 1/1 Running 0 2m53s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/guestbook-ui ClusterIP 10.100.247.168 <none> 80/TCP 2m53s service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 3h39m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/guestbook-ui 1/1 1 1 2m53s NAME DESIRED CURRENT READY AGE replicaset.apps/guestbook-ui-65b878495d 1 1 1 2m53s
この時Web UIでも同期が行われていることが確認できます。
しばらく待機すると、以下のようにSynced
Healthy
という状態が確認できます。
アプリケーションを選択すると、Kubernetesリソースの構成が表示されます。
アプリケーションの変更
次にアプリケーションの構成を一部変更してみます。先ほどのWeb UIからguestbook-ui
Deploymentリソースを選択すると、以下のようにYamlファイルが表示されます。
ここでGitリポジトリと異なる状態を作るために、spec.replicas
を3
に変更し、SAVE
を選択します。すると、Web UI上では新たに2つのPodが作成される様子が見られます。またアプリケーションはOutOfSync
の状態となることも確認できます。
コマンドラインから確認しても、Podが追加されたことが確認できます。
$ kubectl get all NAME READY STATUS RESTARTS AGE pod/guestbook-ui-65b878495d-cs87p 1/1 Running 0 16m pod/guestbook-ui-65b878495d-jp559 1/1 Running 0 3m30s★ pod/guestbook-ui-65b878495d-rcqlw 1/1 Running 0 3m30s★ NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/guestbook-ui ClusterIP 10.100.247.168 <none> 80/TCP 16m service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 3h52m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/guestbook-ui 3/3 3 3 16m NAME DESIRED CURRENT READY AGE replicaset.apps/guestbook-ui-65b878495d 3 3 3 16m
このときWeb UIでAPP DIFF
を選択すると、Gitリポジトリで定義された状態と実際のアプリケーションの状態の間にある差分が表示されます。
Gitリポジトリの状態に戻す(=spec.replicas
を1
に戻す)ため、Web UI上のHISTORY AND ROLLBACK
を選択します。すると、変更前のアプリケーションの状態を表すGitリポジトリのRevisionが表示されるので、Redeploy
を選択します。
再デプロイの実行を確認し、OK
を選択します。
Gitリポジトリの状態にロールバックされ、先ほど作成した2つのPodが削除される様子が確認できます。
削除
最後にアプリケーション、及びArgoCDの削除を行います。Web UIからDELETE
を選択すると、削除の確認を求められるのでOK
を選択します。
Kubernetesリソースの削除が開始され、しばらくするとすべてのリソースが削除されたことが確認できます。
コマンドラインからも、アプリケーションの削除が確認できます。
$ kubectl get all NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 4h13m $ kubectl get app -n argocd No resources found in argocd namespace.
最後にArgoCDを削除します。
$ kubectl delete -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml warning: deleting cluster-scoped resources, not scoped to the provided namespace customresourcedefinition.apiextensions.k8s.io "applications.argoproj.io" deleted customresourcedefinition.apiextensions.k8s.io "appprojects.argoproj.io" deleted serviceaccount "argocd-application-controller" deleted serviceaccount "argocd-dex-server" deleted serviceaccount "argocd-server" deleted role.rbac.authorization.k8s.io "argocd-application-controller" deleted role.rbac.authorization.k8s.io "argocd-dex-server" deleted role.rbac.authorization.k8s.io "argocd-server" deleted clusterrole.rbac.authorization.k8s.io "argocd-application-controller" deleted clusterrole.rbac.authorization.k8s.io "argocd-server" deleted rolebinding.rbac.authorization.k8s.io "argocd-application-controller" deleted rolebinding.rbac.authorization.k8s.io "argocd-dex-server" deleted rolebinding.rbac.authorization.k8s.io "argocd-server" deleted clusterrolebinding.rbac.authorization.k8s.io "argocd-application-controller" deleted clusterrolebinding.rbac.authorization.k8s.io "argocd-server" deleted configmap "argocd-cm" deleted configmap "argocd-gpg-keys-cm" deleted configmap "argocd-rbac-cm" deleted configmap "argocd-ssh-known-hosts-cm" deleted configmap "argocd-tls-certs-cm" deleted secret "argocd-secret" deleted service "argocd-dex-server" deleted service "argocd-metrics" deleted service "argocd-redis" deleted service "argocd-repo-server" deleted service "argocd-server-metrics" deleted service "argocd-server" deleted deployment.apps "argocd-application-controller" deleted deployment.apps "argocd-dex-server" deleted deployment.apps "argocd-redis" deleted deployment.apps "argocd-repo-server" deleted deployment.apps "argocd-server" deleted $ kubectl delete namespace argocd namespace "argocd" deleted
本番環境での利用に向けて
ArgoCDは本番環境での稼働実績もあり、また利用するうえでのBest Practiceなども公開されています。最後にこのBest Practiceを眺め、ArgoCDを利用するうえでのポイントについて紹介します。
アプリケーション用リポジトリとマニフェスト用リポジトリを用意する
アプリケーションのソースコードとマニフェストファイルを1つのリポジトリに格納すると、以下のような問題が発生します。
- アプリケーションに対する全てのCommitがデプロイにつながる。例えば、マニフェストファイルの一部を変更するだけの作業でパイプラインを起動したくない、という場合に対応できなくなる。
- 誰でもアプリケーションをリリースできるようになるが、リリースできるメンバーを制限することが難しくなる。
- Git Logにはアプリケーションの変更とデプロイの履歴が混在することになる。Audit Logをキレイにすることにつながる。
- 複数のリポジトリからなるマイクロサービスの場合、それぞれのサービスのバージョンスキーマやリリースサイクルが異なるため、そのうちの一つのリポジトリにマニフェストファイルを一緒に格納すると、意味をなさなくなってしまう場合がある。
- CIパイプラインを自動化している場合、マニフェストファイルをpushすることで、ビルドジョブとGit Commit Triggerの無限ループとなる場合がある。
上記問題を解消するため、アプリケーションのソースコードとマニフェストファイルはそれぞれ別のリポジトリに格納することが推奨されています。
デプロイ用リポジトリの数を適切にする
マニフェストファイルを格納するようなリポジトリをいくつ用意するかは、状況によってその答えが変わってきます。そのため、以下のようなポイントを考慮して決める必要があります。
- 単一のリポジトリ:小規模の会社で自動化をほぼ行わず、全てのメンバーを信頼している
- チームごとにリポジトリを用意する:中規模の会社である程度の自動化を行う
- サービスごとにリポジトリを用意する:大規模な会社で自動化を推進しており、メンバー毎のアクセスなどをコントロールする必要がある
チーム単位で自分たちのリポジトリを所有することで、誰がリリースするかを決定・制御することができます。これにより、リリースのボトルネックとなる単一の中央集権的チームを所有したり、全チームに書き込み権限を与える場合と比べて、自分たち自身でリポジトリの管理を行うことができます。
Commitする前にテストを行う
多くのエンジニアがマニフェストファイルの変更をCommit/Pushし、GitOpsのエージェントはアプリケーションがデプロイできるかによってその変更をチェックします。一方、Commit前にテストを行うことで防げたかもしれないような問題が、運用前の環境に入り込み、なかなか表出しなくなる、という自体も発生する場合があります。
GitOpsエージェントは一般的にCLIコマンドを実行することでマニフェストの生成を行うので、同じコマンドを使えば、ローカル環境でもテストを行うことができます。
Gitマニフェストは外部の変更によって変更すべきではない
KustomizeやHelmといったツールは、同じCommitでも異なるテンプレートマニフェストとすることを可能にします。もしもGit Commit無しでマニフェストファイルが変更されると、以下のような問題が発生します。
そのため、KustomizeやhElmを利用する場合は、特定のCommitにピンを打つことが推奨されます。
# Kustomizeの場合 bases: - github.com/argoproj/argo-cd//manifests/cluster-install?ref=v0.11.1 # Helmの場合 dependencies: - name: argo-cd version: 0.6.1 repository: github.com/argoproj/argo-cd/manifests/cluster-install
またこれと関連し、Gitマニフェスト中にすべてを定義しないことも推奨されています。例えば、Deploymentのspec.replicas
の数をHPAによって制御する場合、Gitマニフェストにレプリカ数を記述してしまうと、Commitのたびにレプリカ数が戻ってしまいます。そのため、外部要因によって動的に変更するパラメータについては、Gitマニフェスト内では管理しないようにすることが推奨されます。
Secretの管理方法を検討する
アプリケーションコードやGitマニフェストに秘匿情報を直接書き込むことはセキュリティ上の問題につながるため、多くはKubernetesのSecretリソースなどを利用します。その他の選択肢としては以下のようなものがあるので、GitOpsを開始する前にSecret情報の扱いについて検討する必要があります。
- Sealed Secret
- External Secret
- Vault
- Helm Secret
- Kustomize secret generator plugins
※参考ドキュメント: