Skip to content
Published on

GitOps 実践ガイド: ArgoCD vs FluxCD アーキテクチャ比較とプロダクション デプロイ戦略

Authors
  • Name
    Twitter
GitOps ArgoCD vs FluxCD

はじめに

現代のクラウドネイティブ環境において、Kubernetesデプロイを管理する方法は大きくPushベースPullベースに分かれる。従来のCI/CDパイプラインはPush方式で、ビルド完了後にkubectl applyhelm upgradeを実行してクラスターに変更をプッシュする。この方式はCIサーバーにクラスターアクセス権限を付与する必要があり、手動変更(kubectl edit、コンソール修正)によるドリフトの検出が困難という根本的な限界がある。

GitOpsはこの問題を解決する運用パラダイムで、Gitリポジトリを**単一の信頼できるソース(Single Source of Truth)とし、クラスター内部のエージェントがGitの望ましい状態と実際の状態を継続的に比較して自動的に同期(Reconciliation)**する。OpenGitOpsプロジェクトが定義した核心原則は以下の通りである。

  1. 宣言的(Declarative): システムの望ましい状態を宣言的に記述する
  2. バージョン管理(Versioned and Immutable): すべての変更履歴がGitに残り、監査追跡が可能
  3. 自動適用(Pulled Automatically): エージェントが自動的に望ましい状態をクラスターに適用する
  4. 継続的調整(Continuously Reconciled): ドリフトを自動的に検出して修正する

本記事では、GitOpsを実装する代表的な2つのツールであるArgoCDFluxCDのアーキテクチャを深層比較し、実際のプロダクション環境でのデプロイ戦略、シークレット管理、CI/CD統合、障害事例と復旧、運用チェックリストまで総合的に解説する。

ArgoCD アーキテクチャ 深層分析

中核コンポーネント

ArgoCDはCNCF Graduatedプロジェクトで、Kubernetes専用のGitOps継続的デプロイツールである。デフォルトでWeb UI、CLI、gRPC/REST APIを提供する。

# ArgoCD Application リソース例
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/org/k8s-manifests.git
    targetRevision: main
    path: apps/my-app/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
      - PruneLast=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

ArgoCDの主要コンポーネントは以下の通りである。

  • API Server: Web UI、CLI、CI/CDシステムが使用するgRPC/REST APIを提供
  • Repo Server: Gitリポジトリをクローンしてマニフェストを生成。Helm、Kustomize、Jsonnetなどをサポート
  • Application Controller: Applicationリソースを監視して調整ループを実行
  • Redis: UIセッションとキャッシュを保存
  • Dex: SSO(Single Sign-On)認証を担当
  • Notifications Controller: Slack、メールなどで同期状態通知を送信

App of Apps パターン

大規模環境ではApp of Appsパターンを使用して、複数のApplicationを1つの親Applicationで管理する。

# 親Application (root-app)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/org/k8s-manifests.git
    targetRevision: main
    path: apps
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

appsディレクトリ内に各サービスのApplication YAMLファイルを配置すると、root-appが自動的にこれを作成・管理する。

ApplicationSet コントローラー

ApplicationSetは1つのテンプレートから複数のApplicationを動的に生成する。マルチクラスター、マルチテナント、モノレポ環境で非常に有用である。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-apps
  namespace: argocd
spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            environment: production
  template:
    metadata:
      name: 'app-{{name}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/k8s-manifests.git
        targetRevision: main
        path: 'apps/{{metadata.labels.region}}/production'
      destination:
        server: '{{server}}'
        namespace: production
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

このApplicationSetはenvironment: productionラベルを持つすべてのクラスターに対して自動的にApplicationを生成する。

Sync Wavesとフック

ArgoCDのSync Waveはリソースデプロイ順序を精密に制御する。

# Wave 0: NamespaceとRBACを最初に作成
apiVersion: v1
kind: Namespace
metadata:
  name: production
  annotations:
    argocd.argoproj.io/sync-wave: '0'

---
# Wave 1: ConfigMapとSecret
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: production
  annotations:
    argocd.argoproj.io/sync-wave: '1'
data:
  DATABASE_HOST: 'postgres.production.svc'
  LOG_LEVEL: 'info'

---
# Wave 2: Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  namespace: production
  annotations:
    argocd.argoproj.io/sync-wave: '2'
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
        - name: api-server
          image: myregistry/api-server:v2.1.0
          ports:
            - containerPort: 8080

---
# PreSyncフック: DBマイグレーション
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  namespace: production
  annotations:
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: myregistry/db-migrate:v2.1.0
          command: ['./migrate', 'up']
      restartPolicy: Never

