2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kubernetesを学ぶ9日間 - Day 7: ArgoCD GitOps実践

Last updated at Posted at 2025-12-11

はじめに

「ジャンルなしオンラインもくもく会 Advent Calendar 2025」の11日目の記事です。

昨日(12/10)はHelmとKustomizeの使い分けでマニフェスト管理を学びました。今日は、GitOpsの実践としてArgoCDを導入し、Gitへのpushだけでクラスタが自動更新される世界を構築します。

本シリーズの全体構成

前回までのおさらい

GitOpsとは?

定義

GitをKubernetesクラスタの唯一の信頼できる情報源(Single Source of Truth)として扱う運用手法

GitOpsの4原則

  1. 宣言的(Declarative): 望ましい状態をマニフェストで宣言
  2. バージョン管理・不変(Versioned and Immutable): Gitで全ての変更を追跡し、履歴を改変しない
  3. 自動取得(Pulled Automatically): クラスタがGitから自動的に状態を取得
  4. 継続的な調整(Continuously Reconciled): Gitとクラスタの状態を常に一致させる

従来のCI/CDとの違い

【従来のCI/CD】
Git commit → CI/CD Pipeline → kubectl apply → Cluster
              ↑
            認証情報が必要(セキュリティリスク)

【GitOps】
Git commit → Git Repository ← Argo CD (Pull) → Cluster
                              ↑
                          クラスタ内で実行(認証情報不要)

メリット

  • ✅ CI/CDパイプラインにクラスタ認証情報が不要
  • ✅ Git履歴 = デプロイ履歴
  • ✅ Git revert = ロールバック
  • ✅ PRレビュー = 変更レビュー

Argo CD の準備

本記事では、Argo CD がすでにクラスタにインストールされている前提で進めます。

インストール方法について
Argo CD のインストールは kubectl apply や Helm など複数の方法があります。詳細は Argo CD 公式ドキュメント - Getting Started を参照してください。

1. インストール確認

# Pod起動確認
kubectl get pods -n argocd
NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          2m
argocd-applicationset-controller-7c4d5d5d9f-xxxxx   1/1     Running   0          2m
argocd-redis-7c4d5d5d9f-xxxxx                       1/1     Running   0          2m
argocd-repo-server-7c4d5d5d9f-xxxxx                 1/1     Running   0          2m
argocd-server-7c4d5d5d9f-xxxxx                      1/1     Running   0          2m

2. 初期パスワード取得

# admin初期パスワード取得
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# 出力例: xYz123AbC456

3. Argo CD UIアクセス

ブラウザで以下にアクセス

4. Argo CD CLIインストール(オプション)

# macOS
brew install argocd

# Linux
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd
sudo mv argocd /usr/local/bin/

# ログイン
argocd login argocd.homelab.local --username admin --password <your-password>

# パスワード変更
argocd account update-password

GitOps実践: サンプルアプリケーションのデプロイ

シナリオ

Week 1で構築したTalos Linuxクラスタに、デモアプリケーション(Nginx)をGitOpsでデプロイします。

本シリーズで使用しているマニフェストは公開リポジトリで確認できます
https://github.com/r4sd/k8s-advent-2025/tree/main/kubernetes/apps

デモアプリケーションの構成

kubernetes/apps/demo-app.yaml には以下のリソースが含まれています

---
apiVersion: v1
kind: Namespace
metadata:
  name: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
      - name: html
        configMap:
          name: nginx-demo-html
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-demo
  namespace: demo
spec:
  selector:
    app: nginx-demo
  ports:
  - port: 80
    targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-demo
  namespace: demo
spec:
  ingressClassName: nginx
  rules:
  - host: demo.homelab.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-demo
            port:
              number: 80

Argo CD Application定義

このデモアプリをArgo CDで管理するApplication定義を作成します

argocd/demo-app.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demo-app
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default

  source:
    repoURL: https://github.com/r4sd/k8s-advent-2025
    targetRevision: main
    path: kubernetes/apps

  destination:
    server: https://kubernetes.default.svc
    namespace: demo

  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

Argo CDへアプリケーション登録

# Argo CD Applicationをクラスタに適用
kubectl apply -f argocd/demo-app.yaml

# または、Argo CD CLIで登録
argocd app create demo-app \
  --repo https://github.com/r4sd/k8s-advent-2025 \
  --path kubernetes/apps \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace demo \
  --sync-policy automated \
  --auto-prune \
  --self-heal

# アプリケーション一覧確認
argocd app list
NAME      CLUSTER                         NAMESPACE  PROJECT  STATUS  HEALTH   SYNCPOLICY
demo-app  https://kubernetes.default.svc  demo       default  Synced  Healthy  Auto-Prune

# アプリケーション詳細確認
argocd app get demo-app

動作確認: GitOps フロー

1. Gitリポジトリを変更

# demo-app.yaml のreplica数を変更
vi kubernetes/apps/demo-app.yaml
# replicas: 2 → replicas: 4 に変更

# Commit & Push
git add .
git commit -m "Scale demo-app to 4 replicas"
git push origin main

2. Argo CDが自動検知・デプロイ

# Argo CDは定期的(デフォルト3分)にGitをポーリング
# 変更を検知すると自動的にsync

# リアルタイム確認
watch kubectl get pods -n demo
NAME                          READY   STATUS    RESTARTS   AGE
nginx-demo-5d8b9d8d9f-xxxxx   1/1     Running   0          5m
nginx-demo-5d8b9d8d9f-yyyyy   1/1     Running   0          5m
nginx-demo-5d8b9d8d9f-zzzzz   1/1     Running   0          10s  # 新規追加
nginx-demo-5d8b9d8d9f-aaaaa   1/1     Running   0          10s  # 新規追加

3. Argo CD UIで確認

ArgoCD Resource Tree.png

Argo CD UIでは以下が可視化されます

  • Application: アプリケーション全体の状態
  • Resources: 各Kubernetesリソースの状態(Deployment, Pod, Service, Ingress)
  • Sync Status: Gitとクラスタの同期状態
  • Health Status: リソースの健全性(Healthy, Progressing, Degraded)
  • Events: 同期履歴

実践: homelab環境でのセットアップ

ここからは、実際のhomelab環境でArgo CDをセットアップした手順を紹介します。

1. プライベートリポジトリの登録

GitHubのプライベートリポジトリを使用する場合、認証情報の設定が必要です。

GitHub Personal Access Token (PAT) の選択

PAT種類 メリット デメリット
Classic 設定が簡単 権限が広範囲
Fine-grained リポジトリ単位で権限制御 設定が細かい

セキュリティの観点から、Fine-grained PAT を推奨します。

Fine-grained PAT の作成

GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens

必要な権限

  • Repository access: 対象リポジトリのみ選択
  • Permissions:
    • Contents: Read-only(必須)
    • Metadata: Read-only(自動付与)

⚠️ よくあるエラー

Write access to repository not granted エラーが出る場合、ContentsのRead権限が付与されていません。GitHubでPATの権限を確認してください。

ArgoCD CLIでリポジトリ登録

# ArgoCD にログイン
argocd login argocd.homelab.local --username admin

# プライベートリポジトリを登録
argocd repo add https://github.com/your-username/your-repo \
  --username your-username \
  --password ghp_xxxxxxxxxxxx  # Fine-grained PAT

# 登録確認
argocd repo list
TYPE  NAME  REPO                                        INSECURE  ...  STATUS
git         https://github.com/your-username/your-repo  false     ...  Successful

2. Application作成(CLI)

既存のマニフェストをArgoCD管理下に置きます。

# Application作成
argocd app create demo-app \
  --repo https://github.com/r4sd/homelab-infra \
  --path kubernetes/apps \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace demo \
  --sync-policy none

# 作成確認
argocd app get demo-app

出力例

Name:               argocd/demo-app
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          demo
URL:                https://argocd.homelab.local/applications/demo-app
Source:
- Repo:             https://github.com/r4sd/homelab-infra
  Path:             kubernetes/apps
Sync Status:        OutOfSync from  (010c683)
Health Status:      Missing

GROUP              KIND        NAMESPACE  NAME             STATUS     HEALTH
                   ConfigMap   demo       nginx-demo-html  OutOfSync  Missing
                   Namespace              demo             OutOfSync  Missing
                   Service     demo       nginx-demo       OutOfSync  Missing
apps               Deployment  demo       nginx-demo       OutOfSync  Missing
networking.k8s.io  Ingress     demo       nginx-demo       OutOfSync  Missing

ArgoCD がGitリポジトリからマニフェストを読み取り、5つのリソースを検出しました。

3. Sync実行

