⚙️

Goとcdk8sを使ってKubernetesのカスタムリソースを管理する方法

に公開

Goとcdk8sを使ってKubernetesのカスタムリソースを管理する方法

はじめに

Kubernetesのカスタムリソースを管理するのに、YAMLを書くのは正直面倒ですよね。特に複雑なリソースになると、YAMLファイルはすぐに肥大化します。

そこでcdk8sの出番です。GoやTypeScriptなどのプログラミング言語でリソースを定義できるので、コードの再利用や型チェックの恩恵を受けられます。この記事では、Goとcdk8sを使ったカスタムリソース管理の方法を紹介します。例として、Argo WorkflowsのCronWorkflowカスタムリソースを使用しますが、ここで紹介する手法は他のカスタムリソースにも適用できます。

cdk8sとは

cdk8sは、AWSが開発したCDK(Cloud Development Kit)の考え方をKubernetesに適用したものです。これにより、YAMLの代わりにTypeScript、Python、Goなどのプログラミング言語を使用してKubernetesリソースを定義できます。

cdk8sの主な利点:

  • 型安全性: コンパイル時にエラーを検出できる
  • 抽象化: 複雑なリソース定義を再利用可能なコンポーネントとして抽象化できる
  • テスト容易性: ユニットテストやスナップショットテストが可能
  • IDEサポート: コード補完や定義ジャンプなどのIDEの機能を活用できる

環境準備

この記事では、GoとNode.jsがすでにインストールされていることを前提としています。まだインストールしていない場合は、それぞれの公式サイトからインストールしてください。

cdk8s CLIをインストールします:

npm install -g cdk8s-cli

プロジェクトの作成

新しいcdk8sプロジェクトを作成します:

# 新しいディレクトリを作成
mkdir cdk8s-sample
cd cdk8s-sample

# cdk8sプロジェクトを初期化(Go言語を指定)
cdk8s init go-app

これにより、基本的なプロジェクト構造が作成されます。

カスタムリソース定義のインポート

カスタムリソース定義(CRD)をインポートするには、cdk8s importコマンドを使用します。ここでは例としてArgo WorkflowsのCronWorkflow CRDをインポートします:

cdk8s import https://raw.githubusercontent.com/argoproj/argo-workflows/refs/tags/v3.6.5/manifests/base/crds/full/argoproj.io_cronworkflows.yaml

このコマンドは、指定されたURLからCRDを取得し、Goコードを生成します。

これにより、imports/argoprojioディレクトリにカスタムリソースを操作するためのGoコードが生成されます。他のカスタムリソースを使用する場合は、対応するCRDのURLを指定します。

Goコードでのカスタムリソース定義

main.goファイルを編集して、カスタムリソースを定義します。以下はCronWorkflowリソースを例とした実装です:

package main

import (
	"example.com/cdk8s-sample/imports/argoprojio"

	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
	"github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2"
)

type MyChartProps struct {
	cdk8s.ChartProps
}

func NewMyChart(scope constructs.Construct, id string, props *MyChartProps) cdk8s.Chart {
	chart := cdk8s.NewChart(scope, jsii.String(id), &props.ChartProps)

	argoprojio.NewCronWorkflow(chart, jsii.String("hoge"), &argoprojio.CronWorkflowProps{
		Metadata: &cdk8s.ApiObjectMetadata{
			Name: jsii.String("cfw-test"),
		},
		Spec: &argoprojio.CronWorkflowSpec{
			WorkflowSpec: &argoprojio.CronWorkflowSpecWorkflowSpec{
				WorkflowTemplateRef: &argoprojio.CronWorkflowSpecWorkflowSpecWorkflowTemplateRef{
					Name: jsii.String("wft-test"),
				},
			},
			Schedule: jsii.String("0 0 * * *"),
		},
	})

	return chart
}

func main() {
	app := cdk8s.NewApp(&cdk8s.AppProps{})

	NewMyChart(app, "sample", &MyChartProps{})

	app.Synth()
}

