【テクニカル・上級編】Pulumi Kubernetes Operatorを活用したGitOps実践:IaCとK8sコントローラーの融合による次世代インフラ管理 – インフラ構成管理(IaC)活用バイブル

Pulumi Kubernetes Operatorの深淵:IaCとK8sコントローラーの融合による真のGitOps実践

こんにちは、あるいはこんばんは。数々の修羅場を潜り抜け、数千のインフラリソースのライフサイクルをコードの力で調律してきた伝説的SREだ。

世間では「IaC(Infrastructure as Code)」といえばTerraformやOpenTofuが持て囃され、Kubernetes上のデプロイメントといえばArgo CDやFluxといったGitOpsコントローラーが王道として語られる。しかし、真の自動化、そして「インフラとアプリケーションの境界を完全に消し去る」という境地に達したとき、我々は一つのパラドックスに直面する。

「なぜ、Kubernetesの宣言的API(CRD)の世界に、外部のCI/CDパイプラインや命令型に近いプッシュ型CLIからリソースを流し込まなければならないのか?」

この問いに対する答えの一つが、Pulumi Kubernetes Operatorである。今回は、単なる公式ドキュメントのなぞりではない。このOperatorの内部アーキテクチャの骨の髄まで理解し、プロダクション環境で容赦なく発生するエッジケースをねじ伏せ、Argo CDとの決定的な使い分けの境界線を引くための「極限の知見」を共有しよう。

—

1. 内部アーキテクチャの直視:なぜKubernetes OperatorでPulumiを動かすのか?

従来のPulumiは、ローカル環境、あるいはGitHub ActionsやPulumi Cloudなどの外部CI/CDランタイム上でプログラムを実行(`pulumi up`)し、クラウドプロバイダのAPIを直接叩いてリソースを収束させていた。

しかし、Pulumi Kubernetes Operatorを導入すると、Kubernetes自体がPulumiの実行エンジン(ランタイム)に化ける。

[ Git Repository ]
│ (Webhook / Poll)
▼
[ Kubernetes Cluster ]
│
├── (Custom Resource: Stack)
│ │
│ ▼
│ [ Pulumi Operator Pod ]
│ │ (Executes Node.js/Python/Go)
│ ▼
└── [ Cloud APIs / K8s APIs ] (AWS, GCP, etc.)

コントロールプレープーンの完全な内製化

Operatorは、Kubernetesのカスタムリソース(CRD)である `Stack` リソースを監視する。`Stack` が宣言されると、Operator内部のコントローラーが動的にPod(またはジョブ)をスピンアップし、指定されたGitリポジトリからPulumiプログラムをクローンし、クラスター内部からインフラストラクチャを構築・更新する。

このアプローチの最大のメリットは、「Kubernetesの自己修復能力(Reconciliation Loop)をそのままインフラストラクチャの管理に持ち込める」点にある。外部CI/CDパイプラインのスケジューリング遅延や認証情報の散逸から解放され、K8sエコシステムと完全に融合したIaCが完成する。

—

2. 構築:プロダクション品質のPulumi Kubernetes Operatorデプロイメント

甘口のチュートリアルは他のサイトに任せる。ここでは、セキュリティ、リソース制限、そしてステート管理の観点でチューニングされた、プロダクションで即座に使えるマニフェストを提示する。

2.1. 前提条件:バックエンドストレージと暗号化

Pulumiはステート(状態)を持つ。Operatorを使う場合でも、ステートの永続化先(Pulumi Cloud, AWS S3, MinIO等)と、シークレット暗号化のKMSキーは必須だ。KubernetesのSecretにこれらを安全にマウントする。

2.2. Operator本体のデプロイ(RBACとマネージド・アイデンティティ)

以下のマニフェストは、クラスタースコープで動作し、カスタムリソース `Stack` を監視するOperatorの完全な定義である。

apiVersion: v1
kind: Namespace
metadata:
name: pulumi-operator-system
—
apiVersion: apps/v1
kind: Deployment
metadata:
name: pulumi-operator
namespace: pulumi-operator-system
labels:
app.kubernetes.io/name: pulumi-operator
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: pulumi-operator
template:
metadata:
labels:
app.kubernetes.io/name: pulumi-operator
spec:
serviceAccountName: pulumi-operator
containers:

  • name: operator

image: pulumi/pulumi-kubernetes-operator:v1.8.0
imagePullPolicy: IfNotPresent
env:

  • name: WATCH_NAMESPACE

value: “” # 空文字ならクラスタ全体を監視

  • name: PULUMI_ACCESS_TOKEN

valueFrom:
secretKeyRef:
name: pulumi-api-secret
key: accessToken
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
—
以下、ServiceAccount, ClusterRole, ClusterRoleBindingの定義(省略せず記述)
apiVersion: v1
kind: ServiceAccount
metadata:
name: pulumi-operator
namespace: pulumi-operator-system
—
(RBAC definitions go here: ClusterRole granting full access to pulumi.com APIs and core K8s resources)

—

3. 実践:`Stack` カスタムリソースによるインフラの宣言的駆動

Operatorが稼働したら、次はインフラを定義する `Stack` カスタムリソースを投入する。これにより、GitリポジトリにあるTypeScriptやGoのPulumiコードが、Kubernetes内部で自動実行される。

以下の例では、AWSのS3バケットと、それを利用するKubernetes上のアプリケーションを同時にデプロイする「真のフルスタックGitOps」を構築する。

apiVersion: pulumi.com/v1
kind: Stack
metadata:
name: production-infra-stack
namespace: production
spec:
# 実行するPulumiプログラムが存在するGitリポジトリ
projectRepo: https://github.com/your-org/infra-pulumi-repo.git
branch: refs/heads/main
# リポジトリ内のプログラムディレクトリへのパス
projectFolder: ./k8s-app-stack