argocd app sync demo-app

出力例

Name:               argocd/demo-app
Sync Status:        Synced to  (010c683)
Health Status:      Progressing

Operation:          Sync
Sync Revision:      010c683c41fbef2fdc2957c9b08e2e2489fd8596
Phase:              Succeeded
Start:              2025-12-03 19:41:06 +0900 JST
Finished:           2025-12-03 19:41:07 +0900 JST
Duration:           1s
Message:            successfully synced (all tasks run)

GROUP              KIND        NAMESPACE  NAME             STATUS   HEALTH       MESSAGE
                   Namespace   demo       demo             Running  Synced       namespace/demo created
                   ConfigMap   demo       nginx-demo-html  Synced                configmap/nginx-demo-html created
                   Service     demo       nginx-demo       Synced   Healthy      service/nginx-demo created
apps               Deployment  demo       nginx-demo       Synced   Healthy      deployment.apps/nginx-demo created
networking.k8s.io  Ingress     demo       nginx-demo       Synced   Progressing  ingress created

1秒でSync完了し、全リソースが作成されました。

4. Discord通知の確認

通知コントローラのログで、Discordへの通知送信を確認

kubectl logs -n argocd -l app.kubernetes.io/name=argocd-notifications-controller --tail=20

出力例

{"level":"info","msg":"Start processing","resource":"argocd/demo-app","time":"2025-12-03T10:41:07Z"}
{"level":"info","msg":"Trigger on-sync-succeeded result: [{[0].xxx true}]","resource":"argocd/demo-app"}
{"level":"info","msg":"Sending notification about condition 'on-sync-succeeded' to '{discord}'"}
POST https://discord.com/api/webhooks/xxxxxxxxx/yyyyyyyy
{"level":"info","msg":"Processing completed","resource":"argocd/demo-app"}

Discordの #gitops チャンネルに以下のような通知が届きます

✅ Sync Succeeded
Application demo-app synced successfully

Application: demo-app
Namespace:   demo
Revision:    010c683

5. 最終状態確認

# Application状態
argocd app get demo-app
# Sync Status:   Synced
# Health Status: Healthy

# Pod確認
kubectl get pods -n demo
NAME                          READY   STATUS    RESTARTS   AGE
nginx-demo-7d57987576-2fd4r   1/1     Running   0          2m
nginx-demo-7d57987576-xkjs6   1/1     Running   0          2m

これでArgoCD による GitOps 運用の基盤が整いました。以降はGitリポジトリへの変更がArgoCD で検知され、Sync時にDiscord通知が送信されます。


高度な設定

1. Webhook設定(即時同期)

デフォルトでは3分ごとのポーリングですが、Webhookを設定することで即時同期が可能です。

📝 homelab環境での注意

GitHub WebhookはGitHubからArgo CDへHTTPリクエストを送る仕組みです。homelab.local のようなローカルドメインはGitHubから到達できないため、外部公開環境向けの設定です。

GitHub Webhook設定(外部公開環境向け)

# Argo CD Webhook URLを取得
echo "https://argocd.example.com/api/webhook"

# GitHubリポジトリの Settings → Webhooks → Add webhook
# Payload URL: https://argocd.example.com/api/webhook
# Content type: application/json
# Secret: (任意のシークレット)
# Events: Just the push event

2. ApplicationSet: 複数環境の一括管理

複数環境(develop, staging, production)を一つのマニフェストで管理:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: frontend-all-envs
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - env: develop
        replicas: 1
      - env: staging
        replicas: 2
      - env: production
        replicas: 5

  template:
    metadata:
      name: 'frontend-{{env}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/your-org/k8s-gitops-demo
        targetRevision: main
        path: 'applications/frontend/overlays/{{env}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{env}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
# ApplicationSet適用
kubectl apply -f argocd/frontend-applicationset.yaml

# 自動的に3つのApplicationが作成される
argocd app list
NAME                 CLUSTER                         NAMESPACE   PROJECT  STATUS  HEALTH
frontend-develop     https://kubernetes.default.svc  develop     default  Synced  Healthy
frontend-staging     https://kubernetes.default.svc  staging     default  Synced  Healthy
frontend-production  https://kubernetes.default.svc  production  default  Synced  Healthy

3. Progressive Delivery: 段階的ロールアウト

