GitOps
Gitリポジトリを唯一の信頼源(Single Source of Truth)とし、インフラとアプリケーションの宣言的な状態をプルベースで自動同期する運用モデル
GitOps
Gitリポジトリを唯一の信頼源(Single Source of Truth)とし、インフラとアプリケーションの宣言的な状態をプルベースで自動同期する運用モデル
この章で学ぶこと
- GitOpsの4原則とプッシュ型/プル型デプロイの違いを理解する
- ArgoCD、Fluxの仕組みと基本的な設定方法を習得する
- イミュータブルインフラストラクチャとGitOpsの関係を把握する
- GitOpsにおけるシークレット管理とマルチクラスタ運用を実践できる
- GitOpsのトラブルシューティングと運用ベストプラクティスを理解する
前提知識
このガイドを読む前に、以下の知識があると理解が深まります:
- 基本的なプログラミングの知識
- 関連する基礎概念の理解
- Infrastructure as Code (IaC) の内容を理解していること
1. GitOps とは
1.1 GitOps の4原則
GitOps 4原則 (OpenGitOps):
1. 宣言的 (Declarative)
システムのあるべき状態をコードで宣言する
例: Kubernetes マニフェスト、Helm チャート、Kustomize
2. バージョン管理・イミュータブル (Versioned and Immutable)
あるべき状態は Git で管理し、変更履歴を保持する
例: 全ての変更が Git コミットとして記録される
3. 自動プル (Pulled Automatically)
承認された変更はシステムに自動的に適用される
例: ArgoCD/Flux が Git の変更を検知して自動デプロイ
4. 継続的リコンサイル (Continuously Reconciled)
実際の状態とあるべき状態の差分を検知し、自動修復する
例: 手動変更(kubectl)が自動で元に戻される
1.2 GitOps の歴史と背景
GitOpsは2017年にWeaveWorksのAlexis Richardsonが提唱した概念である。Kubernetesの宣言的APIとGitの不変な変更履歴を組み合わせることで、信頼性の高いデプロイフローを実現する。
GitOps の進化:
2014年 Kubernetes の登場 → 宣言的インフラ管理の基盤
2015年 Helm の登場 → パッケージ管理の標準化
2017年 Weaveworks が "GitOps" を提唱
2018年 Flux v1 リリース (初のGitOpsツール)
2019年 Argo CD v1.0 リリース
2020年 CNCF に Flux/ArgoCD が Sandbox プロジェクトとして参加
2021年 Flux v2 リリース (完全リアーキテクチャ)
2022年 OpenGitOps プロジェクト発足 (原則の標準化)
2023年 Argo CD が CNCF Graduated プロジェクトに
2024年 Flux が CNCF Graduated プロジェクトに
1.3 プッシュ型 vs プル型デプロイ
プッシュ型 (従来の CI/CD):| Git | ──→ | CI/CD | ──→ | Kubernetes |
|---|---|---|---|---|
| Server | Cluster |
│
CI がクラスタに
直接デプロイ
(push)
問題:
- CI に本番環境への認証情報が必要
- CI サーバーが SPOF (単一障害点)
- ドリフト(実態の乖離)を検知できない
- CI の設定が複雑になりやすい
- 監査証跡がCIログに依存
プル型 (GitOps):| Git | ←── 監視 ←────── | Agent |
|---|---|---|
| (ArgoCD) |
└───────────┘
│
差分を検知して
自動適用 (pull)
利点:
- クラスタ外に認証情報を露出しない
- エージェントが常に差分を監視・修復
- Git の履歴 = デプロイの履歴
- CI とデプロイの責務が明確に分離
- 監査証跡が Git コミットに残る
1.4 GitOps vs 従来の CI/CD
| 項目 | 従来の CI/CD | GitOps |
|---|---|---|
| デプロイ方式 | プッシュ型 | プル型 |
| 信頼源 | CI サーバー | Git リポジトリ |
| ドリフト検知 | なし | 継続的リコンサイル |
| ロールバック | 再デプロイ | Git revert |
| 認証情報 | CI に保存 | クラスタ内に閉じる |
| 監査証跡 | CI ログ | Git コミット履歴 |
| 再現性 | CI 設定に依存 | Git の状態から完全再現 |
| 障害復旧 | 手順書に依存 | Git から自動復元 |
2. ArgoCD
2.1 ArgoCD の仕組み
| Kubernetes Cluster | ||||
|---|---|---|---|---|
| ┌─────────────┐ ┌──────────────────┐ | ||||
| ArgoCD | Application | |||
| Controller | ──→ | Resources | ||
| (Deployment, | ||||
| ・Git監視 | Service, etc.) | |||
| ・差分検知 | └──────────────────┘ | |||
| ・自動同期 | ||||
| └──────┬──────┘ | ||||
| pull (3分ごと) |
│
↓| Git Repository |
|---|
| (manifests) |
| ├── base/ |
| ├── overlays/ |
| └── apps/ |
2.2 ArgoCD のインストールとセットアップ
# ArgoCD のインストール (Kubernetes クラスタが必要)
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# ArgoCD CLI のインストール
brew install argocd # macOS
# または
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 admin initial-password -n argocd
# ログイン
argocd login localhost:8080
# パスワード変更
argocd account update-password# ArgoCD を Helm でインストール (推奨: 本番環境向け)
# values.yaml
apiVersion: v1
kind: Namespace
metadata:
name: argocd
---
# Helm でのインストール
# helm repo add argo https://argoproj.github.io/argo-helm
# helm install argocd argo/argo-cd -n argocd -f values.yaml
# values.yaml
server:
replicas: 2
ingress:
enabled: true
ingressClassName: nginx
hosts:
- argocd.example.com
tls:
- secretName: argocd-tls
hosts:
- argocd.example.com
controller:
replicas: 1
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
repoServer:
replicas: 2
resources:
requests:
cpu: 250m
memory: 256Mi
redis:
resources:
requests:
cpu: 100m
memory: 128Mi
configs:
params:
server.insecure: false
rbac:
policy.csv: |
g, dev-team, role:readonly
g, ops-team, role:admin2.3 ArgoCD Application 定義
# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io # アプリ削除時にリソースも削除
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: overlays/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 # 他リソース同期後に削除
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# ヘルスチェック設定
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # HPA と競合防止2.4 ApplicationSet (マルチ環境・マルチクラスタ)
# ApplicationSet: 複数環境に一括デプロイ
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: my-app
namespace: argocd
spec:
generators:
# リスト型: 明示的に環境を定義
- list:
elements:
- cluster: dev
url: https://dev-cluster.example.com
revision: develop
replicas: "1"
- cluster: staging
url: https://staging-cluster.example.com
revision: main
replicas: "2"
- cluster: production
url: https://prod-cluster.example.com
revision: main
replicas: "3"
template:
metadata:
name: 'my-app-{{cluster}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: '{{revision}}'
path: 'overlays/{{cluster}}'
destination:
server: '{{url}}'
namespace: 'my-app-{{cluster}}'
syncPolicy:
automated:
prune: true
selfHeal: true# Git Generator: ディレクトリ構造から自動生成
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: cluster-apps
namespace: argocd
spec:
generators:
- git:
repoURL: https://github.com/myorg/k8s-manifests.git
revision: main
directories:
- path: 'apps/*'
- path: 'apps/excluded-app'
exclude: true
template:
metadata:
name: '{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'2.5 Kustomize を使ったマニフェスト管理
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:latest
ports:
- containerPort: 3000
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
---
# base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 3000
---
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
managed-by: argocd
---
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../base
patchesStrategicMerge:
- deployment-patch.yaml
- hpa.yaml
---
# overlays/production/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
template:
spec:
containers:
- name: app
image: my-app:v1.2.3 # 本番用のタグを固定
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
---
# overlays/production/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 702.6 Helm + ArgoCD
# Helm チャートを ArgoCD で管理
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nginx-ingress
namespace: argocd
spec:
project: infrastructure
source:
repoURL: https://kubernetes.github.io/ingress-nginx
chart: ingress-nginx
targetRevision: 4.8.3
helm:
releaseName: nginx-ingress
values: |
controller:
replicaCount: 2
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
resources:
requests:
cpu: 200m
memory: 256Mi
metrics:
enabled: true
destination:
server: https://kubernetes.default.svc
namespace: ingress-nginx
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true3. Flux
3.1 Flux の構成
# flux-system/gotk-components.yaml (Flux Bootstrap で自動生成)
# Flux は以下のコントローラーで構成される:
# 1. Source Controller: Git リポジトリを監視
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m
url: https://github.com/myorg/k8s-manifests
ref:
branch: main
secretRef:
name: git-credentials # 認証情報
# 2. Kustomize Controller: マニフェストを適用
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
path: ./overlays/production
prune: true
sourceRef:
kind: GitRepository
name: my-app
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: my-app
namespace: production
timeout: 3m
retryInterval: 2m3.2 Flux Bootstrap
# Flux のブートストラップ (GitHub)
flux bootstrap github \
--owner=myorg \
--repository=k8s-manifests \
--branch=main \
--path=clusters/production \
--personal
# ブートストラップ後のディレクトリ構造
k8s-manifests/
├── clusters/
│ └── production/
│ └── flux-system/
│ ├── gotk-components.yaml # Flux コンポーネント
│ ├── gotk-sync.yaml # 自己同期設定
│ └── kustomization.yaml
├── apps/
│ └── my-app/
│ ├── base/
│ └── overlays/
└── infrastructure/
├── cert-manager/
└── ingress-nginx/3.3 Flux のイメージ自動更新
# イメージリポジトリの監視
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: my-app
namespace: flux-system
spec:
image: ghcr.io/myorg/my-app
interval: 5m
secretRef:
name: ghcr-credentials
---
# イメージポリシー: セマンティックバージョニングで最新を選択
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: my-app
namespace: flux-system
spec:
imageRepositoryRef:
name: my-app
policy:
semver:
range: ">=1.0.0"
---
# 自動更新設定: Git にコミットを自動作成
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
sourceRef:
kind: GitRepository
name: my-app
git:
checkout:
ref:
branch: main
commit:
author:
name: flux-bot
email: flux@myorg.com
messageTemplate: 'chore: update {{.AutomationObject}} images'
push:
branch: main
update:
path: ./overlays/production
strategy: Setters# マニフェストにマーカーを設定 (イメージ自動更新用)
# overlays/production/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: ghcr.io/myorg/my-app:v1.2.3 # {"$imagepolicy": "flux-system:my-app"}3.4 Flux の通知設定
# Slack 通知
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: slack
namespace: flux-system
spec:
type: slack
channel: deployments
secretRef:
name: slack-webhook
---
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: deployment-alerts
namespace: flux-system
spec:
providerRef:
name: slack
eventSeverity: info
eventSources:
- kind: Kustomization
name: '*'
- kind: HelmRelease
name: '*'
exclusionList:
- ".*upgrade.*" # アップグレード通知を除外4. ArgoCD vs Flux 比較
| 項目 | ArgoCD | Flux |
|---|---|---|
| UI | リッチなWeb UI内蔵 | 別途 Weave GitOps UI |
| マルチクラスタ | ApplicationSet で対応 | Kustomization のリモート参照 |
| Helm 対応 | ネイティブ対応 | HelmRelease CRD |
| SSO/RBAC | 内蔵 (OIDC, LDAP) | Kubernetes RBAC に委任 |
| イメージ自動更新 | Argo Image Updater | Image Automation Controller |
| アーキテクチャ | 中央集権型 (Server + UI) | 分散型 (CRD ベース) |
| 学習コスト | 低 (UIが直感的) | 中 (CRDの理解が必要) |
| 適用場面 | チームがUIを重視 | 軽量・CRDベースを好む |
| リソース消費 | 中〜大 (UI+Server) | 小〜中 (Controller のみ) |
| CNCF ステータス | Graduated | Graduated |
| Webhook 対応 | あり (即座同期トリガー) | あり (Receiver Controller) |
GitOps ツールのデプロイフロー比較
| ステップ | ArgoCD | Flux |
|---|---|---|
| リポジトリ監視 | Application CRD | GitRepository CRD |
| 差分検知 | 3分間隔 (デフォルト) | 1分間隔 (設定可能) |
| マニフェスト生成 | Kustomize/Helm/jsonnet | Kustomize/Helm |
| 同期 | Sync (自動/手動) | Reconcile (自動) |
| ヘルスチェック | 内蔵 (多数のリソース対応) | healthChecks フィールド |
| ロールバック | UI からワンクリック | Git revert → 自動同期 |
4.1 選択ガイド
GitOps ツール選定:
チームが Kubernetes の CRD に慣れている?
├── Yes → Flux を検討
│ ├── 軽量で運用コストを抑えたい → Flux
│ ├── イメージ自動更新が必要 → Flux (Image Automation)
│ └── 複数のソースからマニフェストを取得 → Flux
└── No → ArgoCD を検討
├── Web UI でデプロイ状況を可視化したい → ArgoCD
├── マルチクラスタを一元管理したい → ArgoCD (ApplicationSet)
├── SSO/RBAC が必要 → ArgoCD
└── 非技術者にもデプロイ状況を共有したい → ArgoCD
5. イミュータブルインフラストラクチャ
5.1 ミュータブル vs イミュータブル
ミュータブル (従来型):
サーバーに SSH → パッチ適用 → 設定変更 → 再起動
問題: 設定のドリフト、スノーフレークサーバー
Server v1 → patch → Server v1.1 → patch → Server v1.2
(同じサーバーを変更し続ける)
イミュータブル (GitOps):
新しいイメージをビルド → 古いコンテナを新しいコンテナに置換
利点: 再現性、ロールバック容易、ドリフトなし
Container v1 → 破棄
Container v2 → 新規作成
Container v3 → 新規作成
(変更するのではなく、置き換える)
5.2 GitOps + イミュータブルインフラの完全フロー
GitOps + イミュータブルインフラの流れ:| コード変更 | → | CI: ビルド | → | イメージPush | → | マニフェスト |
|---|---|---|---|---|---|---|
| PR merge | テスト | ghcr.io/... | のタグ更新 |
│
↓| Git commit |
|---|
| (自動/手動) |
│
↓| ArgoCD/Flux |
|---|
| が同期 |
│
↓| Rolling Update |
|---|
| 旧Pod → 新Pod |
5.3 イメージタグ戦略
推奨: タグの不変性を保証する
✗ 悪い例: latest タグを上書き
image: my-app:latest # どのバージョンか不明、ロールバック不可
✗ 微妙な例: ブランチ名タグ
image: my-app:main # 上書きされる可能性
○ 良い例: Git SHA タグ
image: my-app:abc1234 # 不変、追跡可能
◎ 最良: セマンティックバージョン + SHA
image: my-app:v1.2.3-abc1234 # バージョン + 追跡性
タグ付けの CI 設定:
tags:
- ghcr.io/myorg/my-app:${{ github.sha }}
- ghcr.io/myorg/my-app:v${{ steps.version.outputs.value }}
6. GitOps のリポジトリ戦略
6.1 モノレポ vs 分離レポ
# 戦略1: モノレポ (アプリ + マニフェスト同一リポジトリ)
my-app/
├── src/ # アプリケーションコード
├── Dockerfile
├── k8s/ # Kubernetes マニフェスト
│ ├── base/
│ └── overlays/
└── .github/workflows/ # CI/CD
# メリット: シンプル、アプリとインフラの変更を一緒にレビュー
# デメリット: CI が頻繁にマニフェスト変更で発火、権限分離が困難
# 戦略2: 分離レポ (推奨)
my-app/ # アプリリポジトリ
├── src/
├── Dockerfile
└── .github/workflows/
k8s-manifests/ # マニフェストリポジトリ
├── apps/
│ ├── my-app/
│ │ ├── base/
│ │ └── overlays/
│ └── my-api/
├── infrastructure/
│ ├── cert-manager/
│ └── ingress-nginx/
└── clusters/
├── dev/
├── staging/
└── production/
# メリット: 関心の分離、アクセス制御、CI/CD の独立
# デメリット: リポジトリ間の連携が必要6.2 マニフェストリポジトリの推奨構成
k8s-manifests/
├── apps/ # アプリケーション
│ ├── frontend/
│ │ ├── base/
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ ├── ingress.yaml
│ │ │ └── kustomization.yaml
│ │ └── overlays/
│ │ ├── dev/
│ │ │ ├── kustomization.yaml
│ │ │ └── patch.yaml
│ │ ├── staging/
│ │ └── production/
│ ├── backend/
│ │ ├── base/
│ │ └── overlays/
│ └── worker/
│ ├── base/
│ └── overlays/
├── infrastructure/ # インフラコンポーネント
│ ├── cert-manager/
│ │ ├── namespace.yaml
│ │ ├── helmrelease.yaml # Helm リリース定義
│ │ └── kustomization.yaml
│ ├── ingress-nginx/
│ ├── external-secrets/
│ ├── prometheus-stack/
│ └── kustomization.yaml
├── clusters/ # クラスタ別設定
│ ├── dev/
│ │ ├── apps.yaml # どのアプリをデプロイするか
│ │ └── infrastructure.yaml # どのインフラをデプロイするか
│ ├── staging/
│ └── production/
└── README.md
7. シークレット管理
GitOps では全ての状態を Git に保存するが、シークレット(パスワード、APIキー等)をそのままGitにコミットすることはセキュリティ上許容されない。以下の3つのアプローチが主流である。
7.1 Sealed Secrets
# Sealed Secrets: クラスタの公開鍵で暗号化して Git に保存
# 暗号化されたシークレットは Git にコミット可能
# 1. kubeseal でシークレットを暗号化
# kubeseal < secret.yaml > sealed-secret.yaml
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
namespace: production
spec:
encryptedData:
password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq... # 暗号化済み
username: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq... # 暗号化済み
template:
metadata:
name: db-credentials
namespace: production
type: Opaque7.2 External Secrets Operator
# External Secrets Operator: 外部シークレットストアから取得
# AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager 等と連携
# ClusterSecretStore の定義
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-secrets-manager
spec:
provider:
aws:
service: SecretsManager
region: ap-northeast-1
auth:
jwt:
serviceAccountRef:
name: external-secrets
namespace: external-secrets
---
# ExternalSecret: AWS Secrets Manager からシークレットを取得
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: prod/db/password
- secretKey: username
remoteRef:
key: prod/db/username7.3 SOPS (Secrets OPerationS)
# SOPS: Mozilla が開発した暗号化ツール
# AGE, PGP, AWS KMS, GCP KMS, Azure Key Vault で暗号化
# .sops.yaml (暗号化ルール)
creation_rules:
- path_regex: .*secrets.*\.yaml$
age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- path_regex: .*prod.*secrets.*\.yaml$
kms: arn:aws:kms:ap-northeast-1:123456789012:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# 暗号化されたファイル例
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
password: ENC[AES256_GCM,data:xxxxx,iv:xxxxx,tag:xxxxx,type:str]
username: ENC[AES256_GCM,data:xxxxx,iv:xxxxx,tag:xxxxx,type:str]
sops:
kms: []
age:
- recipient: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
...
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-01-15T10:00:00Z"
version: 3.8.1# Flux での SOPS 統合
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
decryption:
provider: sops
secretRef:
name: sops-age # AGE キーを含む Secret
interval: 5m
path: ./overlays/production
prune: true
sourceRef:
kind: GitRepository
name: my-app7.4 シークレット管理の比較
| 項目 | Sealed Secrets | External Secrets | SOPS |
|---|---|---|---|
| 暗号化場所 | クラスタ内 | 外部サービス | ローカル/CI |
| 復号場所 | クラスタ内 | クラスタ内 | クラスタ内 |
| Git に保存 | 暗号化済みOK | 参照のみ | 暗号化済みOK |
| ローテーション | 手動 | 外部サービスで自動 | 手動 |
| 複数クラスタ | クラスタごとに再暗号化 | 共通の外部ストア | 共通キーで暗号化 |
| 依存関係 | クラスタ公開鍵 | 外部サービス | 暗号化キー |
| 推奨場面 | シンプルな構成 | エンタープライズ | マルチ環境 |
8. CI パイプラインとGitOpsの連携
8.1 典型的な連携フロー
# アプリリポジトリの CI (GitOps 連携)
name: CI + GitOps Deploy
on:
push:
branches: [main]
jobs:
ci:
runs-on: ubuntu-latest
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test && npm run build
- name: Build and push Docker image
id: meta
uses: docker/build-push-action@v5
with:
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ github.sha }}
ghcr.io/${{ github.repository }}:latest
update-manifests:
needs: ci
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: myorg/k8s-manifests
token: ${{ secrets.MANIFEST_REPO_TOKEN }}
ref: main
- name: Update image tag in manifests
run: |
cd overlays/production
kustomize edit set image \
my-app=ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Commit and push
run: |
git config user.name "ci-bot"
git config user.email "ci@example.com"
git add .
git commit -m "chore: update my-app image to ${{ github.sha }}"
git push
# この後、ArgoCD/Flux が変更を検知して自動デプロイ8.2 PR ベースのデプロイフロー
# 本番デプロイを PR 経由で行う (より安全なアプローチ)
name: Create Deploy PR
on:
push:
branches: [main]
jobs:
create-deploy-pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: myorg/k8s-manifests
token: ${{ secrets.MANIFEST_REPO_TOKEN }}
- name: Create feature branch
run: |
BRANCH="deploy/my-app-${{ github.sha }}"
git checkout -b $BRANCH
- name: Update image tag
run: |
cd overlays/production
kustomize edit set image \
my-app=ghcr.io/myorg/my-app:${{ github.sha }}
- name: Create PR
run: |
git add .
git commit -m "chore: deploy my-app ${{ github.sha }}"
git push origin $BRANCH
gh pr create \
--title "Deploy my-app ${{ github.sha }}" \
--body "Auto-generated deploy PR for my-app" \
--base main
env:
GH_TOKEN: ${{ secrets.MANIFEST_REPO_TOKEN }}9. 運用とトラブルシューティング
9.1 ArgoCD のトラブルシューティング
# 同期状態の確認
argocd app get my-app
# 同期の詳細ログ
argocd app sync my-app --dry-run
argocd app sync my-app --force
# 差分の確認
argocd app diff my-app
# リソースの状態確認
argocd app resources my-app
# 同期履歴
argocd app history my-app
# ロールバック
argocd app rollback my-app <HISTORY_ID>
# Webhook の手動トリガー
argocd app sync my-app --revision HEAD9.2 よくある問題と対処法
問題1: OutOfSync が解消しない
原因: ignoreDifferences の設定漏れ
対処:
- HPA が replicas を変更 → ignoreDifferences に /spec/replicas を追加
- Webhook が Last Applied を変更 → metadata.annotations を除外
- Operator が Status を更新 → status フィールドを無視
問題2: Sync Failed - ComparisonError
原因: マニフェストの構文エラー、CRD 未インストール
対処:
- kustomize build でローカル検証
- CRD が先にインストールされているか確認
- sync-wave アノテーションで順序制御
問題3: ImagePullBackOff
原因: イメージタグの不一致、レジストリ認証エラー
対処:
- イメージタグが正しいか確認
- imagePullSecrets の設定確認
- ECR/GHCR のトークン有効期限確認
9.3 Sync Wave (同期順序の制御)
# CRD を先にインストールし、次にアプリケーションを同期
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager
annotations:
argocd.argoproj.io/sync-wave: "-2" # 最初に作成
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: cert-manager
annotations:
argocd.argoproj.io/sync-wave: "-1" # 名前空間の後
spec:
source:
repoURL: https://charts.jetstack.io
chart: cert-manager
targetRevision: v1.13.3
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
annotations:
argocd.argoproj.io/sync-wave: "0" # cert-manager の後
spec:
source:
repoURL: https://github.com/myorg/k8s-manifests.git
path: overlays/production10. アンチパターン
アンチパターン1: Git を経由しない手動変更
問題:
kubectl apply -f ... で直接クラスタに変更を適用する
Git の状態: replicas: 3
クラスタの状態: replicas: 5 (kubectl scale で手動変更)
→ ArgoCD が差分を検知し、replicas: 3 に戻してしまう
→ または selfHeal が無効の場合、ドリフトが放置される
改善:
- selfHeal: true を有効にする
- kubectl での直接変更を禁止する RBAC 設定
- 全ての変更は Git PR 経由で行うルールを徹底
- 緊急時の手順書にも「PR 経由」を明記
- kubectl の write 権限を限定的な緊急用 ServiceAccount のみに付与
アンチパターン2: シークレットを Git にコミット
問題:
データベースパスワードや API キーを平文で Git にコミット
→ セキュリティ事故
改善手段:
1. Sealed Secrets: クラスタの公開鍵で暗号化して Git に保存
2. External Secrets Operator: AWS Secrets Manager 等から取得
3. SOPS (Mozilla): 暗号化して Git に保存、復号は CI/CD で
4. Vault Agent: HashiCorp Vault からランタイムで取得
アンチパターン3: latest タグの使用
問題:
image: my-app:latest で GitOps を運用
→ どのバージョンがデプロイされているか不明
→ ロールバック不可
→ ArgoCD が差分を検知できない(タグは同じだが中身が違う)
改善:
- 必ず不変のタグ(Git SHA、セマンティックバージョン)を使用
- imagePullPolicy: Always は使わない
- イメージタグの更新は Git コミットで管理
アンチパターン4: 全環境を1つの Application で管理
問題:
dev/staging/production を1つの ArgoCD Application で管理
→ 環境ごとの独立したデプロイができない
→ dev の変更が production に影響
改善:
- 環境ごとに別々の Application を定義
- ApplicationSet で環境パラメータを変数化
- overlays で環境ごとの差分を管理
実践演習
演習1: 基本的な実装
以下の要件を満たすコードを実装してください。
要件:
- 入力データの検証を行うこと
- エラーハンドリングを適切に実装すること
- テストコードも作成すること
# 演習1: 基本実装のテンプレート
class Exercise1:
"""基本的な実装パターンの演習"""
def __init__(self):
self.data = []
def validate_input(self, value):
"""入力値の検証"""
if value is None:
raise ValueError("入力値がNoneです")
return True
def process(self, value):
"""データ処理のメインロジック"""
self.validate_input(value)
self.data.append(value)
return self.data
def get_results(self):
"""処理結果の取得"""
return {
'count': len(self.data),
'data': self.data
}
# テスト
def test_exercise1():
ex = Exercise1()
assert ex.process(1) == [1]
assert ex.process(2) == [1, 2]
assert ex.get_results()['count'] == 2
try:
ex.process(None)
assert False, "例外が発生するべき"
except ValueError:
pass
print("全テスト合格!")
test_exercise1()演習2: 応用パターン
基本実装を拡張して、以下の機能を追加してください。
# 演習2: 応用パターン
from typing import List, Dict, Optional
from datetime import datetime
class AdvancedExercise:
"""応用パターンの演習"""
def __init__(self, max_size: int = 100):
self._items: List[Dict] = []
self._max_size = max_size
self._created_at = datetime.now()
def add(self, key: str, value: any) -> bool:
"""アイテムの追加(サイズ制限付き)"""
if len(self._items) >= self._max_size:
return False
self._items.append({
'key': key,
'value': value,
'timestamp': datetime.now().isoformat()
})
return True
def find(self, key: str) -> Optional[Dict]:
"""キーによる検索"""
for item in reversed(self._items):
if item['key'] == key:
return item
return None
def remove(self, key: str) -> bool:
"""キーによる削除"""
for i, item in enumerate(self._items):
if item['key'] == key:
self._items.pop(i)
return True
return False
def stats(self) -> Dict:
"""統計情報"""
return {
'total_items': len(self._items),
'max_size': self._max_size,
'usage_percent': len(self._items) / self._max_size * 100,
'uptime': str(datetime.now() - self._created_at)
}
# テスト
def test_advanced():
ex = AdvancedExercise(max_size=3)
assert ex.add("a", 1) == True
assert ex.add("b", 2) == True
assert ex.add("c", 3) == True
assert ex.add("d", 4) == False # サイズ制限
assert ex.find("b")['value'] == 2
assert ex.remove("b") == True
assert ex.find("b") is None
stats = ex.stats()
assert stats['total_items'] == 2
print("応用テスト全合格!")
test_advanced()演習3: パフォーマンス最適化
以下のコードのパフォーマンスを改善してください。
# 演習3: パフォーマンス最適化
import time
from functools import lru_cache
# 最適化前(O(n^2))
def slow_search(data: list, target: int) -> int:
"""非効率な検索"""
for i in range(len(data)):
for j in range(i + 1, len(data)):
if data[i] + data[j] == target:
return (i, j)
return (-1, -1)
# 最適化後(O(n))
def fast_search(data: list, target: int) -> tuple:
"""ハッシュマップを使った効率的な検索"""
seen = {}
for i, num in enumerate(data):
complement = target - num
if complement in seen:
return (seen[complement], i)
seen[num] = i
return (-1, -1)
# ベンチマーク
def benchmark():
import random
data = list(range(5000))
random.shuffle(data)
target = data[100] + data[4000]
start = time.time()
result1 = slow_search(data, target)
slow_time = time.time() - start
start = time.time()
result2 = fast_search(data, target)
fast_time = time.time() - start
print(f"非効率版: {slow_time:.4f}秒")
print(f"効率版: {fast_time:.6f}秒")
print(f"高速化率: {slow_time/fast_time:.0f}倍")
benchmark()ポイント:
- アルゴリズムの計算量を意識する
- 適切なデータ構造を選択する
- ベンチマークで効果を測定する
トラブルシューティング
よくあるエラーと解決策
| エラー | 原因 | 解決策 |
|---|---|---|
| 初期化エラー | 設定ファイルの不備 | 設定ファイルのパスと形式を確認 |
| タイムアウト | ネットワーク遅延/リソース不足 | タイムアウト値の調整、リトライ処理の追加 |
| メモリ不足 | データ量の増大 | バッチ処理の導入、ページネーションの実装 |
| 権限エラー | アクセス権限の不足 | 実行ユーザーの権限確認、設定の見直し |
| データ不整合 | 並行処理の競合 | ロック機構の導入、トランザクション管理 |
デバッグの手順
- エラーメッセージの確認: スタックトレースを読み、発生箇所を特定する
- 再現手順の確立: 最小限のコードでエラーを再現する
- 仮説の立案: 考えられる原因をリストアップする
- 段階的な検証: ログ出力やデバッガを使って仮説を検証する
- 修正と回帰テスト: 修正後、関連する箇所のテストも実行する
# デバッグ用ユーティリティ
import logging
import traceback
from functools import wraps
# ロガーの設定
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s'
)
logger = logging.getLogger(__name__)
def debug_decorator(func):
"""関数の入出力をログ出力するデコレータ"""
@wraps(func)
def wrapper(*args, **kwargs):
logger.debug(f"呼び出し: {func.__name__}(args={args}, kwargs={kwargs})")
try:
result = func(*args, **kwargs)
logger.debug(f"戻り値: {func.__name__} -> {result}")
return result
except Exception as e:
logger.error(f"例外発生: {func.__name__}: {e}")
logger.error(traceback.format_exc())
raise
return wrapper
@debug_decorator
def process_data(items):
"""データ処理(デバッグ対象)"""
if not items:
raise ValueError("空のデータ")
return [item * 2 for item in items]パフォーマンス問題の診断
パフォーマンス問題が発生した場合の診断手順:
- ボトルネックの特定: プロファイリングツールで計測
- メモリ使用量の確認: メモリリークの有無をチェック
- I/O待ちの確認: ディスクやネットワークI/Oの状況を確認
- 同時接続数の確認: コネクションプールの状態を確認
| 問題の種類 | 診断ツール | 対策 |
|---|---|---|
| CPU負荷 | cProfile, py-spy | アルゴリズム改善、並列化 |
| メモリリーク | tracemalloc, objgraph | 参照の適切な解放 |
| I/Oボトルネック | strace, iostat | 非同期I/O、キャッシュ |
| DB遅延 | EXPLAIN, slow query log | インデックス、クエリ最適化 |
設計判断ガイド
選択基準マトリクス
技術選択を行う際の判断基準を以下にまとめます。
| 判断基準 | 重視する場合 | 妥協できる場合 |
|---|---|---|
| パフォーマンス | リアルタイム処理、大規模データ | 管理画面、バッチ処理 |
| 保守性 | 長期運用、チーム開発 | プロトタイプ、短期プロジェクト |
| スケーラビリティ | 成長が見込まれるサービス | 社内ツール、固定ユーザー |
| セキュリティ | 個人情報、金融データ | 公開データ、社内利用 |
| 開発速度 | MVP、市場投入スピード | 品質重視、ミッションクリティカル |
アーキテクチャパターンの選択
| アーキテクチャ選択フロー |
|---|
| ① チーム規模は? |
| ├─ 小規模(1-5人)→ モノリス |
| └─ 大規模(10人+)→ ②へ |
| ② デプロイ頻度は? |
| ├─ 週1回以下 → モノリス + モジュール分割 |
| └─ 毎日/複数回 → ③へ |
| ③ チーム間の独立性は? |
| ├─ 高い → マイクロサービス |
| └─ 中程度 → モジュラーモノリス |
トレードオフの分析
技術的な判断には必ずトレードオフが伴います。以下の観点で分析を行いましょう:
1. 短期 vs 長期のコスト
- 短期的に速い方法が長期的には技術的負債になることがある
- 逆に、過剰な設計は短期的なコストが高く、プロジェクトの遅延を招く
2. 一貫性 vs 柔軟性
- 統一された技術スタックは学習コストが低い
- 多様な技術の採用は適材適所が可能だが、運用コストが増加
3. 抽象化のレベル
- 高い抽象化は再利用性が高いが、デバッグが困難になる場合がある
- 低い抽象化は直感的だが、コードの重複が発生しやすい
# 設計判断の記録テンプレート
class ArchitectureDecisionRecord:
"""ADR (Architecture Decision Record) の作成"""
def __init__(self, title: str):
self.title = title
self.context = ""
self.decision = ""
self.consequences = []
self.alternatives = []
def set_context(self, context: str):
"""背景と課題の記述"""
self.context = context
return self
def set_decision(self, decision: str):
"""決定内容の記述"""
self.decision = decision
return self
def add_consequence(self, consequence: str, positive: bool = True):
"""結果の追加"""
self.consequences.append({
'description': consequence,
'type': 'positive' if positive else 'negative'
})
return self
def add_alternative(self, name: str, reason_rejected: str):
"""却下した代替案の追加"""
self.alternatives.append({
'name': name,
'reason_rejected': reason_rejected
})
return self
def to_markdown(self) -> str:
"""Markdown形式で出力"""
md = f"# ADR: {self.title}\n\n"
md += f"## 背景\n{self.context}\n\n"
md += f"## 決定\n{self.decision}\n\n"
md += "## 結果\n"
for c in self.consequences:
icon = "✅" if c['type'] == 'positive' else "⚠️"
md += f"- {icon} {c['description']}\n"
md += "\n## 却下した代替案\n"
for a in self.alternatives:
md += f"- **{a['name']}**: {a['reason_rejected']}\n"
return md実務での適用シナリオ
シナリオ1: スタートアップでのMVP開発
状況: 限られたリソースで素早くプロダクトをリリースする必要がある
アプローチ:
- シンプルなアーキテクチャを選択
- 必要最小限の機能に集中
- 自動テストはクリティカルパスのみ
- モニタリングは早期から導入
学んだ教訓:
- 完璧を求めすぎない(YAGNI原則)
- ユーザーフィードバックを早期に取得
- 技術的負債は意識的に管理する
シナリオ2: レガシーシステムのモダナイゼーション
状況: 10年以上運用されているシステムを段階的に刷新する
アプローチ:
- Strangler Fig パターンで段階的に移行
- 既存のテストがない場合はCharacterization Testを先に作成
- APIゲートウェイで新旧システムを共存
- データ移行は段階的に実施
| フェーズ | 作業内容 | 期間目安 | リスク |
|---|---|---|---|
| 1. 調査 | 現状分析、依存関係の把握 | 2-4週間 | 低 |
| 2. 基盤 | CI/CD構築、テスト環境 | 4-6週間 | 低 |
| 3. 移行開始 | 周辺機能から順次移行 | 3-6ヶ月 | 中 |
| 4. コア移行 | 中核機能の移行 | 6-12ヶ月 | 高 |
| 5. 完了 | 旧システム廃止 | 2-4週間 | 中 |
シナリオ3: 大規模チームでの開発
状況: 50人以上のエンジニアが同一プロダクトを開発する
アプローチ:
- ドメイン駆動設計で境界を明確化
- チームごとにオーナーシップを設定
- 共通ライブラリはInner Source方式で管理
- APIファーストで設計し、チーム間の依存を最小化
# チーム間のAPI契約定義
from dataclasses import dataclass
from typing import List, Optional
from enum import Enum
class Priority(Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
@dataclass
class APIContract:
"""チーム間のAPI契約"""
endpoint: str
method: str
owner_team: str
consumers: List[str]
sla_ms: int # レスポンスタイムSLA
priority: Priority
def validate_sla(self, actual_ms: int) -> bool:
"""SLA準拠の確認"""
return actual_ms <= self.sla_ms
def to_openapi(self) -> dict:
"""OpenAPI形式で出力"""
return {
'path': self.endpoint,
'method': self.method,
'x-owner': self.owner_team,
'x-consumers': self.consumers,
'x-sla-ms': self.sla_ms
}
# 使用例
contracts = [
APIContract(
endpoint="/api/v1/users",
method="GET",
owner_team="user-team",
consumers=["order-team", "notification-team"],
sla_ms=200,
priority=Priority.HIGH
),
APIContract(
endpoint="/api/v1/orders",
method="POST",
owner_team="order-team",
consumers=["payment-team", "inventory-team"],
sla_ms=500,
priority=Priority.CRITICAL
)
]シナリオ4: パフォーマンスクリティカルなシステム
状況: ミリ秒単位のレスポンスが求められるシステム
最適化ポイント:
- キャッシュ戦略(L1: インメモリ、L2: Redis、L3: CDN)
- 非同期処理の活用
- コネクションプーリング
- クエリ最適化とインデックス設計
| 最適化手法 | 効果 | 実装コスト | 適用場面 |
|---|---|---|---|
| インメモリキャッシュ | 高 | 低 | 頻繁にアクセスされるデータ |
| CDN | 高 | 低 | 静的コンテンツ |
| 非同期処理 | 中 | 中 | I/O待ちが多い処理 |
| DB最適化 | 高 | 高 | クエリが遅い場合 |
| コード最適化 | 低-中 | 高 | CPU律速の場合 |
11. FAQ
Q1: GitOps は Kubernetes 以外でも使えるか?
原理的にはイエス。GitOps の本質は「Git をSingle Source of Truth として宣言的状態を自動同期する」ことであり、Kubernetes に限定されない。Terraform + Atlantis / Spacelift でインフラに GitOps を適用したり、Crossplane で任意のクラウドリソースを Kubernetes CRD として管理する方法もある。ただし、ツールの成熟度は Kubernetes エコシステムが最も高い。
Q2: GitOps でのロールバックはどう行うか?
Git revert で前のバージョンのコミットを作成し、PR をマージする。ArgoCD/Flux がその変更を検知して自動同期する。これにより「ロールバックもGitの履歴に残る」という利点がある。ArgoCD のUIからは過去の同期ポイントに直接ロールバックすることも可能。ただし、データベースマイグレーションを伴う場合は単純な revert では対応できないため、別途手順が必要。
Q3: CI パイプラインと GitOps はどう連携するか?
典型的なフローは (1) アプリリポジトリで CI がビルド・テスト・イメージプッシュ、(2) CI がマニフェストリポジトリの PR を自動作成(イメージタグ更新)、(3) PR レビュー・マージ、(4) ArgoCD/Flux が自動同期。CI はイメージ作成まで、デプロイは GitOps エージェントが担当する責務分離が重要。
Q4: GitOps で DB マイグレーションはどう扱うか?
DB マイグレーションは宣言的ではなく命令的な操作であるため、GitOps の原則に完全には適合しない。一般的なアプローチは、(1) Init Container でマイグレーションを実行、(2) Kubernetes Job としてマイグレーションを実行、(3) ArgoCD の PreSync Hook でマイグレーションを実行。いずれの場合もロールバック戦略を事前に定義しておくことが重要。
Q5: マルチクラスタの GitOps はどう設計するか?
ArgoCD の場合は ApplicationSet を使い、クラスタごとに異なるパラメータ(URL, 環境名, レプリカ数等)を指定する。Hub-and-Spoke モデル(中央の管理クラスタから各クラスタを制御)が一般的。Flux の場合は各クラスタに Flux をインストールし、同じ Git リポジトリの異なるパス(clusters/dev/, clusters/prod/)を参照させる。
Q6: GitOps の導入を段階的に進めるには?
Phase 1: 開発環境のみ GitOps 化(ArgoCD/Flux のインストール、1アプリの同期)、Phase 2: ステージング環境に拡大(ApplicationSet でマルチ環境)、Phase 3: 本番環境に適用(Protection Rules, シークレット管理)、Phase 4: インフラコンポーネントも GitOps 化(cert-manager, ingress 等)。各フェーズで1-2ヶ月の安定稼働を確認してから次に進む。
FAQ
Q1: このトピックを学ぶ上で最も重要なポイントは何ですか?
実践的な経験を積むことが最も重要です。理論だけでなく、実際にコードを書いて動作を確認することで理解が深まります。
Q2: 初心者がよく陥る間違いは何ですか?
基礎を飛ばして応用に進むことです。このガイドで説明している基本概念をしっかり理解してから、次のステップに進むことをお勧めします。
Q3: 実務ではどのように活用されていますか?
このトピックの知識は、日常的な開発業務で頻繁に活用されます。特にコードレビューやアーキテクチャ設計の際に重要になります。
まとめ
| 項目 | 要点 |
|---|---|
| GitOps の本質 | Git が唯一の信頼源、宣言的、プルベース、自動リコンサイル |
| プル型の利点 | 認証情報の局所化、ドリフト自動修復、監査証跡 |
| ArgoCD | リッチUI、マルチクラスタ、ApplicationSet、直感的 |
| Flux | 軽量、CRDベース、イメージ自動更新、SOPS統合 |
| イミュータブル | 変更するのではなく置き換える、不変タグ必須 |
| シークレット管理 | Sealed Secrets / External Secrets / SOPS |
| リポジトリ戦略 | アプリとマニフェストを分離(推奨) |
| CI連携 | CIはイメージ作成まで、デプロイはGitOpsエージェント |
| トラブルシューティング | argocd app diff/sync、ログ確認、sync-wave |
次に読むべきガイド
- コンテナデプロイ -- Kubernetes でのデプロイ実践
- デプロイ戦略 -- Canary、Blue-Green との組合せ
- Actions セキュリティ -- OIDC連携とセキュアなCI
- Infrastructure as Code -- IaCとGitOpsの連携
参考文献
- OpenGitOps. "GitOps Principles." https://opengitops.dev/
- Argo Project. "Argo CD - Declarative GitOps CD for Kubernetes." https://argo-cd.readthedocs.io/
- Fluxcd. "Flux - the GitOps family of projects." https://fluxcd.io/docs/
- Weaveworks. "Guide To GitOps." https://www.weave.works/technologies/gitops/
- Cornelia Davis. Cloud Native Patterns. Manning Publications, 2019.
- Bilgin Ibryam, Roland Hub. Kubernetes Patterns, 2nd Edition. O'Reilly Media, 2023.
- External Secrets Operator. "ESO Documentation." https://external-secrets.io/
- Bitnami Labs. "Sealed Secrets." https://github.com/bitnami-labs/sealed-secrets