これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.

このページの通常のビューに戻る.

Kubernetesを拡張する

作業環境の要求にKubernetesクラスターを適応させるための高度な方法を理解します。

1 - 複数のスケジューラーを設定する

Kubernetesにはこちらで説明されているデフォルトのスケジューラーが付属します。 もしデフォルトのスケジューラーがあなたの要求を満たさない場合、独自にスケジューラーを実装できます。 さらに、デフォルトのスケジューラーと一緒に複数のスケジューラーを同時に実行し、どのPodにどのスケジューラーを使うかKubernetesに指示できます。 具体例を見ながらKubernetesで複数のスケジューラーを実行する方法を学びましょう。

スケジューラーの実装方法の詳細は本ドキュメントの範囲外です。 標準的な例としてKubernetesのソースディレクトリのpkg/schedulerにあるkube-schedulerの実装が参照できます。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:

バージョンを確認するには次のコマンドを実行してください: kubectl version.

スケジューラーをパッケージ化する

スケジューラーのバイナリをコンテナイメージとしてパッケージ化します。 例として、デフォルトのスケジューラー(kube-scheduler)を2つ目のスケジューラーとして使用します。 GitHubからKubernetesのソースコードをクローンし、ビルドします。

git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes
make

kube-schedulerバイナリを含むコンテナイメージを作成します。 そのためのDockerfileは次のとおりです:

FROM busybox
ADD ./_output/local/bin/linux/amd64/kube-scheduler /usr/local/bin/kube-scheduler

これをDockerfileとして保存し、イメージをビルドしてレジストリにプッシュします。 次の例ではGoogle Container Registry (GCR)を使用します。 詳細はGCRのドキュメントから確認できます。 代わりにDocker Hubを使用することもできます。 Docker Hubの詳細はドキュメントから確認できます。

docker build -t gcr.io/my-gcp-project/my-kube-scheduler:1.0 .     # The image name and the repository
gcloud docker -- push gcr.io/my-gcp-project/my-kube-scheduler:1.0 # used in here is just an example

スケジューラー用のKubernetes Deploymentを定義する

スケジューラーをコンテナイメージとして用意できたら、それ用のPodの設定を作成してクラスター上で動かします。 この例では、直接Podをクラスターに作成する代わりに、Deploymentを使用します。 DeploymentReplicaSetを管理し、そのReplicaSetがPodを管理することで、スケジューラーを障害に対して堅牢にします。 my-scheduler.yamlとして保存するDeploymentの設定を示します:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-scheduler
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-scheduler-as-kube-scheduler
subjects:
- kind: ServiceAccount
  name: my-scheduler
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: system:kube-scheduler
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-scheduler-as-volume-scheduler
subjects:
- kind: ServiceAccount
  name: my-scheduler
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: system:volume-scheduler
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-scheduler-extension-apiserver-authentication-reader
  namespace: kube-system
roleRef:
  kind: Role
  name: extension-apiserver-authentication-reader
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: my-scheduler
  namespace: kube-system
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-scheduler-config
  namespace: kube-system
data:
  my-scheduler-config.yaml: |
    apiVersion: kubescheduler.config.k8s.io/v1
    kind: KubeSchedulerConfiguration
    profiles:
      - schedulerName: my-scheduler
    leaderElection:
      leaderElect: false    
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    component: scheduler
    tier: control-plane
  name: my-scheduler
  namespace: kube-system
spec:
  selector:
    matchLabels:
      component: scheduler
      tier: control-plane
  replicas: 1
  template:
    metadata:
      labels:
        component: scheduler
        tier: control-plane
        version: second
    spec:
      serviceAccountName: my-scheduler
      containers:
      - command:
        - /usr/local/bin/kube-scheduler
        - --config=/etc/kubernetes/my-scheduler/my-scheduler-config.yaml
        image: gcr.io/my-gcp-project/my-kube-scheduler:1.0
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10259
            scheme: HTTPS
          initialDelaySeconds: 15
        name: kube-second-scheduler
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10259
            scheme: HTTPS
        resources:
          requests:
            cpu: '0.1'
        securityContext:
          privileged: false
        volumeMounts:
          - name: config-volume
            mountPath: /etc/kubernetes/my-scheduler
      hostNetwork: false
      hostPID: false
      volumes:
        - name: config-volume
          configMap:
            name: my-scheduler-config

上に示したマニフェストでは、KubeSchedulerConfigurationを使用してあなたのスケジューラー実装の振る舞いを変更できます。 この設定ファイルはkube-schedulerの初期化時に--configオプションから渡されます。 この設定ファイルはmy-scheduler-config ConfigMapに格納されており、my-scheduler DeploymentのPodはmy-scheduler-config ConfigMapをボリュームとしてマウントします。

前述のスケジューラー設定において、あなたのスケジューラー実装はKubeSchedulerProfileを使って表現されます。

備考:

特定のPodをどのスケジューラーが処理するかを指定するには、PodTemplateやPodのマニフェストにあるspec.schedulerNameフィールドをKubeSchedulerProfileschedulerNameフィールドに一致させます。 クラスターで動作させるすべてのスケジューラーの名前は一意的である必要があります。

また、専用のサービスアカウントmy-schedulerを作成してsystem:kube-scheduler ClusterRoleに紐づけを行い、スケジューラーにkube-schedulerと同じ権限を付与している点に注意します。

その他のコマンドライン引数の詳細はkube-schedulerのドキュメントから、その他の変更可能なkube-schedulerの設定はスケジューラー設定のリファレンスから確認できます。

クラスターで2つ目のスケジューラーを実行する

2つ目のスケジューラーをクラスター上で動かすには、前述のDeploymentをKubernetesクラスターに作成します:

kubectl create -f my-scheduler.yaml

スケジューラーのPodが実行中であることを確認します:

kubectl get pods --namespace=kube-system
NAME                                           READY     STATUS    RESTARTS   AGE
....
my-scheduler-lnf4s-4744f                       1/1       Running   0          2m
...