このコードでは、以下のことを行っています:

  1. NewMyChart関数でcdk8sのチャートを作成
  2. チャート内でカスタムリソース(この例ではCronWorkflow)を定義
    • メタデータ:名前を設定
    • 各種プロパティ:リソースに必要な設定を指定
  3. main関数でアプリケーションを作成し、チャートを追加して、マニフェストを生成

このパターンは他のカスタムリソースにも適用できます。インポートしたCRDに基づいて生成されたGoの型定義を使用することで、IDEの補完機能を活用しながら、型安全にリソースを定義できます。

マニフェストの生成と適用

以下のコマンドを実行して、Kubernetesマニフェストを生成します:

go run .

または:

cdk8s synth

これにより、distディレクトリにKubernetesマニフェストファイルが生成されます。例えば、上記のCronWorkflowの例では以下のようなYAMLが生成されます:

apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
  name: cfw-test
spec:
  schedule: 0 0 * * *
  workflowSpec:
    workflowTemplateRef:
      name: wft-test

他のカスタムリソースを使用する場合も、同様のパターンでGoコードからYAMLマニフェストが生成されます。

生成されたマニフェストをKubernetesクラスタに適用するには:

kubectl apply -f dist/sample.k8s.yaml

cdk8sを使ったカスタムリソース管理の利点

1. 型安全性

Goの型システムにより、リソース定義の誤りをコンパイル時に検出できます。例えば、必須フィールドの欠落や型の不一致などは、コードを実行する前に検出されます。

2. コード再利用

共通のリソース定義をGoの関数や構造体として抽象化し、再利用できます。例えば、複数のCronWorkflowで共通の設定を持つ場合、それをヘルパー関数として定義できます:

func CreateBaseCronWorkflow(chart constructs.Construct, id string, name string, schedule string) argoprojio.CronWorkflow {
	return argoprojio.NewCronWorkflow(chart, jsii.String(id), &argoprojio.CronWorkflowProps{
		Metadata: &cdk8s.ApiObjectMetadata{
			Name: jsii.String(name),
		},
		Spec: &argoprojio.CronWorkflowSpec{
			Schedule: jsii.String(schedule),
			// 共通の設定...
		},
	})
}

3. 環境ごとの設定変更

環境変数や設定ファイルから値を読み込み、環境ごとに異なるマニフェストを生成できます:

func NewEnvironmentSpecificChart(scope constructs.Construct, id string, props *MyChartProps, env string) cdk8s.Chart {
	chart := cdk8s.NewChart(scope, jsii.String(id), &props.ChartProps)
	
	var schedule string
	if env == "production" {
		schedule = "0 0 * * *"  // 本番環境:毎日午前0時
	} else {
		schedule = "0 12 * * *" // 開発環境:毎日正午
	}
	
	argoprojio.NewCronWorkflow(chart, jsii.String("cron-workflow"), &argoprojio.CronWorkflowProps{
		// ...
		Spec: &argoprojio.CronWorkflowSpec{
			Schedule: jsii.String(schedule),
			// ...
		},
	})
	
	return chart
}

4. テスト容易性

リソース定義をユニットテストできます:

func TestCronWorkflowCreation(t *testing.T) {
	app := cdk8s.NewApp(&cdk8s.AppProps{})
	chart := NewMyChart(app, "test", &MyChartProps{})
	
	// チャート内のリソースをテスト
	// ...
}

まとめ

この記事では、Goとcdk8sを使用してKubernetesのカスタムリソースを管理する方法を紹介しました。cdk8sを使うことで、YAMLファイルを直接編集する代わりに、型安全なGoコードでKubernetesリソースを定義できます。例としてArgo WorkflowsのCronWorkflowを使用しましたが、同じアプローチは他のカスタムリソース(例:Istio、Knative、Prometheus Operator、Cert-Managerなど)にも適用できます。

cdk8sの主な利点は:

  • 型安全性によるエラーの早期発見
  • コードの再利用と抽象化
  • 環境ごとの設定変更の容易さ
  • テスト容易性

カスタムリソースが増えてくると、YAMLファイルの管理は複雑になりがちです。cdk8sを使うことで、プログラミング言語の強力な機能を活用しながら、Kubernetesリソースを効率的に管理できます。

参考リンク

Discussion