mcpField
A
ark-controller-development

ark-controller-development

github.com/mckinsey開発43235 回インストール今日更新
リポジトリ

ark-controller-development について

`ark/` の Ark Kubernetes operator 開発者向けスキルです。CRD と Helm chart の同期、Go の実装方針、テストから E2E 確認までの検証手順を扱います。

主な機能

  1. 01CRD 生成と Helm chart 同期
  2. 02Go 実装と依存関係の指針
  3. 03Lint・ビルド・テスト手順
  4. 04Controller と webhook のテスト指針
  5. 05PR 前の検証チェックリスト

活用シーン

  1. 01CRD フィールドの追加や変更
  2. 02CRD 同期エラーの解消
  3. 03Controller や webhook の変更検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mckinsey/agents-at-scale-ark --skill ark-controller-development

インストール後、Claude Code で/ark-controller-developmentを入力して読み込まれたか確認します。

詳細

Ark Controller の開発

ark/ で Ark Kubernetes オペレーターを開発するためのガイダンスです。

このスキルを使用する場面

  • Go 型定義(api/v1alpha1/*_types.go)を変更する場合
  • CRD/Helm チャートの同期エラーを修正する場合
  • 新しい CRD フィールドやリソースを追加する場合

CRD 生成フロー

api/v1alpha1/*_types.go     # Go types with markers
        ↓
    make manifests          # Generates CRDs and syncs to Helm chart
        ↓
config/crd/bases/*.yaml     # Source CRDs (auto-generated)
dist/chart/templates/crd/   # Helm chart CRDs (auto-synced)

make manifests は、テンプレート化されたヘッダーを保持しながら、ソース CRD を Helm チャートに自動的に同期します。

「CRDs out of sync」エラーの修正

make build が CRD の検証エラーで失敗した場合:

cd ark
make manifests
make build

主なディレクトリ

ディレクトリ用途
api/v1alpha1/Go 型定義
config/crd/bases/自動生成されたソース CRD
dist/chart/templates/crd/Helm チャートの CRD(自動同期)
internal/controller/調整ロジック
internal/webhook/アドミッション Webhook
internal/genai/AI/ML の実行ロジック

一般的なタスク

型またはコメントを変更した後

Go の型コメントは CRD フィールドの説明になります:

cd ark
make manifests
make build
Go コードを変更した後
make lint-fix    # Format and auto-fix what the linter can fix
make lint        # Fail fast on issues CI will reject — MANDATORY
make build       # Build and validate
make test        # Run unit + envtest suites
PR を作成する前

稼働中のクラスターに対して chainsaw e2e スイートを実行します。unit と envtest では、apply → reconcile → status の一連の処理全体をテストできません。決定論的な mock-llm スイートを優先し、LLM を利用するテストは、変更がその経路に直接関係する場合にのみ実行してください(コストを抑え、実際の LLM プロバイダーに起因する不安定さを避けられます)。

# Deterministic suite (default)
(cd tests && chainsaw test --selector '!llm')

# LLM suite — only when your change needs it
(cd tests && chainsaw test --selector 'llm')

パターンとアンチパターンについては、chainsaw スキルを参照してください(例:シェルの grep より chainsaw の assert を優先し、ポーリングより wait を優先します)。

make lint は、CI で適用されるものと同じ golangci-lint ルールを実行します。プッシュ前にローカルで実行することは必須です。lint にかかる数分よりも、PR チェックが失敗する方がはるかに大きなコストになります。

既存のコードを活用する — 車輪の再発明は避ける

パーサー、構造体、ヘルパー、リトライループ、URL ビルダーなどのユーティリティを作成する前に、次の場所に既存のものがないか確認してください。

  1. Go 標準ライブラリ。
  2. go.mod の直接または間接依存関係(controller-runtime、apimachinery、実装対象の仕様に対応する SDK、golang.org/x/...)。

手作業で書いたコードは、時間とともに乖離し、テストが重複し、保守の負担になります。ライブラリに処理を委ねる短いアダプターの方が、再実装よりほとんどの場合優れています。

目安:書こうとしているものが、既存の仕様、ファイル形式、ヘッダー構文、または一般的なインフラパターンに似ているなら、すでに誰かが実装しています。まず検索してください:go doc <import-path>、ls $(go env GOMODCACHE)/<dep>。

同じフィールドを持つ構造体を別途定義するのではなく、エイリアス(type X = lib.X)を使ってライブラリの型を再エクスポートしてください。

実例

このプロジェクトの開始時には、WWW-Authenticate パーサー、RFC 9728 の構造体、RFC 8414 の構造体、HTTP フェッチャーを手作業で実装し、約 150 LOC になりました。go-sdk には、すでに oauthex にそれらが含まれていました。

// Bad — 40-line parser, partial struct, duplicated HTTP wrapper.
func parseHeader(h string) (string, bool) { /* ... */ }
type Metadata struct { /* partial mirror of RFC */ }
func fetch(ctx, url) (*Metadata, error) { /* 30 lines */ }