このリストにはデフォルトのkube-schedulerのPodに加えて、my-schedulerのPodが「Running」になっているはずです。

リーダー選出を有効にする

リーダー選出を有効にして複数のスケジューラーを実行するには、次の対応が必要です:

YAMLファイルにあるmy-scheduler-config ConfigMap内のKubeSchedulerConfigurationの次のフィールドを更新します:

  • leaderElection.leaderElecttrueに設定します
  • leaderElection.resourceNamespace<lock-object-namespace>に設定します
  • leaderElection.resourceName<lock-object-name>に設定します

備考:

ロックオブジェクトはコントロールプレーンが自動的に作成しますが、使用するNamespaceはあらかじめ存在している必要があります。 kube-system Namespaceを使うこともできます。

クラスターでRBACが有効になっている場合、system:kube-scheduler ClusterRoleを更新し、endpointsleasesリソースに適用されるルールのresourceNamesにスケジューラー名を追加します。 例を示します:

kubectl edit clusterrole system:kube-scheduler
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-scheduler
rules:
  - apiGroups:
      - coordination.k8s.io
    resources:
      - leases
    verbs:
      - create
  - apiGroups:
      - coordination.k8s.io
    resourceNames:
      - kube-scheduler
      - my-scheduler
    resources:
      - leases
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resourceNames:
      - kube-scheduler
      - my-scheduler
    resources:
      - endpoints
    verbs:
      - delete
      - get
      - patch
      - update

Podにスケジューラーを指定する

2つ目のスケジューラーが動作している状態で、Podをいくつか作成し、デフォルトのスケジューラーまたは新しいスケジューラーのどちらで配置するか指定します。 あるPodを特定のスケジューラーで配置するには、Podのspecにスケジューラー名を指定します。 3つの例を確認しましょう。

  • スケジューラー名を指定しないPodの設定

    apiVersion: v1
    kind: Pod
    metadata:
      name: no-annotation
      labels:
        name: multischeduler-example
    spec:
      containers:
      - name: pod-with-no-annotation-container
        image: registry.k8s.io/pause:3.8

    スケジューラー名が指定されていない場合、Podは自動的にdefault-schedulerによって配置されます。

    このファイルをpod1.yamlとして保存し、Kubernetesクラスターに投入します。

    kubectl create -f pod1.yaml
    
  • default-schedulerを指定するPodの設定

    apiVersion: v1
    kind: Pod
    metadata:
      name: annotation-default-scheduler
      labels:
        name: multischeduler-example
    spec:
      schedulerName: default-scheduler
      containers:
      - name: pod-with-default-annotation-container
        image: registry.k8s.io/pause:3.8
    

    使用するスケジューラーはspec.schedulerNameの値にスケジューラー名を与えることで指定します。 この場合、デフォルトのスケジューラーであるdefault-schedulerを指定します。

    このファイルをpod2.yamlとして保存し、Kubernetesクラスターに投入します。

    kubectl create -f pod2.yaml
    
  • my-schedulerを指定するPodの設定

    apiVersion: v1
    kind: Pod
    metadata:
      name: annotation-second-scheduler
      labels:
        name: multischeduler-example
    spec:
      schedulerName: my-scheduler
      containers:
      - name: pod-with-second-annotation-container
        image: registry.k8s.io/pause:3.8
    

    この場合、前述の手順でデプロイしたmy-schedulerを使用してPodを配置することを指定します。 spec.schedulerNameの値はKubeSchedulerProfileschedulerNameフィールドに設定した名前と一致する必要があります。

    このファイルをpod3.yamlとして保存し、クラスターに投入します。

    kubectl create -f pod3.yaml
    

    3つのPodがすべて実行中であることを確認します。

    kubectl get pods
    

Podが目的のスケジューラーによって配置されたことを確認する

わかりやすさのため、前述の例ではPodが実際に指定したスケジューラーによって配置されたことを確認していません。 確認したい場合はPodとDeploymentの設定の適用順序を変えてみてください。 もしPodの設定をすべて先に適用し、その後にスケジューラーのDeploymentを適用した場合、annotation-second-scheduler Podは「Pending」のままになり、他の2つのPodが先に配置されることを確認できます。 その後にスケジューラーのDeploymentを適用して新しいスケジューラーが動作すると、annotation-second-scheduler Podも配置されます。

あるいは、イベントログの「Scheduled」の項目を見ることで、どのPodがどのスケジューラーによって配置されたかを確認できます。

kubectl get events

クラスターのメインのスケジューラーについては、独自のスケジューラー設定を適用することや、関連するコントロールプレーンノードにある静的Podのマニフェストを変更し独自のコンテナイメージを使うことができます。

2 - CustomResourceDefinitionのバージョン

このページでは、CustomResourceDefinitionにバージョン情報を追加する方法を説明します。 バージョン情報は、CustomResourceDefinitionの安定性レベルを示したり、API表現間の変換を伴う新しいバージョンへAPIを進化させたりするために使用します。 また、オブジェクトをあるバージョンから別のバージョンにアップグレードする方法についても説明します。

始める前に

Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:

カスタムリソースについての基本的な理解が必要です。

作業するKubernetesサーバーは次のバージョン以降のものである必要があります: v1.16.

バージョンを確認するには次のコマンドを実行してください: kubectl version.

概要

CustomResourceDefinition APIは、CustomResourceDefinitionの新しいバージョンを導入してアップグレードするためのワークフローを提供します。

CustomResourceDefinitionが作成されると、最初のバージョンがCustomResourceDefinitionのspec.versionsリストに適切な安定性レベルとバージョン番号で設定されます。 例えば、v1beta1は最初のバージョンがまだ安定していないことを示します。 すべてのカスタムリソースオブジェクトは、最初はこのバージョンで保存されます。

CustomResourceDefinitionが作成されると、クライアントはv1beta1 APIを使い始められます。

後にv1などの新しいバージョンを追加する必要が生じることがあります。

