目次
- GitOpsとは何か|Push型デプロイとPull型デプロイの違い
- 従来のPush型:CIがクラスタに「押し込む」
- GitOpsのPull型:クラスタ側がGitを「取りに行く」
- 宣言的な状態と差分検知・自動同期の仕組み
- 「あるべき状態」と「実際の状態」を突き合わせる
- 自動同期・自動修復・prune
- リポジトリ構成の設計|アプリと環境をどう分けるか
- アプリケーションリポジトリと構成リポジトリを分離する
- 環境はブランチではなくディレクトリで分ける
- ロールバックがgit revertになる利点
- ArgoCDの最小導入手順
- インストールと初期ログイン
- Applicationリソースで同期対象を宣言する
- Fluxとの違い
- トラブル事例と、Kubernetes以外での考え方
- 事例:selfHealで緊急対応がすぐ元に戻されてしまう
- Kubernetesを使っていない場合のGitOps
- まとめ
「本番のKubernetesに、いつ誰が何を変更したのかわからなくなった」「kubectl applyを手元から実行していて、担当者の端末にしか正しい設定がない」。CI/CDを導入しているチームでも、デプロイ後の"実際の状態"がGitと一致している保証がなく、障害時にどこまで戻せばよいのか判断できない、という悩みはよく聞きます。
この記事では、Gitリポジトリを唯一の正(Single Source of Truth)として扱う運用手法「GitOps」を、Push型デプロイとの違い、差分検知と自動同期の仕組み、リポジトリの分け方、ArgoCDの最小導入手順の順に解説します。読み終えると、ロールバックがgit revertで済む運用がなぜ成立するのか、自分たちの環境に取り入れるべきかどうかを判断できるようになります。CI/CDパイプラインの基礎とKubernetesの基本概念は既知のものとして進めます。
GitOpsとは何か|Push型デプロイとPull型デプロイの違い
従来のPush型:CIがクラスタに「押し込む」
GitHub Actionsなどで「テストが通ったらkubectl applyやhelm upgradeを実行する」構成は、CIランナーがクラスタに向かって変更を押し込む(Push)形です。この方式はシンプルですが、いくつか構造的な弱点があります。
- CIランナーに本番クラスタの強い認証情報(kubeconfigやクラウドのクレデンシャル)を置く必要がある
- パイプラインの外で誰かが手動でkubectl editすると、Gitと実環境がずれたまま気づけない
- 「今、本番で動いている設定は何か」をGitからは断言できない
GitOpsのPull型:クラスタ側がGitを「取りに行く」
GitOpsでは、クラスタ内に常駐するエージェント(ArgoCDやFlux)がGitリポジトリを定期的に監視し、宣言された状態と実際の状態を比較して差分があれば自らクラスタに適用します。変更の向きが逆転し、クラスタがGitを取りに行く(Pull)形になります。
この方式ではCIはコンテナイメージをビルドしてレジストリに置き、マニフェストのイメージタグを書き換えるプルリクエストを作るところまでで役割を終えます。クラスタへの認証情報はクラスタ内部のエージェントだけが持ち、外部のCIには一切渡しません。
| 観点 | Push型(CIからapply) | Pull型(GitOps) |
|---|---|---|
| クラスタの認証情報 | CIランナーに保管 | クラスタ内のエージェントのみ |
| 手動変更(ドリフト) | 検知できない | 検知して自動修復できる |
| 現在の状態の把握 | kubectlで確認するしかない | Gitのmainブランチが正 |
| ロールバック | 過去のパイプラインを再実行 | git revertしてマージ |
| 導入コスト | 低い | エージェントとリポジトリ設計が必要 |
宣言的な状態と差分検知・自動同期の仕組み
「あるべき状態」と「実際の状態」を突き合わせる
Kubernetesのマニフェストは「Podを3つ動かす」という手順ではなく「Podが3つある状態」を宣言します。GitOpsエージェントはこの宣言(Desired State)とクラスタのAPIから取得した実際の状態(Live State)を比較し、ずれをOutOfSyncとして可視化します。ArgoCDはデフォルトで約3分ごとにリポジトリをポーリングし、Webhookを設定すればpush直後に反映されます。
自動同期・自動修復・prune
同期の挙動は3つの独立したスイッチで制御します。実務ではこの3つの意味を理解せずに全部オンにして事故が起きることが多いので、それぞれ分けて考えてください。
- automated:Gitに差分が出たら人の承認なしに適用する
- selfHeal:誰かがkubectlで手動変更しても、Gitの状態に強制的に戻す
- prune:Gitから削除されたリソースをクラスタからも削除する
とくにpruneは、マニフェストのファイル名を変えただけで「古いリソースの削除+新しいリソースの作成」と解釈されることがあります。最初はpruneをオフにして、UI上で削除対象を確認しながら運用に慣れるのが安全です。
リポジトリ構成の設計|アプリと環境をどう分けるか
アプリケーションリポジトリと構成リポジトリを分離する
GitOpsではソースコードを置く「アプリリポジトリ」と、Kubernetesマニフェストを置く「構成リポジトリ(config repo)」を分けるのが定石です。同じリポジトリに混在させると、CIがイメージタグを書き換えるコミットを積むたびにアプリのCIが再実行される無限ループや、コード変更とインフラ変更の履歴が混ざって追えなくなる問題が起きます。
環境はブランチではなくディレクトリで分ける
「staging ブランチ」「production ブランチ」と環境をブランチで分ける構成は、環境間の差分がマージ漏れとして蓄積しやすく、推奨されません。Kustomizeのoverlayを使い、1つのブランチ内でディレクトリを分ける構成が扱いやすいです。
config-repo/
├── apps/
│ └── web/
│ ├── base/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── kustomization.yaml
│ └── overlays/
│ ├── staging/
│ │ └── kustomization.yaml # replicas: 1, イメージタグ
│ └── production/
│ └── kustomization.yaml # replicas: 3, リソース制限
└── argocd/
├── web-staging.yaml # Application定義
└── web-production.yaml
環境ごとの分離の考え方そのものは、本シリーズの「開発・ステージング・本番環境の分離設計」で詳しく扱っています。
ロールバックがgit revertになる利点
本番で不具合が出たとき、Push型では「前回成功したパイプラインを探して再実行する」か「手元で古いタグをapplyする」ことになり、どちらも履歴が残りにくい操作です。GitOpsでは、問題のコミットをgit revertしてマージするだけでエージェントが以前の状態に戻し、「いつ、誰が、なぜ戻したか」がプルリクエストとして残ります。ブルーグリーンやカナリアなどのデプロイ手法と組み合わせる場合も、切り替えの判断がすべてGitの履歴に集約されるのが強みです。
ArgoCDの最小導入手順
インストールと初期ログイン
- ArgoCD用のnamespaceを作り、公式マニフェストを適用します。
- 初期adminパスワードをSecretから取り出します。
- port-forwardでUIに接続し、ログイン後にパスワードを変更します。
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# 初期パスワードの取得(初回ログイン後に必ず変更する)
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d; echo
# UIへ接続(https://localhost:8080)
kubectl port-forward svc/argocd-server -n argocd 8080:443
Applicationリソースで同期対象を宣言する
ArgoCDでは「どのリポジトリのどのパスを、どのクラスタのどのnamespaceに同期するか」をApplicationというカスタムリソースで宣言します。これ自体もGitに置くのがGitOpsらしい運用です。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-staging
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/example-org/config-repo.git
targetRevision: main
path: apps/web/overlays/staging
destination:
server: https://kubernetes.default.svc
namespace: web-staging
syncPolicy:
automated:
selfHeal: true
prune: false # 慣れるまでは手動削除にしておく
syncOptions:
- CreateNamespace=true
プライベートリポジトリの場合は、読み取り専用のDeploy Keyを発行してArgoCDに登録します。書き込み権限は不要です。CI側でイメージタグを更新する処理は、GitHub Actionsによる自動デプロイの仕組みをそのまま流用し、最後のステップをkubectl applyから「構成リポジトリへのコミット」に置き換えるだけで移行できます。
Fluxとの違い
FluxはCNCFのもう一つのGitOpsツールで、Web UIを持たずCLIとカスタムリソースだけで構成する軽量な設計です。「flux bootstrap」コマンドでリポジトリとクラスタを一度に紐づけられ、イメージレジストリの新タグを検知して自動でマニフェストを書き換える機能も標準で備えています。UIで状態を確認しながら段階的に導入したいチームはArgoCD、Terraformのようにコードだけで完結させたいチームはFlux、という選び方が一般的です。
トラブル事例と、Kubernetes以外での考え方
事例:selfHealで緊急対応がすぐ元に戻されてしまう
症状:本番障害時にkubectl scaleでレプリカ数を緊急に増やしたところ、数分後に勝手に元の数に戻ってしまい、対応が無駄になった。
原因:selfHealが有効なため、Gitの宣言(replicas: 3)と実際の状態(replicas: 6)のずれをドリフトとみなして自動修復した。GitOpsとしては正しい動作で、緊急対応のやり方が運用と噛み合っていなかった。
対処:緊急時もGit経由で変更する(replicasを変えるプルリクエストを即マージする)運用に統一する。どうしても手動で変更したい場合は、ArgoCDのUIまたはCLIで一時的に自動同期を無効化してから操作し、対応後に必ず元に戻す。あわせてHorizontalPodAutoscalerを使い、replicas自体をGitで固定しない設計に変えるのも有効です。
Kubernetesを使っていない場合のGitOps
GitOpsの本質は「宣言された状態をGitに置き、実環境との差分を自動で埋める」ことであって、Kubernetesは必須ではありません。TerraformなどのIaCでクラウドリソースを管理し、mainブランチへのマージをトリガーにterraform applyを自動実行してdriftを定期チェックする運用は、同じ思想に基づいています。単一のVPSであっても、docker-compose.ymlをGitで管理し、サーバー側のcronやsystemd timerでgit pullして差分があればdocker compose upを実行するだけで、「サーバー上で直接ファイルを編集しない」というGitOpsの核心は実現できます。
まとめ
GitOpsは、デプロイの向きをPushからPullに変えることで、認証情報の露出を減らし、手動変更によるドリフトを検知し、ロールバックをgit revertという日常操作に置き換える運用手法です。導入の際は、アプリと構成でリポジトリを分け、環境はディレクトリで分け、pruneとselfHealは意味を理解したうえで段階的に有効化してください。まずはステージング環境のApplication1つから始め、UIで差分が見える体験を積むことをおすすめします。自社のデプロイフローをGit中心に再設計したい場合は、Harmonic Societyのシステム開発・インフラ支援にお気軽にご相談ください。
Harmonic Society
この記事の内容、自社の業務でも活かせそうですか?
ローカルLLM・AI・クラウドなどの技術導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK。まずは30分の無料相談から。売り込みはしません。
関連記事
Related / 9 articles
Notes & Insights
- プログラミング
DDoS攻撃の仕組みと対策入門|レイヤー別の防御とCDN・クラウドの活用
DDoS攻撃をボリューム型・プロトコル型・アプリ層に分けて仕組みを解説し、自前サーバーで防げない理由、CloudflareやAWS Shieldの標準防御、オリジンIPの隠し方、レートリミットとBot対策、攻撃を受けたときの初動、費用が跳ね上がるDenial of Walletへの備えまでわかります。
- プログラミング
WAFとは?仕組み・導入パターン・誤検知対策|Webアプリを攻撃から守る実践ガイド
WAFがファイアウォールやIDSと何が違うのか、シグネチャとマネージドルールの仕組み、Cloudflare WAF・AWS WAF・ModSecurityの比較、フォーム送信がブロックされる誤検知の調査と例外設定、ログ監視、WAFが代替できないことまで実践的に解説します。
- プログラミング
セキュリティヘッダー入門|CSP・HSTS・X-Frame-Optionsの設定と効果を実践解説
CSP・HSTS・X-Frame-Options・X-Content-Type-Optionsなど主要セキュリティヘッダーが防ぐ攻撃と、CSPのReport-Onlyからの段階導入、nonce/hash、HSTS preloadの不可逆リスク、Nginx・Next.js・Astroでの設定例、確認方法を解説します。
- プログラミング
クラウドの通信費(Egress)入門|データ転送量課金の仕組みと転送コストを抑える設計
クラウドの「受信無料・送信有料」の原則、AZ間・リージョン間・インターネット向けの単価差、NATゲートウェイ処理料の罠、CDNで転送量を減らす方法、バックアップやログ転送の見落とし、請求書で転送料を特定する手順を解説。想定外の請求を防げます。
- プログラミング
秘密情報をGitに入れない仕組み|.gitignore・git-secrets・履歴から漏れた鍵の削除
APIキーや.envをGitにコミットしてしまう典型経路と、.gitignore・.env.exampleの運用、pre-commitでのgitleaks検知、GitHub secret scanningの活用、漏れた鍵の無効化と履歴書き換え(git filter-repo)の手順を解説。仕組みで再発を防げます。
- プログラミング
開発・ステージング・本番環境の分離設計|環境差分をなくす構成とアクセス制御
開発・ステージング・本番それぞれの目的と、構成をコードで揃える方法、環境別の設定注入、本番データを使わないテストデータ戦略、ステージングの保護(Basic認証・IP制限・noindex)、コストを抑える運用までを解説。環境差分による本番障害を防げます。
- プログラミング
ngrok・Cloudflare Tunnelでローカルを公開|Webhook開発とデモ環境の作り方
NAT内のローカル環境にStripeやLINEのWebhookを届けるトンネリングの仕組みを解説。ngrok・Cloudflare Tunnel・localtunnelの比較、固定ドメインと認証、リクエスト検査、公開時のセキュリティ、自宅サーバー公開への応用までわかります。
- プログラミング
ローカル開発環境のHTTPS化|mkcert・hostsファイル・自己署名証明書の正しい使い方
ローカル開発をHTTPS前提にすべき理由(Secure Cookie・Service Worker・OAuth)と、mkcertでローカルCAを作りhostsで独自ドメインを割り当ててVite・Next.js・Dockerで使う手順を解説。証明書警告を無視する癖の危険も理解できます。
- プログラミング
localhost・0.0.0.0・127.0.0.1の違い|ポートとUnixソケットを理解して「つながらない」を解決
localhost・127.0.0.1・0.0.0.0の意味の違い、Dockerで外から接続できない原因、host.docker.internal、ポート競合の調べ方、Unixソケットの利点と権限、1024未満ポートの制約を解説。「つながらない」を仕組みから解決できます。
Harmonic Society
「読んで終わり」にせず、自社の業務で試してみませんか?
AI・ローカルLLM・クラウドの導入を、要件整理からPoC・社内展開まで代表エンジニアが伴走します。オンライン対応・全国OK・売り込みなし。
無料・30分・オンラインOK|1営業日以内に返信します