現場で震えるKubernetes CI/CD:GitHub Actionsによる完全自動化と極限の冪等性担保
こんにちは。テックリードの私だ。
日々のデプロイ作業、あるいは「staging環境には反映されたのにproductionでコンフリクトした」といった、手動オペレーションに起因するヒヤリハットに疲弊していないだろうか。
現代のインフラエンジニアリングにおいて、「人間の手で `kubectl apply` を叩かないこと」は絶対正義である。
今回は、GitHub ActionsとKubernetesを組み合わせ、開発スピードを劇的に高めつつ、インフラの堅牢性を極限まで高めるCI/CDパイプラインの構築ハンズオンをお届けする。
単に動くだけのコードではない。実務の修羅場を潜り抜けたプロたちが使っている「真のベストプラクティス」を余すところなく共有しよう。
—
1. GitOps / CI/CDの全体アーキテクチャ
まずは、今回構築するパイプラインの全体像を定義する。
インフラの構成管理における最大の悪夢は、「Gitのリポジトリと実際のクラスターの状態が乖離する(ドリフトする)こと」だ。
[ Developer ]
│ (git push)
▼
[ GitHub Repository (Source Code & Manifests) ]
│
├─► [ GitHub Actions (CI) ] ──► Unit Test / Build / Push Image ──► [ GitHub Container Registry (GHCR) ]
│
└─► [ GitHub Actions (CD) ] ──► Update Image Tag in Manifest ──► [ Kubernetes Cluster ]
チーム開発における厳格なルール:コード分離の原則
アプリケーションのリポジトリと、Kubernetesのマニフェスト(YAML)を同一リポジトリで管理するアンチパターンは今すぐ捨ててほしい。
- App Repository: アプリケーションのソースコードとDockerfile。
- Manifest (GitOps) Repository: K8sのマニフェスト(Deployment, Service, Ingress等)専用。
この分離により、CI(ビルド・テスト・コンテナプッシュ)と、CD(宣言的デプロイ)の責任範囲が明確になり、障害時の切り分けが圧倒的に早くなる。
—
2. GitHub Actionsからコンテナレジストリ(GHCR)へのプッシュ
まずはCIの肝となるコンテナビルドだ。セキュアかつ高速にビルドするため、GitHub Packages(GHCR)を利用し、BuildKitのキャッシュを活用する。
以下に、実戦投入レベルのワークフローファイルを提示する。
`.github/workflows/ci.yml`
name: Production CI/CD Pipeline
on:
push:
branches:
- main
paths:
- ‘src/’
- ‘Dockerfile’
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
# 1. Docker Buildxのセットアップ(マルチプラットフォーム・キャッシュ最適化に必須)
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# 2. GHCRへのログイン(GITHUB_TOKENの権限を流用)
- name: Log in to the Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 3. メタデータの抽出(タグやラベルの自動付与:Commit SHAをタグにするのが鉄則)
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,format=long
type=raw,value=latest,enable=${{ github.ref == ‘refs/heads/main’ }}
# 4. ビルド&プッシュ(GitHub Actions Cacheを活用した爆速ビルド)
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
> 💡 プロの知見:タグ戦略の極意
> タグに `latest` を使うのはデバッグ時だけにしてほしい。本番環境では必ず Commit SHA(例: `sha-7f8a9b…`) をイメージタグとして指定する。これにより、「今、何というバージョンのコードがクラスターで動いているか」がGitの履歴と100%一致し、ロールバックが極めて容易になる。
—
3. Kubernetesクラスターへの自動デプロイ設定
コンテナイメージがレジストリにプッシュされたら、次はCD(Continuous Deployment)だ。
ここでは、マニフェストリポジトリのイメージタグを書き換え、Kubernetesクラスターへ適用するパイプラインを構築する。
安全なデプロイのため、今回は `kubectl` と環境変数を組み合わせた実用的な構成をとる。
`.github/workflows/cd.yml`
name: Kubernetes Continuous Deployment
on:
workflow_run:
workflows: [“Production CI/CD Pipeline”]
types:
- completed
jobs:
deploy:
if: ${{ github.event.workflow_run.conclusion == ‘success’ }}
runs-on: ubuntu-latest
steps:
- name: Checkout Manifest Repository
uses: actions/checkout@v4
with:
repository: ‘your-org/k8s-manifests’ # マニフェスト専用リポジトリを指定
token: ${{ secrets.MANIFEST_REPO_PAT }} # クロスリポジトリ操作用PAT
- name: Set up Kubectl
uses: azure/setup-kubectl@v3
with:
version: ‘v1.28.2’ # クラスターのバージョンと一致させること!
- name: Configure Kubernetes Cluster Access
uses: azure/k8s-set-context@v4
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG }} # 認証情報は絶対にベタ書きしない
- name: Update Image Tag in Manifest
env:
# CI側で生成されたCommit SHAを環境変数として引き継ぐ(簡略化のため最新SHAを取得)
NEW_IMAGE_TAG: sha-${{ github.event.workflow_run.head_sha }}
run: |
# yq等のツールを使って安全にYAMLのイメージタグを書き換える
cd manifests/production/
yq -i ‘.spec.template.spec.containers[0].image = “ghcr.io/your-org/app:'”$NEW_IMAGE_TAG”‘”‘ deployment.yaml
- name: Commit and Push Manifest Changes
run: |
git config –global user.name “github-actions[bot]”
git config –global user.email “github-actions[bot]@users.noreply.github.com”
git commit -am “chore(deps): update image tag to ${{ github.event.workflow_run.head_sha }}”
git push
- name: Apply Manifests to Cluster (Declarative)
run: |
# 冪等性を担保するため、kustomizeまたはkubectl applyを使用
kubectl apply -k manifests/production/
—
4. シークレット情報の安全な管理方法
「GitHub ActionsのSecretsにDBのパスワードをそのまま保存している」というチームは、今夜のうちに見直してほしい。
セキュアなインフラを構築するため、シークレット管理は以下の階層で設計すべきだ。
1. GitHub Actions側のシークレット(最小限に絞る)
GitHub側には、Kubernetesクラスターにアクセスするための `KUBE_CONFIG` と、別リポジトリ操作用の `MANIFEST_REPO_PAT` のみを持たせる。アプリケーションのDB接続情報などをGitHub Secretsに置くのはセキュリティ上のアンチパターンだ。
2. Kubernetes内部でのシークレット管理(External Secrets Operatorの推奨)
Kubernetes上の機密情報は、Kubernetes Secretsオブジェクトとして素朴に管理するべきではない(Base64エンコードされているだけで、誰でも復号できるため)。
現代のSREの標準解は [External Secrets Operator (ESO)](https://external-secrets.io/) の導入だ。
AWS Secrets Manager, GCP Secret Manager, HashiCorp Vaultなどの外部シークレットストアから、安全に値を同期させる。
以下は、ESOを用いた実用的なカスタムリソース(ExternalSecret)のベストプラクティス設定例だ。
`manifests/production/external-secret.yaml`
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-database-secret
namespace: production
spec:
refreshInterval: “1h” # 定期的にシークレットを同期
secretStoreRef:
name: aws-secretsmanager # 外部のシークレットストアを指定
kind: ClusterSecretStore
target:
name: app-secret-env # KubernetesのSecretとして生成される名前
creationPolicy: Owner
data:
- secretKey: DATABASE_PASSWORD
remoteRef:
key: production/app/database
property: password
これを利用することで、アプリケーションのPodは通常の環境変数として安全に機密情報を受け取ることができ、CI/CDパイプラインやGitリポジトリに平文のパスワードが紛れ込むリスクを完全に排除できる。
—
5. プロの実践テクニック:開発スピードを最大化するTips
最後に、現場のテックリードとしてチームの生産性を引き上げるための「隠し味」を授けよう。
① 開発者向け神プラグイン & ショートカット
- `k9s`: ターミナル上のKubernetesダッシュボード。これなしでのログ確認やポッド再起動は考えられない。`Shift + F` でのポートフォワーディングや、`s` キーでのコンテナシェル侵入を体に覚え込ませろ。
- `kubectx` / `kubens`: クラスターやネームスペースの切り替えミスによる「プロダクション環境破壊事故」を撲滅する。プロンプトに現在の文脈を常時表示させることが鉄則だ。
② チーム開発での設定共有化ルール
- Kustomizeの活用: `helm` も強力だが、環境ごとの差分(Overlay)を直感的に管理したい場合、Kustomizeの `base / overlays` 構造がGitOpsと最も相性が良い。
- Pre-commit Hooksの徹底: `yamllint` や `kubeconform` を `pre-commit` フックに組み込み、構文エラーやKubernetesのスキーマ違反を「GitHubにプッシュする前」に開発者の手元で必ず弾く仕組みを作れ。
—
結びに
GitHub ActionsとKubernetesを組み合わせたCI/CDパイプラインの構築は、単なる「自動化」ではない。
それは、「人間の記憶力や注意力への依存を断ち切り、システムの予測可能性と再現性を極限まで高めるエンジニアリングそのもの」である。
今回紹介した設計思想とコードをベースに、あなたのチームのデプロイを、ボタン一つで安全に、そして何より「退屈な作業」に変えてほしい。
健闘を祈る。