新しいバージョンを追加する手順:

  1. 変換戦略を選択します。 カスタムリソースオブジェクトは両方のバージョンで提供できる必要があるため、保存されているバージョンとは異なるバージョンで提供される場合があります。 これを実現するために、カスタムリソースオブジェクトを保存バージョンと提供バージョンの間で変換する必要がある場合があります。 変換にスキーマの変更が伴い、カスタムロジックが必要な場合は、Conversion Webhookを使用してください。 スキーマの変更がない場合は、デフォルトのNone変換戦略を使用でき、異なるバージョンを提供する際にapiVersionフィールドのみが変更されます。
  2. Coversion Webhookを使用する場合は、Coversion Webhookを作成してデプロイします。 詳細は Webhook Coversionを参照してください。
  3. CustomResourceDefinitionを更新して、spec.versionsリストにserved:trueを設定した新しいバージョンを追加します。 また、spec.conversionフィールドを選択した変換戦略に設定します。 Conversion Webhookを使用する場合は、spec.conversion.webhookClientConfigフィールドをWebhookを呼び出すように設定します。

新しいバージョンが追加されると、クライアントは段階的に新しいバージョンへ移行できます。 一部のクライアントが古いバージョンを使用し、他のクライアントが新しいバージョンを使用することは問題ありません。

保存されているオブジェクトを新しいバージョンに移行する手順:

  1. 既存のオブジェクトを新しい保存バージョンにアップグレードするセクションを参照してください。

オブジェクトを新しい保存バージョンにアップグレードする前、最中、および後でも、クライアントが古いバージョンと新しいバージョンの両方を使用することは安全です。

古いバージョンを削除する手順:

  1. すべてのクライアントが新しいバージョンに完全に移行したことを確認します。 kube-apiserverのログを確認することで、古いバージョンを使用してアクセスしているクライアントを特定できます。
  2. 古いバージョンのservedspec.versionsリストでfalseに設定します。 まだ古いバージョンを使用しているクライアントがある場合、古いバージョンでカスタムリソースオブジェクトにアクセスしようとするとエラーが報告されます。 その場合は、古いバージョンでserved:trueに戻し、残りのクライアントを新しいバージョンに移行してから、この手順を繰り返してください。
  3. 既存のオブジェクトを新しい保存バージョンにアップグレードする手順が完了していることを確認します。
    1. CustomResourceDefinitionのspec.versionsリストで、新しいバージョンのstoragetrueに設定されていることを確認します。
    2. 古いバージョンがCustomResourceDefinitionのstatus.storedVersionsにリストされていないことを確認します。
  4. CustomResourceDefinitionのspec.versionsリストから古いバージョンを削除します。
  5. Conversion Webhookでの古いバージョンに対する変換サポートを削除します。

複数バージョンの指定

CustomResourceDefinition APIのversionsフィールドは、開発したカスタムリソースの複数バージョンをサポートするために使用できます。 バージョンごとに異なるスキーマを持つことができ、Conversion Webhookによってカスタムリソースをバージョン間で変換できます。 WebhookConversionは、適用可能な箇所ではKubernetes API規約に従ってください。 特に、注意事項と提案についてのAPI変更ドキュメントを参照してください。

備考:

apiextensions.k8s.io/v1beta1では、versionsの代わりにversionフィールドがありました。 versionフィールドは非推奨でオプションですが、空でない場合はversionsフィールドの最初の項目と一致する必要があります。

この例では、2つのバージョンを持つCustomResourceDefinitionを示します。 最初の例では、すべてのバージョンが同じスキーマを共有し、バージョン間の変換がないことを前提としています。 YAML内のコメントはより詳しいコンテキストを提供します。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  # 名前は以下のspecフィールドと一致する必要があり、<plural>.<group>の形式である必要があります。
  name: crontabs.example.com
spec:
  # REST APIに使用するグループ名: /apis/<group>/<version>
  group: example.com
  # このCustomResourceDefinitionでサポートされるバージョンのリスト
  versions:
  - name: v1beta1
    # 各バージョンはServedフラグで有効/無効を切り替えられます。
    served: true
    # 1つのバージョンのみをストレージバージョンとしてマークする必要があります。
    storage: true
    # スキーマは必須です
    schema:
      openAPIV3Schema:
        type: object
        properties:
          host:
            type: string
          port:
            type: string
  - name: v1
    served: true
    storage: false
    schema:
      openAPIV3Schema:
        type: object
        properties:
          host:
            type: string
          port:
            type: string
  # conversionセクションはKubernetes 1.13+で導入され、デフォルト値はNone変換(strategyサブフィールドがNoneに設定)です。
  conversion:
    # None変換はすべてのバージョンで同じスキーマを前提とし、カスタムリソースのapiVersionフィールドのみを適切な値に設定します
    strategy: None
  # NamespacedまたはClusterのいずれか
  scope: Namespaced
  names:
    # URLで使用する複数形の名前: /apis/<group>/<version>/<plural>
    plural: crontabs
    # CLIでのエイリアスおよび表示に使用する単数形の名前
    singular: crontab
    # kindは通常、キャメルケースの単数形の型名です。リソースマニフェストでこれを使用します。
    kind: CronTab
    # shortNamesを使用するとCLIでリソースをより短い文字列で指定できます。
    shortNames:
    - ct

# v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  # 名前は以下のspecフィールドと一致する必要があり、<plural>.<group>の形式である必要があります。
  name: crontabs.example.com