RollingUpdate戦略で環境ごとに段階的にデプロイ

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: frontend-progressive
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - env: develop
      - env: staging
      - env: production

  strategy:
    type: RollingSync
    rollingSync:
      steps:
        # Step 1: develop環境を先にデプロイ
        - matchExpressions:
            - key: env
              operator: In
              values:
                - develop

        # Step 2: develop成功後、staging環境をデプロイ
        - matchExpressions:
            - key: env
              operator: In
              values:
                - staging

        # Step 3: staging成功後、production環境をデプロイ
        - matchExpressions:
            - key: env
              operator: In
              values:
                - production

  template:
    metadata:
      name: 'frontend-{{env}}'
      labels:
        env: '{{env}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/your-org/k8s-gitops-demo
        targetRevision: main
        path: 'applications/frontend/overlays/{{env}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{env}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

フロー:

Git Push → dev環境デプロイ → 成功 → staging環境デプロイ → 成功 → production環境デプロイ

4. Sync Waves: リソース作成順序の制御

依存関係のあるリソース(例: Database → Migration → Application)を順番にデプロイ

# 1. Database(Wave 0)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgresql
  annotations:
    argocd.argoproj.io/sync-wave: "0"  # 最初にデプロイ
spec:
  # ...

---
# 2. Database Migration(Wave 1)
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
  annotations:
    argocd.argoproj.io/sync-wave: "1"  # DBの後にデプロイ
spec:
  # ...

---
# 3. Application(Wave 2)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  annotations:
    argocd.argoproj.io/sync-wave: "2"  # Migrationの後にデプロイ
spec:
  # ...

5. Sync Hooks: デプロイ前後の処理

# Pre-Sync Hook: デプロイ前にバックアップ
apiVersion: batch/v1
kind: Job
metadata:
  name: database-backup
  annotations:
    argocd.argoproj.io/hook: PreSync  # Sync前に実行
    argocd.argoproj.io/hook-delete-policy: HookSucceeded  # 成功後削除
spec:
  template:
    spec:
      containers:
      - name: backup
        image: postgres:15
        command: ["pg_dump", "-h", "postgresql", "-U", "admin", "-d", "app"]
      restartPolicy: Never

---
# Post-Sync Hook: デプロイ後にテスト
apiVersion: batch/v1
kind: Job
metadata:
  name: smoke-test
  annotations:
    argocd.argoproj.io/hook: PostSync  # Sync後に実行
    argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
  template:
    spec:
      containers:
      - name: test
        image: curlimages/curl
        command: ["curl", "http://frontend/health"]
      restartPolicy: Never

トラブルシューティング

Application が Synced にならない

# Application状態確認
argocd app get demo-app

# 詳細ログ確認
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-application-controller

# 手動Sync
argocd app sync demo-app

# Diff確認(Gitとクラスタの差分)
argocd app diff demo-app

Application が Degraded になる

# 各リソースの健全性確認
argocd app resources demo-app

# Podログ確認
kubectl logs -n demo -l app=nginx-demo

# Event確認
kubectl get events -n demo --sort-by='.lastTimestamp'

Git Repository接続エラー

# Repository接続確認
argocd repo list

# 認証情報再設定(HTTPSの場合)
argocd repo add https://github.com/your-org/k8s-gitops-demo \
  --username your-username \
  --password your-token

# 認証情報再設定(SSHの場合)
argocd repo add git@github.com:your-org/k8s-gitops-demo.git \
  --ssh-private-key-path ~/.ssh/id_rsa

Argo CD UI Tips

1. Resource Tree View

Argo CD UIでは、Applicationのリソースがツリー構造で可視化されます:

Application: demo-app
├── Deployment: nginx-demo
│   ├── ReplicaSet: nginx-demo-7d57987576
│   │   ├── Pod: nginx-demo-7d57987576-xxxxx
│   │   └── Pod: nginx-demo-7d57987576-yyyyy
├── Service: nginx-demo
└── Ingress: nginx-demo

2. Sync Options

  • Sync: Gitの状態をクラスタに適用
  • Refresh: Gitから最新状態を取得
  • Hard Refresh: キャッシュをクリアして強制再取得

3. Rollback

Argo CD UIでSync履歴を確認し、任意のリビジョンにロールバック可能:

History:
- Revision 3 (main:abc123) - Scale to 5 replicas (Current)
- Revision 2 (main:def456) - Update image to v1.2.0
- Revision 1 (main:ghi789) - Initial deployment

