•11 min read

Kubernetes Custom Resource Definitions

Kubernetes Custom Resource Definitions

Kubernetesは、クラウドのデファクトスタンダードなオペレーティングシステムとしての地位を確立しました。しかし、その真の力は、Pod、Deployment、Serviceといった標準的なワークロードをオーケストレーションするだけにとどまりません。Kubernetesの真の変革の可能性は、主にカスタムリソース定義(CRD)を介した拡張性によって解き放たれます。CRDを使用すると、開発者はKubernetes APIを拡張し、ネイティブなリソースとまったく同じように動作するカスタムオブジェクトタイプを定義できます。

この包括的な詳細解説では、CRDのアーキテクチャ基盤、カスタムコントローラーの仕組み、APIバージョニング戦略、およびWebhookを使用した高度な検証技術について探ります。

Audio Briefing
0:00 / 0:00

拡張性のパラダイム

CRDを理解するには、まずKubernetesコントロールプレーンがどのように設計されているかを理解する必要があります。その核となるのは、Kubernetes APIサーバー(kube-apiserver)です。これは、クラスターの状態ストア(通常はetcd)へのフロントエンドとして機能するRESTfulインターフェースです。すべてのリクエストに対して、検証、認証、認可を処理します。

歴史的に、このAPIを拡張するには、APIサーバー自体のソースコードを変更する必要がありました。このモノリシックなアプローチは持続不可能でした。カスタムリソース定義(元々はThirdPartyResources)の導入により、拡張メカニズムが分離されました。CRDを使用すると、新しいスキーマを動的に宣言できます。一度定義されると、APIサーバーは新しいリソースのRESTfulエンドポイントを即座に公開し、ロールベースアクセス制御(RBAC)を完備した作成、読み取り、更新、削除(CRUD)操作を提供します。

Advertisement

CRDの構造

典型的なCRD仕様を分析してみましょう。CRDを作成するときは、新しいリソースのグループ、バージョン、種類(GVK)を定義します。さらに、OpenAPI v3仕様を使用してスキーマを定義します。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: databases.company.com
spec:
  group: company.com
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                engine:
                  type: string
                  enum: ["postgres", "mysql"]
                replicas:
                  type: integer
                  minimum: 1
  scope: Namespaced
  names:
    plural: databases
    singular: database
    kind: Database
    shortNames:
    - db

この例では、Databaseリソースを定義しています。openAPIV3Schemaはカスタムリソースを構造的に型付けし、APIサーバーに送信されるペイロードが期待される形式に厳密に準拠していることを保証します。この場合、engineはpostgresまたはmysqlのいずれかである必要があり、replicasは少なくとも1である必要があります。このスキーマ検証は、APIサーバーによって同期的に強制されます。

オペレーターパターン:CRDを活性化させる

CRDだけでは、etcd内の単なる不活性なデータにすぎません。それは何が存在すべきかを定義しますが、どのようにそれを実現するかは定義しません。ここでオペレーターパターンが登場します。オペレーターは、カスタムリソースの変更を監視し、クラスターの現在の状態をCRDで指定された望ましい状態と調整するカスタムコントローラーです。

コントローラーは、レベルトリガー型の調整ループで動作します。Databaseオブジェクトが作成されると、APIサーバーはイベントを発行します。通常、controller-runtimeライブラリを使用してGoで記述されたカスタムコントローラーは、このイベントを受信し、CRD仕様を読み取り、対応する基盤となるリソース(データベースPod用のStatefulSet、ネットワーク用のService、資格情報用のSecretなど)をプロビジョニングします。

状態の調整と冪等性

コントローラーの核となる原則は冪等性です。コントローラーはイベントに反応するだけでなく、望ましい状態と実際の状態を定期的に比較します。ユーザーがDatabaseをバックアップするStatefulSetを手動で削除した場合、コントローラーはドリフトを検出し、それを再作成します。

func (r *DatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    var db companyv1alpha1.Database
    if err := r.Get(ctx, req.NamespacedName, &db); err != nil {
        return ctrl.Result{}, client.IgnoreNotFound(err)
    }

    // Logic to ensure a StatefulSet exists with the correct configuration
    // matching db.Spec.Replicas and db.Spec.Engine
    // ...

    return ctrl.Result{}, nil
}

高度な検証と変更:Webhook