spec:
  # REST APIに使用するグループ名: /apis/<group>/<version>
  group: example.com
  # このCustomResourceDefinitionでサポートされるバージョンのリスト
  versions:
  - name: v1beta1
    # 各バージョンはServedフラグで有効/無効を切り替えられます。
    served: true
    # 1つのバージョンのみをストレージバージョンとしてマークする必要があります。
    storage: true
  - name: v1
    served: true
    storage: false
  validation:
    openAPIV3Schema:
      type: object
      properties:
        host:
          type: string
        port:
          type: string
  # conversionセクションはKubernetes 1.13+で導入され、デフォルト値はNone変換(strategyサブフィールドがNoneに設定)です。
  conversion:
    # None変換はすべてのバージョンで同じスキーマを前提とし、
    # カスタムリソースのapiVersionフィールドのみを適切な値に設定します。
    strategy: None
  # NamespacedまたはClusterのいずれか
  scope: Namespaced
  names:
    # URLで使用する複数形の名前: /apis/<group>/<version>/<plural>
    plural: crontabs
    # CLIでのエイリアスおよび表示に使用する単数形の名前
    singular: crontab
    # kindは通常、パスカルケースの単数形の型名です。リソースマニフェストでこれを使用します。
    kind: CronTab
    # shortNamesを使用するとCLIでリソースをより短い文字列で指定できます。
    shortNames:
    - ct

CustomResourceDefinitionをYAMLファイルに保存し、kubectl applyを使用して作成できます。

kubectl apply -f my-versioned-crontab.yaml

作成後、APIサーバーは有効化された各バージョンをHTTP RESTエンドポイントで提供し始めます。 上記の例では、APIバージョンは/apis/example.com/v1beta1/apis/example.com/v1で利用できます。

バージョンの優先順位

CustomResourceDefinitionでバージョンが定義される順序に関わらず、kubectlはデフォルトバージョンとして最も優先度の高いバージョンを使用してオブジェクトにアクセスします。 優先度は、name フィールドを解析してバージョン番号、安定性(GA、Beta、Alpha)、およびその安定性レベル内のシーケンスを判断することで決定されます。

バージョンをソートするために使用されるアルゴリズムは、KubernetesプロジェクトがKubernetesバージョンをソートするのと同じ方法でバージョンをソートするよう設計されています。 バージョンはvで始まり、その後に数字、オプションのbetaまたはalpha指定、およびオプションの追加の数値バージョン情報が続きます。 大まかに言えば、バージョン文字列はv2またはv2beta1のようになります。 バージョンは以下のアルゴリズムを使用してソートされます。

  • Kubernetesバージョンパターンに従うエントリは、従わないものより先にソートされます。
  • Kubernetesバージョンパターンに従うエントリについては、バージョン文字列の数値部分が大きいものから小さいものへとソートされます。
  • 最初の数値部分の後にbetaまたはalphaという文字列が続く場合、それらはその順序でソートされ、betaまたはalphaサフィックスのない同等の文字列(GAバージョンと想定)の後に配置されます。
  • betaまたはalphaの後に別の数字が続く場合、それらの数字も大きいものから小さいものへとソートされます。
  • 上記の形式に合わない文字列はアルファベット順にソートされ、数値部分は特別扱いされません。 以下の例ではfoo1foo10より先にソートされることに注意してください。 これはKubernetesバージョンパターンに従うエントリの数値部分のソートとは異なります。

次のソート済みバージョンリストを見るとわかりやすいかもしれません。

- v10
- v2
- v1
- v11beta2
- v10beta3
- v3beta1
- v12alpha1
- v11alpha2
- foo1
- foo10

複数バージョンの指定の例では、バージョンのソート順はv1の後にv1beta1となります。 これにより、提供されたオブジェクトがバージョンを指定しない限り、kubectlコマンドはデフォルトバージョンとしてv1を使用します。

バージョンの非推奨化

FEATURE STATE: Kubernetes v1.19 [stable]

v1.19以降、CustomResourceDefinitionは定義するリソースの特定バージョンが非推奨であることを示せます。 そのリソースの非推奨バージョンへのAPIリクエストが行われると、APIレスポンスのヘッダーに警告メッセージが返されます。 必要に応じて、リソースの非推奨バージョンごとに警告メッセージをカスタマイズできます。

カスタマイズされた警告メッセージは、非推奨のAPIグループ、バージョン、およびkindを示し、該当する場合は代わりに使用すべきAPIグループ、バージョン、およびkindを示してください。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
  name: crontabs.example.com
spec:
  group: example.com
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
  scope: Namespaced
  versions:
  - name: v1alpha1
    served: true
    storage: false
    # カスタムリソースのv1alpha1バージョンが非推奨であることを示します。
    # このバージョンへのAPIリクエストはサーバーレスポンスに警告ヘッダーを受け取ります。
    deprecated: true
    # v1alpha1 APIリクエストを行うAPIクライアントに返されるデフォルトの警告を上書きします。
    deprecationWarning: "example.com/v1alpha1 CronTab is deprecated; see http://example.com/v1alpha1-v1 for instructions to migrate to example.com/v1 CronTab"
    
    schema: ...
  - name: v1beta1
    served: true
    # カスタムリソースのv1beta1バージョンが非推奨であることを示します。
    # このバージョンへのAPIリクエストはサーバーレスポンスに警告ヘッダーを受け取ります。
    # このバージョンにはデフォルトの警告メッセージが返されます。
    deprecated: true
    schema: ...
  - name: v1
    served: true
    storage: true
    schema: ...

# v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: crontabs.example.com
spec:
  group: example.com
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
  scope: Namespaced
  validation: ...
  versions:
  - name: v1alpha1
    served: true
    storage: false
    # カスタムリソースのv1alpha1バージョンが非推奨であることを示します。
    # このバージョンへのAPIリクエストはサーバーレスポンスに警告ヘッダーを受け取ります。
    deprecated: true
    # v1alpha1 APIリクエストを行うAPIクライアントに返されるデフォルトの警告を上書きします。
    deprecationWarning: "example.com/v1alpha1 CronTab is deprecated; see http://example.com/v1alpha1-v1 for instructions to migrate to example.com/v1 CronTab"
  - name: v1beta1
    served: true
    # カスタムリソースのv1beta1バージョンが非推奨であることを示します。
    # このバージョンへのAPIリクエストはサーバーレスポンスに警告ヘッダーを受け取ります。
    # このバージョンにはデフォルトの警告メッセージが返されます。
    deprecated: true
  - name: v1
    served: true
    storage: true

バージョンの削除