FluxCD アーキテクチャ 深層分析

中核コンポーネント

FluxCDはCNCF Graduatedプロジェクトで、KubernetesネイティブのGitOpsツールキットである。複数の独立したコントローラーで構成されている。

  • Source Controller: Gitリポジトリ、Helmリポジトリ、OCIアーティファクト、S3バケットなどのソースを管理
  • Kustomize Controller: Kustomizationリソースを監視してクラスターにマニフェストを適用
  • Helm Controller: HelmReleaseリソースを監視してHelmチャートを管理
  • Notification Controller: イベント通知と外部Webhook受信を処理
  • Image Reflector/Automation Controllers: コンテナレジストリの新しいイメージを検知し、自動的にGitを更新

GitRepositoryとKustomization

FluxCDの基本ワークフローは、GitRepositoryでソースを定義し、Kustomizationで適用方法を記述することである。

# ソース定義
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: k8s-manifests
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/org/k8s-manifests.git
  ref:
    branch: main
  secretRef:
    name: git-credentials
  ignore: |
    # 不要なファイルを除外
    docs/
    README.md

---
# 適用定義
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: production-apps
  namespace: flux-system
spec:
  interval: 5m
  retryInterval: 2m
  timeout: 3m
  sourceRef:
    kind: GitRepository
    name: k8s-manifests
  path: ./apps/production
  prune: true
  force: false
  targetNamespace: production
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: api-server
      namespace: production
  postBuild:
    substituteFrom:
      - kind: ConfigMap
        name: cluster-vars

HelmReleaseコントローラー

FluxCDのHelm ControllerはHelmRelease CRDを通じてHelmチャートのライフサイクルを宣言的に管理する。

apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
  name: bitnami
  namespace: flux-system
spec:
  interval: 30m
  url: https://charts.bitnami.com/bitnami

---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: postgresql
  namespace: production
spec:
  interval: 10m
  chart:
    spec:
      chart: postgresql
      version: '15.x'
      sourceRef:
        kind: HelmRepository
        name: bitnami
        namespace: flux-system
  values:
    primary:
      persistence:
        size: 50Gi
      resources:
        requests:
          memory: 512Mi
          cpu: 250m
    metrics:
      enabled: true
  upgrade:
    remediation:
      retries: 3
      remediateLastFailure: true
  rollback:
    cleanupOnFail: true
    timeout: 5m

FluxCD 依存関係管理

Kustomizationリソース間の依存関係を宣言してデプロイ順序を制御できる。

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: infrastructure
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: k8s-manifests
  path: ./infrastructure
  prune: true

---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: applications
  namespace: flux-system
spec:
  interval: 10m
  dependsOn:
    - name: infrastructure
  sourceRef:
    kind: GitRepository
    name: k8s-manifests
  path: ./applications
  prune: true

infrastructure Kustomizationが正常に適用された後にのみapplicationsが適用される。

ArgoCD vs FluxCD 比較表

項目ArgoCDFluxCD
CNCFステータスGraduatedGraduated
Web UIO(内蔵、豊富な機能)X(別途Weave GitOps UIを使用)
CLIargocd CLIflux CLI
アーキテクチャモノリシック(複数コンポーネントが一体)マイクロサービス(独立コントローラー)
CRDApplication, ApplicationSet, AppProjectGitRepository, Kustomization, HelmReleaseなど
マルチクラスターハブ・スポークモデルクラスターごとにFluxをインストール
HelmサポートO(ソースとして直接参照)O(HelmRelease CRD)
KustomizeOO(ネイティブ)
RBAC独自RBAC + SSO統合KubernetesネイティブRBAC
通知Notification ControllerNotification Controller
イメージ自動更新Image Updater(別途インストール)Image Automation Controller
ドリフト検出O(リアルタイムUI表示)O(イベントベース)
同期順序Sync Wave + フックdependsOn依存関係
SSOサポートO(Dex内蔵)X(Kubernetes RBACに委譲)
マルチテナンシーAppProjectベースネームスペースベース
Git対応GitHub, GitLab, BitbucketなどGitHub, GitLab, Bitbucket, S3, OCIなど
学習曲線中程度(UIが助けになる)高め(CLI中心)
リソース使用量比較的高い比較的低い

デプロイ戦略

Blue-Greenデプロイ(Argo Rollouts)

ArgoCDと共にArgo Rolloutsを使用すると、Blue-Greenデプロイを宣言的に実装できる。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: api-server
  namespace: production
spec:
  replicas: 5
  strategy:
    blueGreen:
      activeService: api-server-active
      previewService: api-server-preview
      autoPromotionEnabled: false
      prePromotionAnalysis:
        templates:
          - templateName: success-rate
        args:
          - name: service-name
            value: api-server-preview
      scaleDownDelaySeconds: 30
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
        - name: api-server
          image: myregistry/api-server:v2.2.0
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5

---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
  namespace: production
spec:
  args:
    - name: service-name
  metrics:
    - name: success-rate
      interval: 30s
      count: 5
      successCondition: result[0] >= 0.95
      provider:
        prometheus:
          address: http://prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{service="{{args.service-name}}",status=~"2.."}[5m])) /
            sum(rate(http_requests_total{service="{{args.service-name}}"}[5m]))

Canaryデプロイ(Flagger + FluxCD)

FluxCD環境ではFlaggerを使用してCanaryデプロイを自動化する。

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: api-server
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  service:
    port: 8080
    targetPort: 8080
  analysis:
    interval: 1m
    threshold: 5
    maxWeight: 50
    stepWeight: 10
    metrics:
      - name: request-success-rate
        thresholdRange:
          min: 99
        interval: 1m
      - name: request-duration
        thresholdRange:
          max: 500
        interval: 1m
    webhooks:
      - name: load-test
        type: rollout
        url: http://flagger-loadtester.production/
        metadata:
          cmd: 'hey -z 1m -q 10 -c 2 http://api-server-canary.production:8080/'

シークレット管理

SOPS(Secrets OPerationS)

SOPSはファイルレベルでシークレットを暗号化してGitに安全に保存するツールである。FluxCDはSOPSをネイティブにサポートする。

# .sops.yaml(リポジトリルートに配置)
creation_rules:
  - path_regex: .*.enc.yaml
    encrypted_regex: '^(data|stringData)$'
    age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# シークレット暗号化
sops --encrypt --in-place secrets/production/db-credentials.enc.yaml

# FluxCD KustomizationでSOPS復号化を有効化
flux create kustomization production-secrets \
  --source=GitRepository/k8s-manifests \
  --path="./secrets/production" \
  --prune=true \
  --interval=10m \
  --decryption-provider=sops \
  --decryption-secret=sops-age

Sealed Secrets

Sealed Secretsは非対称暗号化を使用してシークレットをGitに安全に保存する。

# SealedSecret作成
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password=supersecret \
  --dry-run=client -o yaml | \
  kubeseal --controller-name=sealed-secrets \
  --controller-namespace=kube-system \
  --format=yaml > sealed-db-credentials.yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  encryptedData:
    username: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...
    password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...
  template:
    type: Opaque
    metadata:
      name: db-credentials
      namespace: production

Vault統合(ArgoCD Vault Plugin)

HashiCorp VaultとArgoCDを統合してシークレットを動的に注入する。

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: production
  annotations:
    avp.kubernetes.io/path: 'secret/data/production/database'
type: Opaque
stringData:
  username: <username>
  password: <password>

上記のマニフェストで<username><password>は、ArgoCD Vault PluginがVaultから値を取得して実際のシークレット値に置き換えるプレースホルダーである。

CI/CD統合パターン

GitHub Actions + ArgoCD

# .github/workflows/deploy.yml
name: Build and Deploy
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build and Push Image
        run: |
          docker build -t myregistry/api-server:$GITHUB_SHA .
          docker push myregistry/api-server:$GITHUB_SHA

      - name: Update Kubernetes Manifests
        run: |
          git clone https://github.com/org/k8s-manifests.git
          cd k8s-manifests
          kustomize edit set image myregistry/api-server=myregistry/api-server:$GITHUB_SHA
          git add .
          git commit -m "chore: update api-server image to $GITHUB_SHA"
          git push

このパターンでは、CI(GitHub Actions)はイメージビルドとマニフェストリポジトリの更新のみを担当し、実際のデプロイはArgoCDがGit変更を検知して自動的に実行する。

障害事例と復旧手順

事例1: Sync Loop(無限同期ループ)

状況: ArgoCD ApplicationがSync完了後、即座にOutOfSync状態に遷移し、無限同期ループに陥った。原因はAdmission Webhookがリソースにデフォルト値を注入し、Gitのマニフェストとの差分が発生したことだった。

症状:

  • Application状態がSyncedとOutOfSyncを繰り返す
  • ArgoCD API Server CPU使用量が急増
  • Repo Serverメモリ使用量が増加

復旧手順:

# 1. 自動同期を一時停止
argocd app set my-app --sync-policy none

# 2. ドリフト原因を分析
argocd app diff my-app --local ./manifests/

# 3. ignoreDifferences設定でWebhook注入フィールドを無視
argocd app set my-app --ignore-differences \
  'group=apps, kind=Deployment, jsonPointers=[/spec/template/metadata/annotations]'