→ Revision 2にロールバック可能

Discord通知連携

Argo CDのSync状態をDiscordに通知することで、デプロイ状況をリアルタイムで把握できます。

1. Notificationsの有効化

Helm values.yamlで通知機能を有効化

notifications:
  enabled: true

  # Discord webhook Secret
  secret:
    items:
      discord-webhook-url: "YOUR_DISCORD_WEBHOOK_URL"

  # 通知サービス設定
  notifiers:
    service.webhook.discord: |
      url: $discord-webhook-url
      headers:
        - name: Content-Type
          value: application/json

  # 通知テンプレート
  templates:
    template.app-sync-succeeded: |
      webhook:
        discord:
          method: POST
          body: |
            {
              "embeds": [{
                "title": "✅ Sync Succeeded",
                "description": "Application **{{.app.metadata.name}}** synced successfully",
                "color": 3066993,
                "fields": [
                  {"name": "Application", "value": "{{.app.metadata.name}}", "inline": true},
                  {"name": "Namespace", "value": "{{.app.spec.destination.namespace}}", "inline": true},
                  {"name": "Revision", "value": "{{.app.status.sync.revision | substr 0 7}}", "inline": true}
                ]
              }]
            }

    template.app-sync-failed: |
      webhook:
        discord:
          method: POST
          body: |
            {
              "embeds": [{
                "title": "❌ Sync Failed",
                "description": "Application **{{.app.metadata.name}}** sync failed",
                "color": 15158332,
                "fields": [
                  {"name": "Application", "value": "{{.app.metadata.name}}", "inline": true},
                  {"name": "Message", "value": "{{.app.status.operationState.message}}", "inline": false}
                ]
              }]
            }

    template.app-health-degraded: |
      webhook:
        discord:
          method: POST
          body: |
            {
              "embeds": [{
                "title": "⚠️ Health Degraded",
                "description": "Application **{{.app.metadata.name}}** health is degraded",
                "color": 15105570,
                "fields": [
                  {"name": "Application", "value": "{{.app.metadata.name}}", "inline": true},
                  {"name": "Health Status", "value": "{{.app.status.health.status}}", "inline": true}
                ]
              }]
            }

  # トリガー設定
  triggers:
    trigger.on-sync-succeeded: |
      - when: app.status.operationState.phase in ['Succeeded']
        send: [app-sync-succeeded]

    trigger.on-sync-failed: |
      - when: app.status.operationState.phase in ['Error', 'Failed']
        send: [app-sync-failed]

    trigger.on-health-degraded: |
      - when: app.status.health.status == 'Degraded'
        send: [app-health-degraded]

  # デフォルトトリガー(全Applicationに適用)
  subscriptions:
    - recipients:
        - discord
      triggers:
        - on-sync-succeeded
        - on-sync-failed
        - on-health-degraded

2. 通知の種類

イベント 通知内容 用途
Sync Succeeded ✅ デプロイ成功 正常確認
Sync Failed ❌ デプロイ失敗 即座に対応
Health Degraded ⚠️ 健全性低下 Pod起動失敗等

3. Discordでの表示例

✅ Sync Succeeded
Application demo-app synced successfully

Application: demo-app
Namespace: demo
Revision: abc1234

まとめ

GitOpsのメリット

  • Declarative: 望ましい状態をGitで宣言
  • Auditable: 全ての変更がGit履歴に記録
  • Reversible: Git revertで即座にロールバック
  • Secure: CI/CDパイプラインにクラスタ認証情報が不要
  • Collaborative: PRレビューで変更を検証

Argo CDの強み

  • ✅ UI/CLIの両方で操作可能
  • ✅ ApplicationSet で複数環境を一括管理
  • ✅ Sync Waves/Hooks で柔軟なデプロイ制御
  • ✅ Health Status で各リソースの健全性を監視
  • ✅ Webhook/Pollingで自動同期

所感

  • 1つの記事でまとめるにはちょっとつらいが、ぼちぼちやっていければと思いました
  • 自宅環境をGitOpsにできたことで今まで何をどこまでやったか?から脱却できたのは嬉しいです!!

次回予告

次回(12/17)は、Kubernetesクラスタのセキュリティベストプラクティスを実装します。Pod Security Standards、Network Policy、RBAC、Secrets管理など、本番運用に必須のセキュリティ設定を解説します!


参考リンク

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?