古いAPIバージョンは、その古いバージョンのカスタムリソースを提供したすべてのクラスターで既存の保存データが新しいAPIバージョンに移行され、古いバージョンがCustomResourceDefinitionのstatus.storedVersionsから削除されるまで、CustomResourceDefinitionマニフェストから削除できません。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
  name: crontabs.example.com
spec:
  group: example.com
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
  scope: Namespaced
  versions:
  - name: v1beta1
    # カスタムリソースのv1beta1バージョンが提供されなくなったことを示します。
    # このバージョンへのAPIリクエストはサーバーレスポンスでnot foundエラーを受け取ります。
    served: false
    schema: ...
  - name: v1
    served: true
    # 新しく提供するバージョンをストレージバージョンとして設定する必要があります。
    storage: true
    schema: ...

Webhook Conversion

FEATURE STATE: Kubernetes v1.16 [stable]

備考:

WebhookConversionは1.15からベータ版として、Kubernetes 1.13からアルファ版として利用できます。 CustomResourceWebhookConversionフィーチャーゲートが有効である必要があります。 ベータ機能として多くのクラスターで自動的に有効化されています。 詳細についてはフィーチャーゲートのドキュメントを参照してください。

上記の例では、バージョン間でNone変換を使用しており、変換時にapiVersionフィールドのみを設定し、オブジェクトの残りの部分は変更しません。 APIサーバーは、変換が必要な場合に外部サービスを呼び出すWebhookConversionもサポートしています。 例えば以下の場合です。

  • カスタムリソースが保存バージョンとは異なるバージョンでリクエストされた場合。
  • Watchがあるバージョンで作成されたが、変更されたオブジェクトが別のバージョンで保存されている場合。
  • カスタムリソースのPUTリクエストがストレージバージョンとは異なるバージョンで行われた場合。

これらすべてのケースをカバーし、APIサーバーによる変換を最適化するために、変換リクエストには外部呼び出しを最小限に抑えるために複数のオブジェクトを含めることができます。 Webhookはこれらの変換を独立して実行する必要があります。

Conversion Webhookサーバーの作成

Kubernetes e2eテストで検証されているカスタムリソースConversion Webhookサーバーの実装を参照してください。 このWebhookはAPIサーバーから送信されたConversionReviewリクエストを処理し、ConversionResponseにラップした変換結果を返します。 リクエストには、オブジェクトの順序を変更せずに独立して変換する必要があるカスタムリソースのリストが含まれていることに注意してください。 このサーバーは他の変換にも再利用できるように構成されています。 共通コードのほとんどはフレームワークファイルにあり、異なる変換に対して実装が必要な1つの関数のみを残しています。

備考:

サンプルのConversion WebhookサーバーはClientAuthフィールドをのままにしており、デフォルトはNoClientCertです。 つまり、Webhookサーバーはクライアント(おそらくAPIサーバー)の身元を認証しません。 相互TLSやその他の方法でクライアントを認証する必要がある場合は、APIサーバーの認証方法を参照してください。

許可される変更

Conversion Webhookは、変換されたオブジェクトのmetadata内のlabelsannotations以外のものを変更してはなりません。 nameUIDnamespaceへの変更はリジェクトされ、変換を引き起こしたリクエストは失敗します。 その他のすべての変更は無視されます。

Conversion Webhookサービスのデプロイ

Conversion Webhookのデプロイに関するドキュメントは、アドミッションWebhookのサービス例と同じです。 以降のセクションでは、Conversion Webhookサーバーがdefault Namespaceのexample-conversion-webhook-serverという名前のサービスにデプロイされ、/crdconvertパスでトラフィックを提供していることを前提としています。

備考:

WebhookサーバーがKubernetesクラスターにサービスとしてデプロイされている場合、ポート443のサービスを通じて公開する必要があります(サーバー自体は任意のポートを使用できますが、サービスオブジェクトはポート443にマッピングする必要があります)。 サービスに異なるポートを使用すると、APIサーバーとWebhookサービス間の通信が失敗する可能性があります。

Webhookを使用するためのCustomResourceDefinitionの設定

None変換の例は、specconversionセクションを変更することで、Conversion Webhookを使用するように拡張できます。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  # 名前は以下のspecフィールドと一致する必要があり、<plural>.<group>の形式である必要があります。
  name: crontabs.example.com
spec:
  # REST APIに使用するグループ名: /apis/<group>/<version>
  group: example.com
  # このCustomResourceDefinitionでサポートされるバージョンのリスト
  versions:
  - name: v1beta1
    # 各バージョンはServedフラグで有効/無効を切り替えられます。
    served: true
    # 1つのバージョンのみをストレージバージョンとしてマークする必要があります。
    storage: true
    # トップレベルのスキーマが定義されていない場合、各バージョンが独自のスキーマを定義できます。
    schema:
      openAPIV3Schema:
        type: object
        properties:
          hostPort:
            type: string
  - name: v1
    served: true
    storage: false
    schema:
      openAPIV3Schema:
        type: object
        properties:
          host:
            type: string
          port:
            type: string
  conversion:
    # Webhookストラテジーは、カスタムリソース間のあらゆる変換に対して外部Webhookを呼び出すようAPIサーバーに指示します。
    strategy: Webhook
    # Webhookは、strategyが`Webhook`の場合に必須であり、APIサーバーが呼び出すWebhookエンドポイントを設定します。
    webhook:
      # conversionReviewVersionsはWebhookが理解/推奨するConversionReviewのバージョンを示します。
      # リストの中でAPIサーバーが理解できる最初のバージョンがWebhookに送信されます。
      # Webhookは受け取ったのと同じバージョンのConversionReviewオブジェクトで応答する必要があります。
      conversionReviewVersions: ["v1","v1beta1"]
      clientConfig:
        service:
          namespace: default
          name: example-conversion-webhook-server
          path: /crdconvert
        caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
  # NamespacedまたはClusterのいずれか
  scope: Namespaced
  names:
    # URLで使用する複数形の名前: /apis/<group>/<version>/<plural>
    plural: crontabs
    # CLIでのエイリアスおよび表示に使用する単数形の名前
    singular: crontab
    # kindは通常、キャメルケースの単数形の型名です。リソースマニフェストでこれを使用します。
    kind: CronTab
    # shortNamesを使用するとCLIでリソースをより短い文字列で指定できます。
    shortNames:
    - ct