// Good — thin adapter, full spec support, ~10 LOC.
import "github.com/modelcontextprotocol/go-sdk/oauthex"
type Metadata = oauthex.ProtectedResourceMetadata
func Fetch(ctx context.Context, metaURL, resourceURL string, timeout time.Duration) (*Metadata, error) {
    return oauthex.GetProtectedResourceMetadata(ctx, metaURL, resourceURL, &http.Client{Timeout: timeout})
}

同じ原則は、リトライ/バックオフ(k8s.io/apimachinery/pkg/util/wait)、JSON パッチ(strategicpatch)、条件の更新(meta.SetStatusCondition)、HTTP クライアント、ワークキューにも当てはまります。何に取り組む場合でも、まず既存の依存関係を確認してください。

マジックナンバーを避け、設定可能な値を再利用する

数値の時間、リトライ回数、バッファーサイズを直接埋め込まないでください。優先順位は次のとおりです。

  1. ユーザーが設定可能な spec フィールド — リソースにすでに spec.timeout、spec.pollInterval、spec.retries がある場合は、それを使用します。同じ調整処理内の関連するすべてのコードパスを、1 つのオペレーター設定項目で制御します。
  2. パッケージレベルの const — その数値を使う理由がわかる名前を付けます。
  3. テストローカルの const(例:const testTimeout = 5 * time.Second)— テスト内にリテラルを直接埋め込まないでください。
実例
// Bad — parallel constant invented out of thin air.
const discoveryTimeout = 10 * time.Second
client := &http.Client{Timeout: discoveryTimeout}

// Good — plumb the MCPServer's spec.timeout; single source of truth.
func Fetch(ctx, url string, timeout time.Duration) ...
timeout := parseTimeout(mcpServer.Spec.Timeout)

テスト — 必須です

すべてのコード変更にはテストが必要です。ark/internal/ に変更を加える PR に _test.go がない場合は未完成です。これはコントローラーの分岐、Webhook、ヘルパーにも適用されます。公開 API だけが対象ではありません。

変更場所フレームワーク
internal/<pkg>/ のヘルパー/パーサー<file>_test.go標準ライブラリの testing、テーブル駆動
コントローラーの分岐internal/controller/<scenario>_test.goGinkgo + envtest
Webhook ルールinternal/webhook/v1/<resource>_webhook_test.goGinkgo
HTTP ロジック同じパッケージ内の httptest.NewServer標準ライブラリの testing

コントローラーの分岐に必要なテストカバレッジ:

  • 正常系 → 期待されるステータスと条件。
  • 各失敗モード → それぞれ異なる安定した条件理由(文字列マッチングは使用しない)。
  • 冪等性 → 再調整しても重複イベントが発生せず、lastTransitionTime が更新されないこと。
  • リグレッションガード → 既存の分岐に影響がないこと。

完了チェックリスト

「完了」とする前に:

  • make manifests がクリーン(型を変更した場合)
  • make lint がクリーン — CI と同じルールを適用
  • make build が成功
  • make test が成功 — 出力を貼り付けるか、参照する
  • Chainsaw の決定論的スイート(chainsaw test --selector '!llm')が成功。LLM スイートは変更に必要な場合のみ実行
  • 新しい関数/分岐ごとに新しい _test.go がある
  • Helm チャートの CRD が再生成され、コミットされている
  • CRD を変更した場合は、OpenAPI/Python SDK/TypeScript SDK が再生成されている
  • 実行中の Pod を再検証済み — devspace はソースを同期しますが、新しい Go バイナリを反映するにはコンテナーの再起動が必要です。調整パスに変更を加えた後は、コントローラーのログを追跡してください

コメント