OpenAPIスキーマ検証は強力ですが、限界があります。データベース名が名前空間全体で一意であることを強制する必要がある場合はどうでしょうか?または、動的なデフォルト値を設定したい場合はどうでしょうか?ここでAdmission Webhookが威力を発揮します。

Kubernetesでは、ValidatingAdmissionWebhookとMutatingAdmissionWebhookを介してAPIリクエストを傍受できます。

  1. Mutating Webhook: これらはスキーマ検証前にリクエストを傍受します。主にデフォルト値の設定に使用されます。たとえば、ユーザーがDatabase CRDでバックアップスケジュールを指定しない場合、ミューティングWebhookは、ペイロードが保存される前に動的にデフォルトのcron式を挿入できます。
  2. Validating Webhook: これらは変更とスキーマ検証の後、ただしオブジェクトがetcdにコミットされる前に実行されます。複雑な命令型検証ロジックを実行します。バリデーションWebhookは、外部の企業ポリシーエンジンに問い合わせて、ユーザーがマルチレプリカデータベースをデプロイするための適切なコストセンター予算を持っていることを確認できます。
Advertisement

ライフサイクルの管理:APIバージョニング

カスタムリソースが進化するにつれて、スキーマを変更する必要が必然的に生じます。Kubernetesは、CRDバージョニングと変換Webhookを介してこれを適切に処理します。

v1alpha1を置き換えるv1バージョンを導入する場合、APIサーバーが両方のバージョンを同時に提供するように構成できます。ただし、etcdには1つのストレージバージョンしか存在できません。

バージョン間のギャップを埋めるために、変換Webhookを実装します。クライアントがv1alpha1を要求し、データがv1として保存されている場合、APIサーバーは変換Webhookを呼び出し、v1 JSONペイロードをオンザフライでv1alpha1に変換します。これにより、シームレスな移行パスが提供され、バックエンドスキーマが進化しても古いクライアントは引き続き機能できます。

構造化スキーマとプルーニング

apiextensions.k8s.io/v1では、KubernetesはCRDの構造化スキーマを厳密に強制します。この強制は、プルーニングと呼ばれる機能にとって非常に重要です。ユーザーがOpenAPIスキーマで定義されていない余分なフィールドを持つCRDを送信した場合、APIサーバーはオブジェクトを永続化する前にそれらを自動的に削除(プルーニング)します。これにより、etcdの肥大化を防ぎ、データの一貫性を確保します。

さらに、CRDをシステムに効果的に統合するには、ファイナライザーのニュアンスを理解する必要があります。ファイナライザーは事前削除フックとして機能し、関連するコントローラーが管理するすべての外部依存関係または子オブジェクトのクリーンアップを正常に完了するまで、カスタムリソースがetcdから完全に削除されるのを防ぎます。クリーンアップが完了すると、コントローラーはファイナライザーを削除し、削除を続行できるようにします。

拡張機能のセキュリティに関する考慮事項

Kubernetes APIを拡張する際に、セキュリティを後回しにすることはできません。CRDは新しいエンドポイントを導入するため、RBACによって厳密に管理される必要があります。常に最小権限の原則を強制し、特定のServiceAccountまたはユーザーグループのみがカスタムリソースに対するcreate、update、またはdeleteの権限を持つようにする必要があります。

さらに、リソース枯渇のベクトルも考慮してください。不適切に記述されたコントローラーは、障害時に継続的にループし、大量のログを生成し、他のコンポーネントを混乱させる可能性があります。このリスクを軽減するために、コントローラーのワークキュー内でレート制限と指数バックオフを実装してください。

結論

Kubernetesカスタムリソース定義は、強力なオーケストレーターを無限に拡張可能なプラットフォームに変革します。CRD、オペレーターパターン、Admission Webhook、およびAPIバージョニングを習得することで、プラットフォームエンジニアリングチームは、複雑なドメイン固有のインフラストラクチャを宣言型APIに抽象化できます。

これにより、開発者はセルフサービス機能を利用できるようになり、基本的なPodに使用するのと同じkubectlワークフローを使用して、データベース、メッセージキュー、複雑な分散システムをプロビジョニングできます。その結果、組織の複雑さに比例して拡張する、統一された、堅牢で、高度に自動化されたクラウドネイティブエコシステムが実現します。

こちらもおすすめ

Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement