Contents
- 1 前提条件と GitLab プロジェクトの作成
- 2 Kubernetes クラスタ要件(バージョン・ネットワーク)
- 3 protected variables の設定例とスコープ拡張
- 4 GitLab Agent for Kubernetes (v2) のトークン取得と Helm デプロイ
- 5 Flux + Helm による GitOps 基盤構築
- 6 .gitlab-ci.yml の最新記法(rules)とサンプルパイプライン
- 7 values.yaml の実践的な例(replicaCount・resources 等)
- 8 運用ベストプラクティス、Review Apps、トラブルシューティング
- 9 まとめ
前提条件と GitLab プロジェクトの作成
1‑1. GitLab アカウント・プロジェクト作成手順
| 手順 | 操作内容 |
|---|---|
| ① | GitLab にサインイン → 左上メニュー > 「New project」 → 「Create blank project」 を選択 |
| ② | プロジェクト名は k8s-gitlab-agent など分かりやすく設定。Visibility は Private(推奨) |
| ③ | 作成後、左サイドバー > 「Settings → CI/CD」 → Variables タブへ遷移し、後述の protected variables を登録 |
公式ドキュメント: https://docs.gitlab.com/ee/user/project/settings/#ci-cd-settings
Kubernetes クラスタ要件(バージョン・ネットワーク)
| 項目 | 推奨設定 | 参考リンク |
|---|---|---|
| Kubernetes バージョン | v1.27 以上(GitLab の公式 Helm chart は >=1.27 <1.31 をサポート) |
https://docs.gitlab.com/ee/user/clusters/kubernetes.html#supported-kubernetes-versions |
| Helm Chart バージョン | GitLab Agent for Kubernetes v2 用チャートは ~1.5.x 系(2026‑03 時点の最新は 1.5.4) |
https://docs.gitlab.com/charts/agent/ |
| ネットワークアクセス | Runner / Agent がクラスタ API エンドポイントへ Outbound 接続できる VPC/サブネットを使用。ファイアウォールで 443/tcp を許可 |
同上 |
| RBAC | デフォルトで cluster-admin は不要。最小権限の ServiceAccount と Role/RoleBinding だけで Flux と Helm の操作が可能 |
https://docs.gitlab.com/ee/user/clusters/kubernetes.html#rbac-requirements |
protected variables の設定例とスコープ拡張
2‑1. 基本的な変数一覧
| 変数名 | 用途 | 推奨属性 |
|---|---|---|
KUBE_API_URL |
クラスタ API エンドポイント | Protected, Masked |
KUBE_TOKEN |
ServiceAccount トークン | Protected, Masked |
GITLAB_AGENT_TOKEN |
GitLab Agent v2 用トークン | Protected, Masked |
FLUX_GITLAB_TOKEN |
Flux が GitLab にアクセスする Personal Access Token(api スコープ) |
Protected, Masked |
2‑2. スコープ例のバリエーション
| 変数名 | Environment scope | 有効になるブランチ・タグ |
|---|---|---|
KUBE_TOKEN |
production |
main, release/*(保護ブランチ) |
KUBE_TOKEN_STAGING |
staging |
develop, feature/*(保護なしでも OK) |
FLUX_GITLAB_TOKEN |
(全環境) | タグ (v*.*.*) と main のみ(Protected) |
HELM_VALUES |
preview |
MR 用ブランチ mr-*/** で自動生成 |
ポイント
- Protected が付いている変数は、保護されたブランチ/タグ(GitLab の「Protected branches」設定に含まれる)からしか参照できません。
- 環境スコープを利用すると、production用トークンがstagingで誤って使用されるリスクを防げます。
公式ガイド: https://docs.gitlab.com/ee/ci/variables/#protected-environment-variables
GitLab Agent for Kubernetes (v2) のトークン取得と Helm デプロイ
3‑1. エージェントトークン作成手順
| 手順 | 操作 |
|---|---|
| ① | プロジェクト左メニュー > 「Infrastructure → Kubernetes clusters」 を開く |
| ② | 「Add a new cluster」→「Connect a cluster using the GitLab Agent」を選択 |
| ③ | 「Create new agent」 ボタンをクリックし、エージェント名(例:prod-agent)を入力 |
| ④ | 作成完了後に表示される Agent token をコピー |
手順は GitLab Docs の Connect a cluster using the GitLab Agent に詳述: https://docs.gitlab.com/ee/user/clusters/agent/
3‑2. Kubernetes シークレット作成(CI 環境で実行する例)
|
1 2 3 4 5 6 |
# 前提:$KUBE_TOKEN と $GITLAB_AGENT_TOKEN は protected variables に設定済み kubectl create namespace gitlab-agent # 必要なら名前空間を先に作る kubectl -n gitlab-agent create secret generic gitlab-agent-token \ --from-literal=token=$GITLAB_AGENT_TOKEN |
- シークレット名は Helm chart のデフォルト
gitlab-agent-tokenに合わせておくと、values.yamlが簡潔になる。
3‑3. Helm chart を用いたエージェントインストール
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# 1️⃣ リポジトリ追加 & 更新 helm repo add gitlab https://charts.gitlab.io/ helm repo update # 2️⃣ values.yaml(抜粋)を作成 cat > values.yaml <<'EOF' gitlab: # UI で取得した token を直接参照させる例 token: $(kubectl -n gitlab-agent get secret gitlab-agent-token -o jsonpath="{.data.token}" | base64 --decode) agent: enabled: true # Agent コンポーネントを有効化 config: project: "my-group/k8s-gitlab-agent" rbac: create: true # 最小権限の ServiceAccount と Role を自動生成 # 以下は values.yaml の拡張例(後述参照) replicaCount: 2 resources: limits: cpu: "500m" memory: "512Mi" requests: cpu: "250m" memory: "256Mi" EOF # 3️⃣ デプロイ実行 helm upgrade --install gitlab-agent gitlab/gitlab-agent \ -f values.yaml -n gitlab-agent |
Helm chart の公式インストールガイド: https://docs.gitlab.com/charts/agent/
Flux + Helm による GitOps 基盤構築
4‑1. Flux CLI インストール(Linux/macOS)
|
1 2 |
curl -s https://fluxcd.io/install.sh | sudo bash |
公式インストーラ: https://fluxcd.io/installation/
4‑2. flux bootstrap gitlab による初期化
|
1 2 3 4 5 6 7 8 |
flux bootstrap gitlab \ --owner=<group-or-username> \ --repository=k8s-gitlab-agent \ --branch=main \ --path=clusters/production \ --personal \ --token=$FLUX_GITLAB_TOKEN # protected variable |
--pathに指定したディレクトリが Flux の同期対象になる。- Personal Access Token は api スコープを持つものを使用(GitLab Docs: https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html)。
4‑3. HelmRelease マニフェスト例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# clusters/production/helmrelease-nginx.yaml apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: nginx-ingress namespace: ingress-nginx spec: chart: spec: chart: ingress-nginx sourceRef: kind: HelmRepository name: bitnami # 事前に作成した HelmRepository リソース namespace: flux-system version: "4.7.0" values: controller: replicaCount: 2 resources: limits: cpu: "1000m" memory: "1Gi" requests: cpu: "500m" memory: "512Mi" |
HelmRepository の作成例は公式ドキュメント参照: https://fluxcd.io/docs/components/source/helmrepositories/
4‑4. Git リポジトリ構成(ベストプラクティス)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
├─ clusters/ │ └─ production/ │ ├─ kustomization.yaml # Flux が読むエントリポイント │ └─ helmrelease-nginx.yaml ├─ apps/ │ └─ nginx-ingress/ │ ├─ Chart.yaml │ ├─ values.yaml │ └─ templates/... └─ flux-system/ ├─ helmrepository-bitnami.yaml └─ kustomization.yaml |
- 環境別ディレクトリ (
clusters/production,clusters/staging) にそれぞれkustomization.yamlを置くことで、同一リポジトリで複数環境を管理できる。 - Review Apps 用ブランチ(例:
feature/*)はclusters/preview/<branch>/を追加すれば自動的に別名前空間へデプロイ可能。
公式ガイド: https://fluxcd.io/docs/guides/gitops/
.gitlab-ci.yml の最新記法(rules)とサンプルパイプライン
5‑1. only: / except: を廃止し、rules: に置き換える理由
- GitLab 15.0 以降で非推奨となり、将来的に削除される。
rules:は ブランチ・タグ・マージリクエスト それぞれの条件を柔軟に組み合わせられる。
5‑2. 完全サンプル(文字数増加・コメント付与)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# .gitlab-ci.yml # ------------------------------------------------------------ # CI/CD パイプラインは 3 ステージで構成: # - lint : コード検証のみ # - build : Docker イメージのビルド & レジストリへ push # - deploy : GitOps リポジトリへのマニフェスト更新 or 手動デプロイ # ------------------------------------------------------------ stages: - lint - build - deploy # ----------------------------------------------------------------- # 1️⃣ Lint (コード検証) # ----------------------------------------------------------------- lint: stage: lint image: alpine/git:latest script: - echo "🔍 Checking for Dockerfile ..." - git ls-files | grep -E '^Dockerfile$' && echo "✅ Dockerfile found" rules: # main ブランチ、または MR が作成されたときだけ実行 - if: '$CI_COMMIT_BRANCH == "main"' when: on_success - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' when: on_success # ----------------------------------------------------------------- # 2️⃣ Build (Docker イメージ) # ----------------------------------------------------------------- build: stage: build image: docker:23.0.6 services: - docker:dind variables: DOCKER_DRIVER: overlay2 script: - echo "🔧 Building Docker image ..." - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" . - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" rules: # main ブランチとタグ(リリース)で実行、他はスキップ - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_TAG' when: on_success # ----------------------------------------------------------------- # 3️⃣ Deploy (GitOps リポジトリへ変更プッシュ) # ----------------------------------------------------------------- deploy_gitops: stage: deploy image: alpine/git:latest needs: [build] # ビルドが成功したら実行 variables: GITOPS_REPO_URL: "git@gitlab.com:$CI_PROJECT_NAMESPACE/k8s-gitlab-agent.git" GITOPS_BRANCH: "main" TARGET_PATH: "clusters/production/" before_script: - apk add --no-cache openssh-client git # SSH 鍵は protected variable `SSH_DEPLOY_KEY` に格納済み - echo "$SSH_DEPLOY_KEY" | tr -d '\r' > /tmp/deploy_key && chmod 600 /tmp/deploy_key - eval "$(ssh-agent -s)" && ssh-add /tmp/deploy_key - git config --global user.email "ci@example.com" - git config --global user.name "CI Bot" script: - echo "🚀 Cloning GitOps repo ..." - git clone "$GITOPS_REPO_URL" /tmp/gitops - cd /tmp/gitops - git checkout $GITOPS_BRANCH - cp ${CI_PROJECT_DIR}/helmrelease-nginx.yaml $TARGET_PATH/ - git add $TARGET_PATH/helmrelease-nginx.yaml - | if git diff-index --quiet HEAD; then echo "✅ No changes to commit." else git commit -m "ci: update nginx HelmRelease (image tag $CI_COMMIT_SHORT_SHA)" git push origin $GITOPS_BRANCH fi rules: # main ブランチからのマージ、またはタグ作成時にのみ実行(protected 変数利用) - if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_TAG' when: on_success # ----------------------------------------------------------------- # 4️⃣ 手動デプロイ (kubectl / helm) – 本番環境向け # ----------------------------------------------------------------- manual_deploy: stage: deploy image: bitnami/kubectl:latest variables: KUBECONFIG: "/tmp/kubeconfig" before_script: - echo "$KUBE_CONFIG_CONTENT" | base64 -d > $KUBECONFIG # protected variableに格納されたkubeconfig script: - kubectl --kubeconfig=$KUBECONFIG apply -f k8s/manifests/ environment: name: production url: https://prod.example.com when: manual rules: # タグ(リリース)または保護ブランチで手動実行を許可 - if: '$CI_COMMIT_TAG' when: manual - if: '$CI_COMMIT_BRANCH == "release/*"' when: manual # ----------------------------------------------------------------- # 5️⃣ Review Apps 用ジョブ(マージリクエスト時に自動作成) # ----------------------------------------------------------------- review_app: stage: deploy image: bitnami/kubectl:latest script: - export NAMESPACE="mr-${CI_MERGE_REQUEST_IID}" - kubectl create namespace $NAMESPACE || true - helm upgrade --install myapp ./charts/myapp \ --namespace $NAMESPACE \ --set image.tag=$CI_COMMIT_SHORT_SHA environment: name: review/$CI_MERGE_REQUEST_IID url: https://mr-${CI_MERGE_REQUEST_IID}.example.com on_stop: stop_review_app rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' when: on_success stop_review_app: stage: deploy image: bitnami/kubectl:latest script: - export NAMESPACE="mr-${CI_MERGE_REQUEST_IID}" - helm uninstall myapp --namespace $NAMESPACE || true - kubectl delete namespace $NAMESPACE || true environment: name: review/$CI_MERGE_REQUEST_IID action: stop rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' when: manual |
主な変更点
| 変更前 | 変更後 |
|---|---|
only: / except: |
rules: に統一し、ブランチ・タグ・MR を個別に判定 |
| protected variables の利用範囲が限定的 | KUBE_CONFIG_CONTENT(本番用)、SSH_DEPLOY_KEY(GitOps 用)など、スコープごとに変数を分離 |
手動デプロイは when: manual + rules: でタグ・保護ブランチのみ許可 |
同上 |
values.yaml の実践的な例(replicaCount・resources 等)
以下は GitLab Agent for Kubernetes と 自前アプリケーション 両方に共通して使える設定例です。実運用では環境ごとに values.production.yaml / values.staging.yaml などを分割すると管理が楽になります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# values.yaml(ベース) gitlab: # UI で取得した token を直接参照する場合は上記スクリプトのように展開 token: "<YOUR_AGENT_TOKEN>" agent: enabled: true config: project: "my-group/k8s-gitlab-agent" replicaCount: 2 # 高可用性のため複製数を増やす rbac: create: true # ServiceAccount と Role を自動生成 # アプリケーション側(例:nginx-ingress)に適用するカスタム設定 controller: replicaCount: 2 service: type: LoadBalancer ports: - port: 80 targetPort: http resources: limits: cpu: "1000m" memory: "1Gi" requests: cpu: "500m" memory: "512Mi" # Global のリソース上限(Cluster-wide に適用したい場合) global: imagePullPolicy: IfNotPresent storageClass: standard # Node affinity / tolerations の例 nodeSelector: kubernetes.io/os: linux tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" # Helm chart が提供する任意のカスタム項目(公式ドキュメント参照) extraEnv: - name: LOG_LEVEL value: "info" |
詳細は公式チャートリファレンス → Values セクションに記載されています。
https://docs.gitlab.com/charts/agent/#values
運用ベストプラクティス、Review Apps、トラブルシューティング
7‑1. Review Apps の自動作成とクリーンアップ
| 手順 | 内容 |
|---|---|
| ① | Settings → CI/CD → Environments で Review apps を有効化 |
| ② | .gitlab-ci.yml に review_app と stop_review_app ジョブを追加(上記参照) |
| ③ | マージリクエストが閉じられたら stop_review_app が手動または自動で名前空間と Helm リリースを削除 |
7‑2. RBAC・シークレット管理の最小権限化
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# rbac-minimal.yaml apiVersion: v1 kind: ServiceAccount metadata: name: gitlab-agent namespace: gitlab-agent --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: gitlab-agent-role namespace: gitlab-agent rules: - apiGroups: [""] resources: ["pods", "services", "secrets"] verbs: ["get","list","watch","create","update","patch","delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: gitlab-agent-binding namespace: gitlab-agent subjects: - kind: ServiceAccount name: gitlab-agent roleRef: kind: Role name: gitlab-agent-role apiGroup: rbac.authorization.k8s.io |
- ポイント:
cluster-adminを付与しない。必要最小限の API (pods,services,secrets) のみ許可する。
7‑3. シークレット暗号化と GitOps への安全な保存
|
1 2 3 4 5 6 |
# Dry-run + apply パターンで平文をリポジトリに残さない例 kubectl create secret generic gitlab-agent-token \ --from-literal=token=$GITLAB_AGENT_TOKEN \ -n gitlab-agent \ --dry-run=client -o yaml | kubectl apply -f - |
- GitOps でのベストプラクティス:シークレットはリポジトリに
SealedSecret(bitnami/sealed-secrets)や SOPS 暗号化ファイルとして保存し、Flux が自動復元できる形にする。
7‑4. 典型的なエラーと対処フロー
| 症状 | 原因例 | 確認手順 | 推奨解決策 |
|---|---|---|---|
| Agent が Disconnected | gitlab-agent-token と UI のトークンが不一致 |
kubectl -n gitlab-agent get secret gitlab-agent-token -o yaml → token をデコードして比較 |
正しいトークンでシークレット再作成し、Helm リリースを helm upgrade --install で再適用 |
| Flux が Failed to reconcile | HelmRepository の認証情報が欠如 | kubectl -n flux-system get helmrepositories -o yaml → spec.secretRef.name を確認 |
flux create secret gitlab --url <repo> --personal-token $FLUX_GITLAB_TOKEN で Secret 作成し、HelmRepository に参照させる |
| CI ジョブで 403 Forbidden | protected variable が保護されていないブランチから参照された | パイプラインの Variables タブ → Protected チェック状態を確認 |
保護対象ブランチ(例:main, release/*)に限定し、.gitlab-ci.yml の rules: で条件付ける |
詳細は GitLab Docs 「Kubernetes クラスタを GitLab に接続する手順」および「Flux トラブルシューティングガイド」に掲載。
まとめ
| 項目 | 要点 |
|---|---|
| 前提条件 | GitLab プロジェクト作成 → K8s バージョン (≥ 1.27) 確認 → protected variables の適切なスコープ設定 |
| エージェントトークン | UI で取得 → gitlab-agent-token シークレット化 → Helm chart (gitlab/gitlab-agent) でデプロイ |
| GitOps 基盤 | flux bootstrap gitlab により Flux + Helm の自動同期環境構築。HelmRelease でアプリ管理 |
| CI/CD パイプライン | rules: を用いた条件分岐、protected variables と environment scopes の併用で安全性確保 |
| 運用ベストプラクティス | Review Apps 自動生成、最小権限 RBAC、シークレット暗号化(SealedSecret/SOPS) |
| トラブルシューティング | 接続失敗・Flux 同期エラー・CI 権限エラーの典型パターンと対処フローを把握 |
これらの手順と設定をそのまま適用すれば、GitLab と Kubernetes の安全な連携が確立し、コード変更から本番環境へのデプロイまでが完全に自動化された GitOps ワークフローとして運用できます。
この記事は 2026 年 4 月時点の公式情報を元に作成しています。バージョンや API の変更が生じた場合は、必ず最新の公式ドキュメントをご確認ください。