# Pulumiのスタック名(環境名)
stack: production

# クラウドプロバイダの認証情報や設定を環境変数として注入
envSecrets:

  • name: AWS_ACCESS_KEY_ID

secretKeyRef:
name: aws-credentials
key: access-key-id

  • name: AWS_SECRET_ACCESS_KEY

secretKeyRef:
name: aws-credentials
key: secret-access-key

# 自動リフレッシュと自動プレビューの設定
refreshChanges: true
destroyOnDelete: false # 本番環境での誤削除を防ぐ極めて重要な設定

このカスタムリソースをクラスターにapplyした瞬間、Operatorは内部でジョブを立ち上げ、`pulumi up` を無人実行し、AWSリソースとKubernetesリソースの乖離をミリ秒単位で埋めに行く。

—

4. 既存GitOpsの覇者「Argo CD」との決定的な使い分け:どちらを選ぶべきか?

「すでにArgo CDを導入しているのに、なぜPulumi Operatorを使う必要があるのか?」という疑問はもっともだ。この2つは競合するようでいて、解決するレイヤーが異なる。

| 比較項目 | Argo CD (GitOps Tool) | Pulumi Kubernetes Operator |
| :— | :— | :— |
| 得意領域 | Kubernetesマニフェスト(YAML, Helm, Kustomize)の収束 | クラウドインフラ(AWS, GCP, Azure等)+ K8sリソースの統合管理 |
| 言語の柔軟性 | 宣言的YAML / Jinja / Helm templateの限界に縛られる | TypeScript, Python, Go, C# などの汎用プログラミング言語 |
| ステート管理 | Gitが単一の真実のソース (Git as Source of Truth) | Pulumi Backend(S3/Pulumi Cloud) + Gitがコードのソース |
| 依存関係解決 | K8sリソース間のSync Waves / Sync Hooks | プログラミング言語の関数、非同期処理、カスタムロジック |

結論:使い分けの黄金律

  • Argo CDを採用すべきケース:

Kubernetesクラスターがすでに存在し、その上で動くアプリやアドオン(ServiceMesh, Monitoring等)のデプロイがメインであり、クラウド側のインフラ(VPC, RDSなど)の変更頻度が低い場合。

  • Pulumi Kubernetes Operatorを採用すべきケース:

アプリケーションのデプロイと、それらが依存するクラウドインフラ(例: S3バケット、IAMロール、データベース)をアトミック(不可分)にデプロイ・管理したい場合。特にマルチクラウド環境や、動的にインフラをプロビジョニングする必要があるSaaS基盤において、その真価を発揮する。

—

5. エキスパート向け知見:パフォーマンス最適化とトラブルシューティングハック

プロダクション環境でPulumi Operatorを運用する際、幾つかの「罠」を踏み抜くことになる。それを未然に防ぐための極上のハックを伝授しよう。

ハック1: Podのスパイクによるリソース枯渇を防ぐ

Pulumiの実行には、Node.jsやPythonのランタイム、そしてPulumi CLIそのものがメモリを大量に消費する。多数の `Stack` リソースを同時にデプロイすると、K8sノードのメモリが枯渇し、OOM Killer(Out of Memory)の餌食になる。

対策:
OperatorのHelmチャート、あるいはDeployment設定で、ジョブを実行するPodのResource Requests/Limitsを厳格に定義し、さらに同時に実行されるStackの最大数(Concurrency)を絞ること。

OperatorのConfigMap等で並行実行数を制限
data:
maxConcurrentReconciles: “2”

ハック2: シークレット管理のジレンマを断つ

GitOpsの原則に従うと、リポジトリにシークレットを含めることはご法度だ。Pulumiプログラム内でパスワードやAPIキーを扱う場合、`pulumi.Config` の `secret: true` を使う。
しかし、Kubernetes Operator環境下では、Pulumiの暗号化パスフレーズ(Passphrase)の管理が鍵になる。

極限のプラクティス:
KMS(AWS KMS / Vault等)をバックエンドにした暗号化プロバイダをPulumiに強制し、Passphrase自体をKubernetesの `External Secrets Operator` などを介して安全にOperatorのポッドへ環境変数(`PULUMI_CONFIG_PASSPHRASE`)として注入する。ファイルベースでの保存は絶対に避けるべきだ。

ハック3: ゾンビプロセスの検知とリカバリ

ネットワークの瞬断やクラウドAPIのレートリミット(429 Too Many Requests)により、`pulumi up` が途中でフリーズすることがある。KubernetesのControllerは、リミットを超えたジョブを放置しがちだ。

対策:
`Stack` リソースのステータスフィールドを監視する独自のPrometheusカスタムメグス(Alertmanager連携)を構築し、`LastExecutionState` が `Failed` または一定時間 `Running` のまま膠着している場合に、自動でPodをパージしてリトライするスクリプトをサイドカーとして常駐させるのが、真のSREの仕事である。

—

終わりに:インフラコードの未来へ

Pulumi Kubernetes OperatorによるGitOpsは、単なる「流行りのツール」ではない。それは、「インフラストラクチャをアプリケーションと同等のライフサイクル、同等の宣言的抽象度で扱う」という、インフラエンジニアリングの究極の到達点の一つだ。

YAMLの呪縛から逃れ、プログラミング言語の表現力とKubernetesの自己修復能力を掛け合わせたとき、あなたのインフラストラクチャは、誰の手も煩わせることなく、自律的に呼吸し、進化する生命体へと生まれ変わる。

さあ、今すぐコードを書き、クラスターに命を吹き込め。健闘を祈る。

タイトルとURLをコピーしました