# v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  # 名前は以下のspecフィールドと一致する必要があり、<plural>.<group>の形式である必要があります。
  name: crontabs.example.com
spec:
  # REST APIに使用するグループ名: /apis/<group>/<version>
  group: example.com
  # 以下のOpenAPIスキーマで指定されていないオブジェクトフィールドを除去します。
  preserveUnknownFields: false
  # このCustomResourceDefinitionでサポートされるバージョンのリスト
  versions:
  - name: v1beta1
    # 各バージョンはServedフラグで有効/無効を切り替えられます。
    served: true
    # 1つのバージョンのみをストレージバージョンとしてマークする必要があります。
    storage: true
    # トップレベルのスキーマが定義されていない場合、各バージョンが独自のスキーマを定義できます。
    schema:
      openAPIV3Schema:
        type: object
        properties:
          hostPort:
            type: string
  - name: v1
    served: true
    storage: false
    schema:
      openAPIV3Schema:
        type: object
        properties:
          host:
            type: string
          port:
            type: string
  conversion:
    # Webhookストラテジーは、カスタムリソース間のあらゆる変換に対して外部Webhookを呼び出すようAPIサーバーに指示します。
    strategy: Webhook
    # webhookClientConfigは、strategyが`Webhook`の場合に必須であり、APIサーバーが呼び出すWebhookエンドポイントを設定します。
    webhookClientConfig:
      service:
        namespace: default
        name: example-conversion-webhook-server
        path: /crdconvert
      caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
  # NamespacedまたはClusterのいずれか
  scope: Namespaced
  names:
    # URLで使用する複数形の名前: /apis/<group>/<version>/<plural>
    plural: crontabs
    # CLIでのエイリアスおよび表示に使用する単数形の名前
    singular: crontab
    # kindは通常、キャメルケースの単数形の型名です。リソースマニフェストでこれを使用します。
    kind: CronTab
    # shortNamesを使用するとCLIでリソースをより短い文字列で指定できます。
    shortNames:
    - ct

CustomResourceDefinitionをYAMLファイルに保存し、kubectl applyを使用して適用できます。

kubectl apply -f my-versioned-crontab-with-conversion.yaml

新しい変更を適用する前に、変換サービスが起動して実行されていることを確認してください。

Webhookへの接続

APIサーバーがリクエストをConversion Webhookに送信すべきと判断すると、Webhookへの接続方法を知る必要があります。 これはWebhook設定のwebhookClientConfigスタンザで指定します。

Conversion WebhookはURLまたはサービスへの参照を通じて呼び出すことができ、オプションでTLS接続の検証に使用するカスタムCAバンドルを含めることができます。

URL

urlはWebhookの場所を標準的なURL形式(scheme://host:port/path)で指定します。

hostはクラスター内で実行中のサービスを参照しないようにしてください。 代わりにserviceフィールドを指定してサービスへの参照を使用してください。 ホストは一部のAPIサーバー(例えば、kube-apiserverはレイヤー違反になるためクラスター内DNSを解決できません)では外部DNSを通じて解決される場合があります。 hostはIPアドレスでも構いません。

localhostまたは127.0.0.1hostとして使用することは、このWebhookを必要とする可能性のあるAPIサーバーを実行するすべてのホストで、このWebhookを実行するよう細心の注意を払わない限りリスクがあります。 このようなインストールはポータブルでなかったり、新しいクラスターでの実行が難しかったりする可能性があります。

スキームは"https"である必要があります。 URLは"https://"で始まる必要があります。

ユーザー認証またはBasic認証(例えば "user:password@")の使用は許可されていません。 フラグメント("#...")およびクエリパラメーター("?...")も許可されていません。

以下は、URLを呼び出すように設定されたConversion Webhookの例です(TLS証明書はシステムの信頼ルートを使用して検証されるため、caBundleは指定していません)。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:
  ...
  conversion:
    strategy: Webhook
    webhook:
      clientConfig:
        url: "https://my-webhook.example.com:9443/my-webhook-path"
...

# v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
...
spec:
  ...
  conversion:
    strategy: Webhook
    webhookClientConfig:
      url: "https://my-webhook.example.com:9443/my-webhook-path"
...

サービスへの参照

webhookClientConfig内のserviceスタンザは、Conversion Webhookのサービスへの参照です。 Webhookがクラスター内で実行されている場合は、urlの代わりにserviceを使用してください。 サービスのNamespaceと名前は必須です。 ポートはオプションで、デフォルトは443です。 パスはオプションで、デフォルトは"/"です。

以下は、サブパス"/my-path"のポート"1234"でサービスを呼び出し、カスタムCAバンドルを使用してServerName my-service-name.my-service-namespace.svcに対するTLS接続を検証するように設定されたWebhookの例です。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:
  ...
  conversion:
    strategy: Webhook
    webhook:
      clientConfig:
        service:
          namespace: my-service-namespace
          name: my-service-name
          path: /my-path
          port: 1234
        caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...

# v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
...
spec:
  ...
  conversion:
    strategy: Webhook
    webhookClientConfig:
      service:
        namespace: my-service-namespace
        name: my-service-name
        path: /my-path
        port: 1234
      caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...

Webhookのリクエストとレスポンス

リクエスト

WebhookにはContent-Type: application/jsonを持つPOSTリクエストが送信され、apiextensions.k8s.io APIグループのConversionReview APIオブジェクトがJSONとしてシリアライズされたものがボディとして含まれます。

WebhookはCustomResourceDefinitionのconversionReviewVersionsフィールドを使用して、受け入れるConversionReviewオブジェクトのバージョンを指定できます。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:
  ...
  conversion:
    strategy: Webhook
    webhook:
      conversionReviewVersions: ["v1", "v1beta1"]
      ...

conversionReviewVersionsapiextensions.k8s.io/v1カスタムリソース定義を作成する際の必須フィールドです。 Webhookは現在および1つ前のAPIサーバーが理解できるConversionReviewバージョンを少なくとも1つサポートする必要があります。

# v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
...
spec:
  ...
  conversion:
    strategy: Webhook
    conversionReviewVersions: ["v1", "v1beta1"]
    ...

conversionReviewVersionsが指定されない場合、apiextensions.k8s.io/v1beta1カスタムリソース定義を作成する際のデフォルトはv1beta1です。

APIサーバーはconversionReviewVersionsリストの中でサポートする最初のConversionReviewバージョンを送信します。 リスト内のバージョンがAPIサーバーでサポートされていない場合、カスタムリソース定義は作成できません。 以前に作成されたConversion Webhook設定にAPIサーバーが送信できるConversionReviewバージョンのいずれもサポートされていない場合、Webhookの呼び出しは失敗します。

この例では、CronTabオブジェクトをexample.com/v1に変換するリクエストのConversionReviewオブジェクトに含まれるデータを示します。

{
  "apiVersion": "apiextensions.k8s.io/v1",
  "kind": "ConversionReview",
  "request": {
    # この変換呼び出しを一意に識別するランダムなuid
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
    
    # オブジェクトを変換すべきAPIグループとバージョン
    "desiredAPIVersion": "example.com/v1",
    
    # 変換するオブジェクトのリスト。
    # 1つまたは複数のバージョン、1つまたは複数のオブジェクトを含む場合があります。
    "objects": [
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1beta1",
        "metadata": {
          "creationTimestamp": "2019-09-04T14:03:02Z",
          "name": "local-crontab",
          "namespace": "default",
          "resourceVersion": "143",
          "uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
        },
        "hostPort": "localhost:1234"
      },
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1beta1",
        "metadata": {
          "creationTimestamp": "2019-09-03T13:02:01Z",
          "name": "remote-crontab",
          "resourceVersion": "12893",
          "uid": "359a83ec-b575-460d-b553-d859cedde8a0"
        },
        "hostPort": "example.com:2345"
      }
    ]
  }
}

{
  # v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
  "apiVersion": "apiextensions.k8s.io/v1beta1",
  "kind": "ConversionReview",
  "request": {
    # この変換呼び出しを一意に識別するランダムなuid
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
    
    # オブジェクトを変換すべきAPIグループとバージョン
    "desiredAPIVersion": "example.com/v1",
    
    # 変換するオブジェクトのリスト。
    # 1つまたは複数のバージョンの1つまたは複数のオブジェクトを含む場合があります。
    "objects": [
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1beta1",
        "metadata": {
          "creationTimestamp": "2019-09-04T14:03:02Z",
          "name": "local-crontab",
          "namespace": "default",
          "resourceVersion": "143",
          "uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
        },
        "hostPort": "localhost:1234"
      },
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1beta1",
        "metadata": {
          "creationTimestamp": "2019-09-03T13:02:01Z",
          "name": "remote-crontab",
          "resourceVersion": "12893",
          "uid": "359a83ec-b575-460d-b553-d859cedde8a0"
        },
        "hostPort": "example.com:2345"
      }
    ]
  }
}

レスポンス

WebhookはHTTPステータスコード200、Content-Type: application/json、およびConversionReviewオブジェクト(送信されたのと同じバージョン)を含むボディで応答します。 このオブジェクトはresponseスタンザが設定され、JSONにシリアライズされています。

変換が成功した場合、Webhookは以下のフィールドを含むresponseスタンザを返す必要があります:

  • Webhookに送信されたrequest.uidからコピーされたuid
  • {"status":"Success"}に設定されたresult
  • request.objectsのすべてのオブジェクトをrequest.desiredAPIVersionに変換したものを含むconvertedObjects

Webhookからの最小限の成功レスポンスの例:

{
  "apiVersion": "apiextensions.k8s.io/v1",
  "kind": "ConversionReview",
  "response": {
    # <request.uid>と一致する必要があります。
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
    "result": {
      "status": "Success"
    },
    # オブジェクトはrequest.objectsの順序と一致し、apiVersionが<request.desiredAPIVersion>に設定されている必要があります。
    # kind、metadata.uid、metadata.name、metadata.namespaceフィールドはWebhookによって変更してはなりません。
    # metadata.labelsとmetadata.annotationsフィールドはWebhookによって変更できます。
    # Webhookによるmetadataフィールドのその他すべての変更は無視されます。
    "convertedObjects": [
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1",
        "metadata": {
          "creationTimestamp": "2019-09-04T14:03:02Z",
          "name": "local-crontab",
          "namespace": "default",
          "resourceVersion": "143",
          "uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
        },
        "host": "localhost",
        "port": "1234"
      },
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1",
        "metadata": {
          "creationTimestamp": "2019-09-03T13:02:01Z",
          "name": "remote-crontab",
          "resourceVersion": "12893",
          "uid": "359a83ec-b575-460d-b553-d859cedde8a0"
        },
        "host": "example.com",
        "port": "2345"
      }
    ]
  }
}

{
  # v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
  "apiVersion": "apiextensions.k8s.io/v1beta1",
  "kind": "ConversionReview",
  "response": {
    # <request.uid>と一致する必要があります。
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
    "result": {
      "status": "Failed"
    },
    # オブジェクトはrequest.objectsの順序と一致し、apiVersionが<request.desiredAPIVersion>に設定されている必要があります。
    # kind、metadata.uid、metadata.name、metadata.namespaceフィールドはWebhookによって変更してはなりません。
    # metadata.labelsとmetadata.annotationsフィールドはWebhookによって変更できます。
    # Webhookによるmetadataフィールドのその他すべての変更は無視されます。
    "convertedObjects": [
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1",
        "metadata": {
          "creationTimestamp": "2019-09-04T14:03:02Z",
          "name": "local-crontab",
          "namespace": "default",
          "resourceVersion": "143",
          "uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
        },
        "host": "localhost",
        "port": "1234"
      },
      {
        "kind": "CronTab",
        "apiVersion": "example.com/v1",
        "metadata": {
          "creationTimestamp": "2019-09-03T13:02:01Z",
          "name": "remote-crontab",
          "resourceVersion": "12893",
          "uid": "359a83ec-b575-460d-b553-d859cedde8a0"
        },
        "host": "example.com",
        "port": "2345"
      }
    ]
  }
}

変換が失敗した場合、Webhookは以下のフィールドを含むresponseスタンザを返す必要があります:

  • Webhookに送信されたrequest.uidからコピーされたuid
  • {"status":"Failed"}に設定されたresult

警告:

変換の失敗は、リソースの更新や削除を含む、カスタムリソースへの読み取りおよび書き込みアクセスを妨げる可能性があります。 変換の失敗はできる限り避け、バリデーション制約を強制するために使用しないでください(代わりに検証スキーマやWebhookアドミッションを使用してください)。

変換リクエストの失敗を示すWebhookからのレスポンスの例(オプションのメッセージ付き):

{
  "apiVersion": "apiextensions.k8s.io/v1",
  "kind": "ConversionReview",
  "response": {
    "uid": "<value from request.uid>",
    "result": {
      "status": "Failed",
      "message": "hostPort could not be parsed into a separate host and port"
    }
  }
}

{
  # v1.16でapiextensions.k8s.io/v1を推奨として非推奨になりました。
  "apiVersion": "apiextensions.k8s.io/v1beta1",
  "kind": "ConversionReview",
  "response": {
    "uid": "<value from request.uid>",
    "result": {
      "status": "Failed",
      "message": "hostPort could not be parsed into a separate host and port"
    }
  }
}

バージョン管理されたCustomResourceDefinitionオブジェクトの書き込み、読み取り、更新

オブジェクトが書き込まれると、書き込み時にストレージバージョンとして指定されているバージョンで保存されます。 ストレージバージョンが変更されても、既存のオブジェクトは自動的に変換されません。 ただし、新しく作成または更新されたオブジェクトは新しいストレージバージョンで書き込まれます。 オブジェクトが現在提供されていないバージョンで書き込まれていた可能性があります。

オブジェクトを読み取る際は、パスの一部としてバージョンを指定します。 現在提供されているバージョンであれば、任意のバージョンでオブジェクトをリクエストできます。 オブジェクトの保存バージョンとは異なるバージョンを指定した場合、Kubernetesはリクエストしたバージョンでオブジェクトを返しますが、保存されているオブジェクトはディスク上で変更されません。

読み取りリクエストを提供する際に返されるオブジェクトに何が起きるかは、CRDのspec.conversionに何が指定されているかによります:

  • デフォルトのstrategyNoneが指定されている場合、オブジェクトへの変更はapiVersion文字列の変更と、不明なフィールドのプルーニング(設定に依存)のみです。 保存バージョンとリクエストバージョン間でスキーマが異なる場合、この方法では適切な結果が得られない可能性があることに注意してください。 特に、バージョン間で同じデータが異なるフィールドで表現されている場合は、このストラテジーを使用しないでください。
  • Webhook Conversionが指定されている場合は、そのメカニズムが変換を制御します。

既存のオブジェクトを更新すると、現在のストレージバージョンで書き直されます。 これがオブジェクトがあるバージョンから別のバージョンに変更される唯一の方法です。

これを説明するために、以下の仮想的な一連のイベントを考えてみましょう:

  1. ストレージバージョンはv1beta1です。 オブジェクトを作成します。 バージョンv1beta1で保存されます。
  2. CustomResourceDefinitionにv1バージョンを追加して、ストレージバージョンとして指定します。 ここではv1v1beta1のスキーマが同一であり、これはKubernetesエコシステムでAPIを安定版に昇格させる際の通常のケースです。
  3. オブジェクトをバージョンv1beta1で読み取り、次にバージョンv1で再度読み取ります。 返された両方のオブジェクトはapiVersionフィールドを除いて同一です。
  4. 新しいオブジェクトを作成します。 バージョンv1で保存されます。 これで2つのオブジェクトがあり、一方はv1beta1で、もう一方はv1です。
  5. 最初のオブジェクトを更新します。 現在のストレージバージョンがv1であるため、バージョンv1で保存されます。

過去のストレージバージョン

APIサーバーは、ストレージバージョンとしてマークされたことがあるすべてのバージョンをステータスフィールドのstoredVersionsに記録します。 オブジェクトは、ストレージバージョンとして指定されたことがある任意のバージョンで保存されている場合があります。 ストレージバージョンであったことがないバージョンのオブジェクトはストレージに存在できません。

既存のオブジェクトを新しい保存バージョンにアップグレードする

バージョンを非推奨化してサポートを終了する場合は、ストレージアップグレード手順を選択してください。

オプション1: Storage Version Migratorを使用する

  1. Storage Version Migratorを実行します
  2. CustomResourceDefinitionのstatus.storedVersionsフィールドから古いバージョンを削除します

オプション2: 既存のオブジェクトを新しい保存バージョンに手動でアップグレードする

以下はv1beta1からv1へのアップグレード手順の例です。

  1. CustomResourceDefinitionファイルでv1をストレージに設定し、kubectlを使用して適用します。 storedVersionsv1beta1, v1になります。
  2. 既存のすべてのオブジェクトをリストアップして同じ内容で書き込むアップグレード手順を作成します。 これによりバックエンドが現在のストレージバージョン(v1)でオブジェクトを書き込むよう強制されます。
  3. CustomResourceDefinitionのstatus.storedVersionsフィールドからv1beta1を削除します。

備考:

kubectlを使用してCRDオブジェクトのstatusサブリソースにパッチを当てる方法の例を以下に示します:

kubectl patch customresourcedefinitions <CRD_Name> --subresource='status' --type='merge' -p '{"status":{"storedVersions":["v1"]}}'