GitOpsは、Gitリポジトリをシステムの望ましい状態の単一の信頼源(Single Source of Truth)として扱い、宣言的にインフラとアプリケーションを管理するアプローチだ。従来のCI/CDパイプラインでは「pushベース」でデプロイが実行されていたが、GitOpsでは「pullベース」で、Gitの状態とクラスタの状態を継続的に同期します。
筆者がGitOpsを本格的に導入したのは3年前のことだが、それ以来デプロイに関する運用負荷が劇的に低下した。ロールバックはGitのrevertだけで完結し、誰がいつ何を変更したかの監査証跡も自然に残る。本記事では、GitOpsの実装ツールとして最も広く採用されているArgoCDの導入から運用までを解説します。
ArgoCDはCNCF(Cloud Native Computing Foundation)の卒業プロジェクトであり、Kubernetes上で動作するGitOps型の継続的デリバリーツールだ。主要コンポーネントとして、API Server、Repository Server、Application Controllerの3つで構成されています。
まずはKubernetesクラスタにArgoCDをインストールします。Helmを使った方法が最も管理しやすい。
# namespaceの作成
kubectl create namespace argocd
# Helmリポジトリの追加
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
# ArgoCDのインストール
helm install argocd argo/argo-cd \
--namespace argocd \
--set server.service.type=LoadBalancer \
--set configs.params.server\.insecure=true
# 初期パスワードの取得
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
ArgoCDでは、デプロイ対象をApplicationというカスタムリソースで定義します。以下はシンプルなアプリケーション定義の例だ。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/my-app-manifests.git
targetRevision: main
path: overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
syncPolicy.automatedを設定することで、Gitリポジトリに変更がpushされると自動的にクラスタへ反映されます。selfHeal: trueは、手動でクラスタ上のリソースを変更した場合にGitの状態に自動で戻す設定だ。これにより、設定のドリフトを防止できます。
複数のアプリケーションを管理する場合、App of Appsパターンが有効です。親Applicationが子Applicationを管理する構造で、大規模な環境でもスケーラブルに運用できます。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: app-of-apps
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/argocd-apps.git
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
実運用では、開発・ステージング・本番の各環境で異なる設定が必要になります。Kustomizeを使った環境別管理が最も一般的です。
# ディレクトリ構造
# manifests/
# base/
# deployment.yaml
# service.yaml
# kustomization.yaml
# overlays/
# dev/
# kustomization.yaml
# staging/
# kustomization.yaml
# production/
# kustomization.yaml
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patchesStrategicMerge:
- deployment-patch.yaml
namePrefix: prod-
commonLabels:
env: production
筆者のチームでは、マニフェスト用リポジトリとアプリケーションコード用リポジトリを分離しています。これにより、インフラ変更とアプリケーション変更のライフサイクルを独立して管理でき、権限分離も容易になります。
GitOpsの最大の課題は、機密情報をGitに格納できないことだ。Sealed SecretsやExternal Secrets Operatorを併用して、暗号化された状態でGit管理することを強く推奨します。
同期が失敗した場合、ArgoCDのUI上で詳細なエラーメッセージを確認できます。よくある原因としては、リソースの依存関係の問題やRBACの権限不足があります。argocd app syncコマンドで手動同期を実行し、問題を特定するのが定石だ。
# 同期状態の確認
argocd app get my-app
# 手動同期の実行
argocd app sync my-app --prune
# 同期履歴の確認
argocd app history my-app
GitOpsとArgoCDの組み合わせは、Kubernetesベースのデプロイを劇的に改善します。導入初期はlearning curveがあるが、一度軌道に乗れば運用コストの大幅な削減が期待できます。まずは非本番環境から始めて、チームに合った運用フローを確立していきましょう。