# 4. マニフェストにWebhookが注入するデフォルト値を明示的に追加

# 5. 自動同期を再有効化
argocd app set my-app --sync-policy automated

事例2: ドリフト検出の失敗

状況: FluxCDのKustomizationが成功状態を報告しているが、実際のクラスターで手動変更されたリソースが復元されなかった。forceオプションが無効化されており、手動変更がFluxCDが管理しないフィールドで発生していた。

症状:

  • Kustomization状態はReady
  • 実際のリソース設定がGitと異なる
  • kubectl diffで差分を確認可能

復旧手順:

# 1. FluxCD強制調整をトリガー
flux reconcile kustomization production-apps --with-source

# 2. forceオプションを有効化(server-side applyを使用)
flux create kustomization production-apps \
  --source=GitRepository/k8s-manifests \
  --path="./apps/production" \
  --prune=true \
  --force=true \
  --interval=5m

# 3. 手動変更防止のためのOPAポリシーを追加
# (kubectl edit, kubectl patchなどを制限)

事例3: Helm Releaseロールバック失敗

状況: FluxCD HelmReleaseのアップグレードが失敗したが、自動ロールバックが動作しなかった。remediation設定でremediateLastFailureがfalseになっていた。

症状:

  • HelmRelease状態がFailed
  • 以前のバージョンのリリースも破損
  • Helm historyにfailedリリースが蓄積

復旧手順:

# 1. HelmRelease状態確認
flux get helmrelease -n production

# 2. Helmリリース履歴確認
helm history postgresql -n production

# 3. 手動ロールバック
helm rollback postgresql 3 -n production

# 4. HelmRelease設定に自動復旧を追加
flux create helmrelease postgresql \
  --source=HelmRepository/bitnami \
  --chart=postgresql \
  --chart-version="15.x" \
  --target-namespace=production \
  --values=values/postgresql.yaml \
  --remediation-retries=3

プロダクションデプロイチェックリスト

事前準備

  • Gitリポジトリ構造を設計(モノレポ vs ポリレポの決定)
  • ブランチ戦略を策定(main -> staging -> production)
  • RBACポリシーを設計(どのチームがどのApplication/Kustomizationを管理するか)
  • シークレット管理方法を決定(SOPS、Sealed Secrets、Vaultから選択)

ArgoCD設定

  • HA(高可用性)モードでデプロイ(最低3レプリカ)
  • Redis SentinelまたはRedis Clusterを構成
  • DexまたはOIDCによるSSO設定
  • AppProjectごとにソースリポジトリとターゲットクラスターを制限
  • Resource Exclusions/Inclusions設定で管理範囲を明確化

FluxCD設定

  • 各クラスターに独立したFluxCDをインストール
  • Source ControllerのGitポーリング間隔を最適化(デフォルト1分)
  • Kustomizationのヘルスチェック対象リソースを指定
  • Notification ControllerでSlack/Teams通知を構成

運用上の注意事項

  • Gitリポジトリのwrite権限を最小化(PRベースの変更)
  • プロダクションデプロイは必ずPRレビュー後にマージ
  • 同期間隔とタイムアウトをワークロード特性に合わせて調整
  • 大規模マニフェスト変更時はSync WaveやdependsOnで順序を保証
  • Helmチャートバージョンは範囲ではなく固定バージョンで指定
  • ロールバックのためのGit revertプロセスを文書化

モニタリング

  • ArgoCD: Application同期状態メトリクスを収集(argocd_app_info
  • FluxCD: Kustomization/HelmRelease状態メトリクスを収集
  • 同期失敗時の自動アラートを設定(PagerDuty、OpsGenie連携)
  • 定期的なドリフト監査レポートを生成

まとめ

GitOpsはKubernetesデプロイ管理の標準として定着した。ArgoCDとFluxCDはともにCNCF Graduatedプロジェクトとして成熟したエコシステムを備えており、どちらのツールを選択してもGitOpsの核心原則を忠実に実装できる。

ArgoCDは豊富なWeb UIとApplicationSetによるマルチクラスター管理、Argo Rolloutsとの統合を強みとする。FluxCDはKubernetesネイティブなマイクロサービスアーキテクチャ、軽量なリソース使用量、SOPSのネイティブサポートを強みとする。

重要なのはツールの選択よりもGitOps文化の定着である。すべての変更がGitを通じて行われるようにプロセスを確立し、手動変更を防ぐガードレールを構築し、ドリフトを継続的に検出・修正する自動化体制を整えることが、真のGitOpsの完成である。

参考資料