- Published on
ArgoCD GitOps 完全ガイド: ApplicationSet·Sync Waves·Hookで実現するKubernetes宣言的デプロイ
- Authors
- Name
- はじめに
- ArgoCD アーキテクチャ概要
- Application リソース基本構成
- AppProjectによるRBAC実装
- ApplicationSet ジェネレーター
- Sync Wavesによるデプロイ順序制御
- Sync Hookの活用
- シークレット管理
- マルチクラスターデプロイ
- ロールバック戦略
- モニタリング構成
- 運用時の注意事項
- 障害事例と復旧手順
- まとめ
- 参考資料

はじめに
GitOpsはGitをSingle Source of Truthとして使用し、インフラとアプリケーションの望ましい状態を宣言的に管理する運用パラダイムです。ArgoCDはKubernetes環境でGitOpsを実現する最も広く使用されているツールで、CNCF Graduatedプロジェクトとしてプロダクションでの検証が完了しています。
本記事ではArgoCDの核心機能であるApplicationSetを通じたマルチクラスター/環境デプロイ、Sync WavesとHookを通じたデプロイ順序制御、RBACとシークレット管理までプロダクション環境で必要な全設定を実践コードと共に解説します。
ArgoCD アーキテクチャ概要
ArgoCDは以下の主要コンポーネントで構成されています。
| コンポーネント | 役割 | 主な機能 |
|---|---|---|
| API Server | Web UI、CLI、CI/CD連携 | gRPC/REST API提供、RBAC処理 |
| Repo Server | Gitリポジトリ管理 | マニフェスト生成(Helm、Kustomize、Plain YAML) |
| Application Controller | コア調整ループ | クラスター状態監視、同期実行 |
| ApplicationSet Controller | 複数Application生成 | テンプレートベース自動Application作成 |
| Redis | キャッシュ | マニフェストキャッシング、クラスター状態キャッシング |
| Dex | 認証 | SSO、OIDC、LDAP等の外部認証連携 |
ArgoCD インストール
# Namespace作成とArgoCDインストール
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# またはHelmでインストール(プロダクション推奨)
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd \
--namespace argocd \
--create-namespace \
--set server.service.type=LoadBalancer \
--set configs.params."server\.insecure"=true \
--set controller.replicas=2 \
--set repoServer.replicas=2 \
--set redis-ha.enabled=true
# 初期adminパスワード確認
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath='{.data.password}' | base64 -d
Application リソース基本構成
Application スペック詳細
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-application
namespace: argocd
# Finalizer: Application削除時にクラスターリソースも一緒に削除
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: production
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: apps/my-app/overlays/production
# Kustomizeオプション
kustomize:
namePrefix: prod-
commonLabels:
env: production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Gitから削除されたリソースをクラスターからも削除
selfHeal: true # 手動変更時に自動復旧
allowEmpty: false # 空マニフェストのデプロイ防止
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
- ServerSideApply=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # HPA管理対象のため無視
Helm ソース設定
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prometheus-stack
namespace: argocd
spec:
project: monitoring
source:
repoURL: https://prometheus-community.github.io/helm-charts
chart: kube-prometheus-stack
targetRevision: 65.1.0
helm:
releaseName: prometheus
valuesObject:
grafana:
enabled: true
adminPassword: vault:secret/grafana#password
prometheus:
prometheusSpec:
retention: 30d
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp3
resources:
requests:
storage: 100Gi
destination:
server: https://kubernetes.default.svc
namespace: monitoring
AppProjectによるRBAC実装
プロジェクト定義
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
description: 'Production environment project'
# 許可されたソースリポジトリ
sourceRepos:
- 'https://github.com/myorg/k8s-manifests.git'
- 'https://github.com/myorg/helm-charts.git'
# 許可されたデプロイ先
destinations:
- namespace: 'production'
server: 'https://kubernetes.default.svc'
- namespace: 'production-*'
server: 'https://kubernetes.default.svc'
# 許可されたクラスターリソース
clusterResourceWhitelist:
- group: ''
kind: Namespace
- group: 'rbac.authorization.k8s.io'
kind: ClusterRole
- group: 'rbac.authorization.k8s.io'
kind: ClusterRoleBinding
# ブロックされたネームスペースリソース
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
- group: ''
kind: LimitRange
# RBACロール定義
roles:
- name: deployer
description: 'Can sync and manage applications'
policies:
- p, proj:production:deployer, applications, get, production/*, allow
- p, proj:production:deployer, applications, sync, production/*, allow
- p, proj:production:deployer, applications, action/*, production/*, allow
groups:
- platform-team
- name: viewer
description: 'Read-only access'
policies:
- p, proj:production:viewer, applications, get, production/*, allow
groups:
- dev-team
ApplicationSet ジェネレーター
Git Directoryジェネレーター
Gitリポジトリのディレクトリ構造に基づいてApplicationを自動生成します。
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: app-of-apps
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ['missingkey=error']
generators:
- git:
repoURL: https://github.com/myorg/k8s-manifests.git
revision: main
directories:
- path: 'apps/*/overlays/production'
- path: 'apps/deprecated-*'
exclude: true
template:
metadata:
name: '{{.path.basename}}'
namespace: argocd
labels:
app.kubernetes.io/managed-by: applicationset
spec:
project: production
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: '{{.path.path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
Clusterジェネレーター
登録されたクラスターに基づいてマルチクラスターデプロイを自動化します。
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: multi-cluster-apps
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ['missingkey=error']
generators:
- clusters:
selector:
matchLabels:
env: production
matchExpressions:
- key: region
operator: In
values:
- ap-northeast-2
- us-west-2
- eu-west-1
template:
metadata:
name: 'app-{{.name}}'
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: 'apps/my-app/overlays/{{.metadata.labels.env}}'
kustomize:
commonLabels:
cluster: '{{.name}}'
region: '{{.metadata.labels.region}}'
destination:
server: '{{.server}}'
namespace: production
Matrixジェネレーター(複合組み合わせ)
2つのジェネレーターを組み合わせて全組み合わせを生成します。
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: matrix-deployment
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ['missingkey=error']
generators:
- matrix:
generators:
# ジェネレーター1: クラスターリスト
- clusters:
selector:
matchLabels:
env: production
# ジェネレーター2: Gitディレクトリからアプリリスト
- git:
repoURL: https://github.com/myorg/k8s-manifests.git
revision: main
directories:
- path: 'apps/*'
template:
metadata:
name: '{{.path.basename}}-{{.name}}'
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: '{{.path.path}}/overlays/production'
destination:
server: '{{.server}}'
namespace: '{{.path.basename}}'
Listジェネレーター
静的な値リストに基づいてApplicationを生成します。
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: environment-apps
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ['missingkey=error']
generators:
- list:
elements:
- env: dev
cluster: https://dev-k8s.example.com
revision: develop
replicas: '1'
- env: staging
cluster: https://staging-k8s.example.com
revision: release/v2.5
replicas: '2'
- env: production
cluster: https://kubernetes.default.svc
revision: main
replicas: '3'
template:
metadata:
name: 'my-app-{{.env}}'
namespace: argocd
spec:
project: '{{.env}}'
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: '{{.revision}}'
path: 'apps/my-app/overlays/{{.env}}'
destination:
server: '{{.cluster}}'
namespace: 'my-app-{{.env}}'
Sync Wavesによるデプロイ順序制御
Sync Wave基本概念
Sync Waveはargocd.argoproj.io/sync-waveアノテーションで定義し、整数値を使用して低い値から順次デプロイします。デフォルト値は0です。
# Wave -2: NamespaceとRBAC(前提条件)
apiVersion: v1
kind: Namespace
metadata:
name: production
annotations:
argocd.argoproj.io/sync-wave: '-2'
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '-2'
---
# Wave -1: ConfigMapとSecret(設定)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '-1'
data:
APP_ENV: production
LOG_LEVEL: info
---
# Wave 0: コアアプリケーション(デフォルト)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '0'
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
serviceAccountName: app-service-account
containers:
- name: app
image: myorg/my-app:v2.5.0
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
---
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '0'
spec:
selector:
app: my-app
ports:
- port: 8080
targetPort: 8080
---
# Wave 1: 依存リソース(Ingress、HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '1'
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
---
# Wave 2: モニタリング
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app-monitor
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '2'
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: http
interval: 15s
Sync Hookの活用
PreSync Hook: デプロイ前のデータベースマイグレーション
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
namespace: production
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
argocd.argoproj.io/sync-wave: '-1'
spec:
backoffLimit: 3
template:
spec:
containers:
- name: migrate
image: myorg/db-migrator:v2.5.0
command: ['./migrate', 'up']
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
restartPolicy: Never
PostSync Hook: デプロイ後の検証
apiVersion: batch/v1
kind: Job
metadata:
name: smoke-test
namespace: production
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
backoffLimit: 1
template:
spec:
containers:
- name: smoke-test
image: myorg/smoke-tester:latest
command:
- /bin/sh
- -c
- |
echo "Running smoke tests..."
curl -sf http://my-app.production.svc:8080/healthz || exit 1
curl -sf http://my-app.production.svc:8080/api/v1/status || exit 1
echo "All smoke tests passed!"
restartPolicy: Never
SyncFail Hook: 同期失敗時の通知
apiVersion: batch/v1
kind: Job
metadata:
name: sync-fail-notification
namespace: production
annotations:
argocd.argoproj.io/hook: SyncFail
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
backoffLimit: 1
template:
spec:
containers:
- name: notify
image: curlimages/curl:latest
command:
- /bin/sh
- -c
- |
curl -X POST "$SLACK_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d '{"text":"ArgoCD Sync FAILED for my-app in production!"}'
env:
- name: SLACK_WEBHOOK_URL
valueFrom:
secretKeyRef:
name: slack-webhook
key: url
restartPolicy: Never
シークレット管理
Sealed Secrets連携
# Sealed Secretsコントローラーインストール
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets \
--namespace kube-system
# kubeseal CLIでシークレット暗号化
kubectl create secret generic db-credentials \
--namespace production \
--from-literal=url='postgresql://user:pass@db:5432/mydb' \
--dry-run=client -o yaml | \
kubeseal --format yaml > sealed-db-credentials.yaml
# Gitにコミット可能なSealedSecret
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '-2'
spec:
encryptedData:
url: AgA2X5N0Q...encrypted...base64==
template:
metadata:
name: db-credentials
namespace: production
type: Opaque
External Secrets Operator連携
# ExternalSecret: AWS Secrets Managerからシークレット同期
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
annotations:
argocd.argoproj.io/sync-wave: '-2'
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secretsmanager
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: url
remoteRef:
key: production/database
property: connection_url
- secretKey: password
remoteRef:
key: production/database
property: password
---
# ClusterSecretStore定義
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-secretsmanager
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-2
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
namespace: external-secrets
マルチクラスターデプロイ
クラスター登録
# 対象クラスター登録(kubeconfigコンテキストベース)
argocd cluster add staging-cluster \
--name staging \
--label env=staging \
--label region=ap-northeast-2
argocd cluster add production-cluster \
--name production \
--label env=production \
--label region=ap-northeast-2
# 登録済みクラスター確認
argocd cluster list
クラスター別設定分離
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: platform-services
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ['missingkey=error']
generators:
- matrix:
generators:
- clusters:
selector:
matchLabels:
env: production
- list:
elements:
- app: cert-manager
namespace: cert-manager
chart: cert-manager
repoURL: https://charts.jetstack.io
targetRevision: v1.16.0
- app: external-secrets
namespace: external-secrets
chart: external-secrets
repoURL: https://charts.external-secrets.io
targetRevision: 0.12.0
- app: metrics-server
namespace: kube-system
chart: metrics-server
repoURL: https://kubernetes-sigs.github.io/metrics-server
targetRevision: 3.12.0
template:
metadata:
name: '{{.app}}-{{.name}}'
namespace: argocd
spec:
project: platform
source:
repoURL: '{{.repoURL}}'
chart: '{{.chart}}'
targetRevision: '{{.targetRevision}}'
helm:
releaseName: '{{.app}}'
destination:
server: '{{.server}}'
namespace: '{{.namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
ロールバック戦略
自動ロールバック設定
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/myorg/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
retry:
limit: 3
backoff:
duration: 10s
factor: 2
maxDuration: 5m
CLIによる手動ロールバック
# デプロイ履歴確認
argocd app history my-app
# 特定リビジョンにロールバック
argocd app rollback my-app 5
# または特定Gitコミットに同期
argocd app sync my-app --revision abc123def
# 同期状態確認
argocd app get my-app
argocd app wait my-app --health
モニタリング構成
ArgoCD Prometheusメトリクス
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: argocd-metrics
namespace: argocd
spec:
selector:
matchLabels:
app.kubernetes.io/part-of: argocd
endpoints:
- port: metrics
interval: 30s
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: argocd-alerts
namespace: argocd
spec:
groups:
- name: argocd
rules:
- alert: ArgoCDAppOutOfSync
expr: |
argocd_app_info{sync_status="OutOfSync"} == 1
for: 10m
labels:
severity: warning
annotations:
summary: 'Application {{ "{{" }} $labels.name {{ "}}" }} is OutOfSync for more than 10 minutes'
- alert: ArgoCDAppDegraded
expr: |
argocd_app_info{health_status="Degraded"} == 1
for: 5m
labels:
severity: critical
annotations:
summary: 'Application {{ "{{" }} $labels.name {{ "}}" }} is Degraded'
- alert: ArgoCDSyncFailed
expr: |
increase(argocd_app_sync_total{phase="Failed"}[10m]) > 0
labels:
severity: critical
annotations:
summary: 'ArgoCD sync failed for {{ "{{" }} $labels.name {{ "}}" }}'
Slack通知設定
# argocd-notifications-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
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]
trigger.on-sync-succeeded: |
- when: app.status.operationState.phase in ['Succeeded']
oncePer: app.status.sync.revision
send: [app-sync-succeeded]
template.app-sync-failed: |
slack:
attachments: |
[{
"color": "#E96D76",
"title": "Sync Failed: {{.app.metadata.name}}",
"text": "Application {{.app.metadata.name}} sync failed.\nRevision: {{.app.status.sync.revision}}\nMessage: {{.app.status.operationState.message}}"
}]
template.app-health-degraded: |
slack:
attachments: |
[{
"color": "#f4c030",
"title": "Health Degraded: {{.app.metadata.name}}",
"text": "Application {{.app.metadata.name}} health is degraded."
}]
template.app-sync-succeeded: |
slack:
attachments: |
[{
"color": "#18BE52",
"title": "Sync Succeeded: {{.app.metadata.name}}",
"text": "Application {{.app.metadata.name}} synced successfully.\nRevision: {{.app.status.sync.revision}}"
}]
運用時の注意事項
1. ApplicationSetセキュリティ
ApplicationSetのprojectフィールドがテンプレート化されている場合、開発者が過剰な権限を持つプロジェクトにApplicationを作成できる可能性があります。常に管理者が制御するソースからのみプロジェクトフィールドを参照するよう設定してください。
2. 自動同期の注意点
automated.prune: trueはGitから削除されたリソースをクラスターから削除します。誤ってマニフェストを削除するとプロダクションリソースが即座に削除される可能性があるため、重要リソースにはargocd.argoproj.io/sync-options: Prune=falseアノテーションを追加することを推奨します。
3. Webhookセキュリティ
ArgoCDが公開的にアクセス可能な場合、必ずWebhookシークレットを設定してDDoS攻撃を防止してください。
4. Repo Serverリソース
大規模リポジトリやHelmチャートの処理時にRepo Serverのメモリ使用量が急増する可能性があります。適切なリソース制限とレプリカ数を設定してください。
5. 抽象化レイヤー制限
Application of Applicationsパターン使用時、3階層以上の抽象化を避けてください。4-5階層のネストはデバッグを極めて困難にします。
障害事例と復旧手順
事例1: Sync無限ループ
# 症状: ApplicationがSyncing状態を繰り返す
# 原因: ignoreDifferences未設定によるドリフト検知
# 診断
argocd app diff my-app
argocd app get my-app --show-operation
# 復旧: ignoreDifferencesを追加
kubectl patch application my-app -n argocd --type merge -p '{
"spec": {
"ignoreDifferences": [
{
"group": "apps",
"kind": "Deployment",
"jsonPointers": ["/spec/replicas"]
}
]
}
}'
事例2: Repo Server OOM
# 症状: ApplicationがUnknown状態、マニフェスト生成失敗
# 診断
kubectl logs -n argocd deploy/argocd-repo-server --previous
kubectl top pods -n argocd
# 復旧: リソース制限を増加
kubectl patch deployment argocd-repo-server -n argocd --type json -p '[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/resources/limits/memory",
"value": "4Gi"
}
]'
# Repo Server再起動
kubectl rollout restart deployment/argocd-repo-server -n argocd
事例3: シークレット同期失敗(External Secrets)
# 症状: ApplicationはHealthyだがPodがCrashLoopBackOff
# 原因: ExternalSecretがまだ同期されていない
# 診断
kubectl get externalsecret -n production
kubectl describe externalsecret db-credentials -n production
# 復旧: ExternalSecret強制同期
kubectl annotate externalsecret db-credentials \
-n production \
force-sync=$(date +%s) --overwrite
# またはSync Waveで順序を保証
# ExternalSecret: sync-wave=-2, Deployment: sync-wave=0
事例4: ApplicationSet意図しない削除
# 症状: ApplicationSet修正後に既存Applicationが削除される
# 原因: ジェネレーター設定エラーでマッチ項目が減少
# 予防: preserveResourcesOnDeletion設定
kubectl patch applicationset my-appset -n argocd --type merge -p '{
"spec": {
"syncPolicy": {
"preserveResourcesOnDeletion": true
}
}
}'
# 復旧: Git履歴から以前のApplicationSet設定を復元
git log --oneline -- applicationsets/my-appset.yaml
git checkout HEAD~1 -- applicationsets/my-appset.yaml
git commit -m "Revert ApplicationSet to restore applications"
git push
まとめ
ArgoCDはGitOpsの核心ツールとして、ApplicationSetを通じたマルチクラスター自動化、Sync WavesとHookを通じた精密なデプロイ順序制御、そしてRBACとシークレット管理を通じたセキュリティ強化まで、プロダクション環境で必要な全機能を提供します。
重要なのはGitをSingle Source of Truthとして維持しながら、適切な自動化レベルを設定することです。全環境に自動同期を適用するのではなく、開発/ステージングには自動同期を、プロダクションには手動同期を適用する段階的なアプローチを推奨します。モニタリングとアラートを必ず併せて構成し、同期失敗やヘルスチェック異常を迅速に検知して対応できるようにしてください。