Kubernetesプレビュー環境:Argo CDで「誰がステージングを壊した?」問題を解決した方法

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

ステージングサーバーのボトルネック

数年前、私のチームでは1つのステージングサーバーを共有していました。それはまるで、コンロが1つしかない混み合ったキッチンのようでした。あるエンジニアが新しいログインフローをテストしている一方で、別のエンジニアがチェックアウトのエラーをデバッグしようとする。お互いの作業が干渉し合い、午後4時には「誰がステージングを壊した?」という悲痛なSlackメッセージが飛び交うのが日常茶飯事でした。作業は混乱し、15人のチーム全体の開発速度が低下し、QA(品質保証)はまるで終わりのない「モグラ叩き」のような状態でした。

高スピードで開発を進めるチームには、より良いアプローチが必要です。それがエフェメラル環境(一時的な環境)、通称プレビュー環境です。仕組みはこうです。プルリクエスト(PR)が作成されるたびに、Kubernetes上にそのアプリの分離された短命なバージョンが立ち上がります。PRがマージまたはクローズされると、その環境は自動的に消滅します。レビュアーは、メインブランチにコードが反映される前に、本番に近いURLを使って隔離された環境で変更内容を確認できるようになります。

私たちは昨年、このセットアップを本番に導入し、手動デプロイのオーバーヘッドを週に約12時間削減することに成功しました。Argo CDとそのApplicationSetコントローラーを使用することで、手動管理の悪夢を、完全に自動化された「ただ動く」システムへと置き換えたのです。

エンジン:Argo CD ApplicationSet

ApplicationSetが登場する前は、ブランチごとにArgo CDの「Application」を手動で定義する必要がありました。これではスケールしません。ApplicationSetコントローラーは、テンプレートを使用してGitHubのプルリクエストなどの外部トリガーに基づき、複数のApplicationを自動生成することでこの問題を解決しました。

ここで重要な役割を果たすのがPull Request Generatorです。これはリポジトリのオープンなPRを監視し、PR番号やコミットSHAなどのメタデータを取得して、デプロイテンプレートに流し込みます。これがエフェメラルなワークフローの核心です。

なぜこのスタックなのか?

  • 完全な隔離: すべてのPRは専用の名前空間(Namespace)で動作します。
  • 自己修復: プレビュー環境でPodがクラッシュしても、Argo CDが自動的に復旧させます。
  • 高い視認性: Argo CDのダッシュボードを見れば、どのPRがアクティブな環境を持っているかが一目でわかります。

実践:パイプラインの構築

前提条件はシンプルです。Argo CDがインストールされたKubernetesクラスター、Gitリポジトリ、そしてIngress Controllerを指すワイルドカードDNSレコード(例:*.preview.mycompany.com)が必要です。

ステップ1:GitHub認証

Argo CDにはリポジトリを監視する権限が必要です。repoスコープを持つパーソナルアクセストークン(PAT)を作成し、argocd名前空間にSecretとして保存します。

kubectl create secret generic github-token \
  --from-literal=token=ここにあなたのGITHUBトークンを入力 \
  -n argocd

ステップ2:ApplicationSetマニフェスト

ApplicationSetリソースは、新しいPRをどのように処理するかをArgo CDに指示します。generators(生成器)とtemplate(テンプレート)セクションがどのように連携するかに注目してください。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-app-previews
  namespace: argocd
spec:
  generators:
    - pullRequest:
        github:
          owner: my-organization
          repo: my-cool-app
          tokenRef:
            secretName: github-token
            key: token
        requeueAfterSeconds: 60
  template:
    metadata:
      name: 'preview-pr-{{number}}'
    spec:
      project: default
      source:
        repoURL: 'https://github.com/my-organization/my-cool-app.git'
        targetRevision: '{{head_sha}}'
        path: charts/my-app
        helm:
          parameters:
            - name: "ingress.host"
              value: "pr-{{number}}.preview.mycompany.com"
            - name: "image.tag"
              value: "{{head_sha}}"
      destination:
        server: https://kubernetes.default.svc
        namespace: 'preview-pr-{{number}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

仕組みはこうです。Argo CDは pr-123.preview.mycompany.com のような一意のURLを生成します。{{number}}{{head_sha}} といった変数は自動的に注入されます。新しいコミットをプッシュすると、Argo CDがSHAの変更を検知し、即座に環境を更新します。

ステップ3:DNSパズルを解く

DNSはしばしば導入の障壁になります。すべてのPRに対して手動でレコードを作成することは不可能です。解決策はワイルドカードDNSレコードです。*.preview.mycompany.com をNginxやTraefikといったIngress Controller의 外部IPに向けます。

ApplicationSetが新しいIngressを立ち上げると、コントローラーがホスト名を認識し、トラフィックを新しいPodに自動でルーティングします。手間いらずで信頼性の高い方法です。

リソース管理

リソースは無料ではありません。放置しておくと、すべてのPRに対して環境を実行するのはコストがかさみます。幸い、ApplicationSetのPRジェネレーターは、PRがマージされると自動的にApplicationを削除します。prune: true を有効にしているため、Kubernetesは関連するPodやServiceを即座に削除(クリーンアップ)します。

それでも、制限を設けるべきです。忙しいチームが一度に20個のPRを作成した場合、ノードのメモリ不足が発生する可能性があります。プレビュー環境の名前空間ごとに、RAMを約512Mi、CPUコアを0.5個程度に制限するResourceQuotasの使用をお勧めします。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: preview-quota
spec:
  hard:
    requests.cpu: "500m"
    requests.memory: "512Mi"
    limits.cpu: "1000m"
    limits.memory: "1Gi"

新しいワークフロー

これが稼働すると、一日の流れは劇的に変わります:

  1. 開発者がブランチをプッシュし、PRを作成する。
  2. Argo CDが60秒以内にPRを検知する。
  3. 新しい preview-pr-X 名前空間が作成される。
  4. Helm経由でアプリがデプロイされる。
  5. ボットがPRにプレビューリンクをコメントする。
  6. ステークホルダーが実際の機能を確認し、フィードバックを残す。
  7. PRがマージされ、Argo CDがリソースを自動でクリーンアップする。

まとめ

エフェメラル環境への移行は、あらゆるDevOpsパイプラインにおいて最大の成果の一つです。ステージングのボトルネックを解消し、本番環境に到達する前にバグをキャッチできます。ワイルドカードDNSやApplicationSetの設定には最初少し手間がかかりますが、それによってチームが得られるスピードと安心感は、その努力に見合う十分な価値があります。ぜひ試してみてください。開発者もきっと感謝するはずです。

Share: