TT Lab
はじめる
学ぶ 学習パス コース

CNPA — クラウドネイティブプラットフォームエンジニアリングアソシエイト

CRDでプラットフォームAPIを作る

TT Labで続きを見る

目標

Kubernetes APIを拡張してWebServiceというプラットフォームAPIを自分で作り、スキーマ検証・サーバーサイドのデフォルト値・テナントの境界・セルフサービスのRBACまでを一式、実際のクラスターで完成させます。

なぜ重要なのか

プラットフォームAPIを社内のWebアプリとして作ると、状態の保存、並行制御、認証・認可、監査、watchをすべて実装し直す必要があります。CRDを登録すれば、それらがすべてついてきます。だからKubernetes APIがプラットフォームの共通言語になりました。特にOpenAPIスキーマは、セルフサービスの3つの条件のうち「速いフィードバック」を最も安く実装する仕組みです。maximum: 10の1行で、誤ったリクエストが、30分後のパイプラインログではなく即座に、人が読める文で拒否されます。defaultも同様に、「安全なデフォルト値」をサーバーが強制してくれます。そして、CRDだけではプラットフォームは完成しません。テナントが互いを侵害できないという境界(ネームスペース・クォータ・RBAC)がそろって初めて、チケットなしで権限を与えられます。このラボのリソースはすべてKubernetes組み込みのリソースなので、実際に適用してkubectlで採点します。

ステップ

  1. /root/cnpa-platform/crd.yamlにCustomResourceDefinitionを作成して適用してください。metadata.name: webservices.platform.labhub.io、spec.group: platform.labhub.io、spec.scope: Namespacedとし、spec.namesはkindがWebService、pluralがwebservices、singularがwebservice、shortNamesの最初の項目がwsです。バージョンv1alpha1はserved: true、storage: trueにしてください。
  2. 同じCRDのv1alpha1スキーマを完成させてください。specオブジェクトにimage(string、必須)、replicas(integer、default: 2、minimum: 1、maximum: 10)、public(boolean、default: false)を定義します。さらにadditionalPrinterColumnsに、名前Image(jsonPath .spec.image、type string)とReplicas(jsonPath .spec.replicas、type integer)の2つの列を追加してください。
  3. ネームスペースtenant-blueを作成してください。ラベルはplatform.labhub.io/tenant: blueとpod-security.kubernetes.io/enforce: baselineです。
  4. tenant-blueにResourceQuota tenant-blue-quotaを作成してください。requests.cpu: "2"、requests.memory: 4Gi、limits.cpu: "4"、limits.memory: 8Gi、pods: "10"を設定します。同じネームスペースにLimitRange tenant-blue-limitsを作成してください。typeはContainer、defaultはcpu 200m / memory 256Mi、defaultRequestはcpu 100m / memory 128Miです。
  5. tenant-blueにWebService shopを作成してください。spec.image: ghcr.io/labhub/shop:1.0.0だけを書き、replicasとpublicは書かないでください。作成したら、もう一度読み出して、2つの値が補われていることを確認してください。
  6. スキーマ違反を確認してください。spec.replicas: 20のWebService badをtenant-blueに作成してみて、その失敗の出力(標準エラー出力を含む)を/root/cnpa-platform/reject.txtに保存してください。badはクラスターに残っていてはいけません。
  7. ServiceAccount blue-devをtenant-blueに作成し、同じネームスペースにRole webservice-editor(apiGroups platform.labhub.io、resources webservices、verbs get,list,watch,create,update,patch,delete)とRoleBinding blue-devs(そのRoleをblue-dev ServiceAccountに結び付けるもの)を作成してください。クォータを変更する権限は与えないでください。
  8. 同じパターンで2つ目のテナントを作成してください。ネームスペースtenant-green(ラベルplatform.labhub.io/tenant: green)、ResourceQuota tenant-green-quota(pods: "10"を含む)、そしてWebService api(spec.image: ghcr.io/labhub/api:1.0.0、replicasは指定しない)です。tenant-blueのblue-devがtenant-greenにはWebServiceを作成できない状態にしてください。

参考

CRDの登録: グループ・スコープ・名前

/root/cnpa-platform/crd.yamlにCustomResourceDefinitionを作成して適用してください。metadata.name: webservices.platform.labhub.io、spec.group: platform.labhub.io、spec.scope: Namespacedとし、spec.namesはkindがWebService、pluralがwebservices、singularがwebservice、shortNamesの最初の項目がwsです。バージョンv1alpha1はserved: true、storage: trueにしてください。

CRDの名前は<복수형>.<그룹>の形式でなければなりません(プレースホルダーは複数形とグループです)。テナントが作るリソースなので、スコープの選択に注意してください。

スキーマとプリンターカラム

同じCRDのv1alpha1スキーマを完成させてください。specオブジェクトにimage(string、必須)、replicas(integer、default: 2、minimum: 1、maximum: 10)、public(boolean、default: false)を定義します。さらにadditionalPrinterColumnsに、名前Image(jsonPath .spec.image、type string)とReplicas(jsonPath .spec.replicas、type integer)の2つの列を追加してください。

OpenAPI v3スキーマは、versions配列の中の各バージョンに付けます。required、minimum/maximum、defaultをそれぞれどこに書くのかを区別してください。プリンターカラムもバージョンごとに定義します。

テナントのネームスペース

ネームスペースtenant-blueを作成してください。ラベルはplatform.labhub.io/tenant: blueとpod-security.kubernetes.io/enforce: baselineです。

ネームスペース自体がテナントの境界です。所属を示すラベルと、Pod Security Standardsのラベルを一緒に付けてください。

ResourceQuotaとLimitRange

tenant-blueにResourceQuota tenant-blue-quotaを作成してください。requests.cpu: "2"、requests.memory: 4Gi、limits.cpu: "4"、limits.memory: 8Gi、pods: "10"を設定します。同じネームスペースにLimitRange tenant-blue-limitsを作成してください。typeはContainer、defaultはcpu 200m / memory 256Mi、defaultRequestはcpu 100m / memory 128Miです。

2つは役割が違います。1つはネームスペース全体の総量の上限で、もう1つは個々のコンテナのデフォルト値と範囲です。両方そろって初めて、「requestを指定していないPod」がクォータを通過します。

CRの作成とサーバーサイドのデフォルト値

tenant-blueにWebService shopを作成してください。spec.image: ghcr.io/labhub/shop:1.0.0だけを書き、replicasとpublicは書かないでください。作成したら、もう一度読み出して、2つの値が補われていることを確認してください。

replicasをまったく書かずに作成してみてください。保存されたオブジェクトを読み直すと、値が入っているはずです。

スキーマ違反が拒否されることの確認

スキーマ違反を確認してください。spec.replicas: 20のWebService badをtenant-blueに作成してみて、その失敗の出力(標準エラー出力を含む)を/root/cnpa-platform/reject.txtに保存してください。badはクラスターに残っていてはいけません。

範囲外の値で作成してみて、そのとき出るエラーメッセージをファイルに残してください。標準エラー出力も一緒に保存する必要があります。

セルフサービスの権限とガードレール

ServiceAccount blue-devをtenant-blueに作成し、同じネームスペースにRole webservice-editor(apiGroups platform.labhub.io、resources webservices、verbs get,list,watch,create,update,patch,delete)とRoleBinding blue-devs(そのRoleをblue-dev ServiceAccountに結び付けるもの)を作成してください。クォータを変更する権限は与えないでください。

新しいリソースにも、既存のRBACがそのまま適用されます。ルールのapiGroupsとresourcesに何を書くかを確認し、クォータには触れられないままにしておいてください。

2つ目のテナントと分離の証明

同じパターンで2つ目のテナントを作成してください。ネームスペースtenant-green(ラベルplatform.labhub.io/tenant: green)、ResourceQuota tenant-green-quota(pods: "10"を含む)、そしてWebService api(spec.image: ghcr.io/labhub/api:1.0.0、replicasは指定しない)です。tenant-blueのblue-devがtenant-greenにはWebServiceを作成できない状態にしてください。

同じパターンをもう一度適用するのがプラットフォームです。そして、最初のテナントの権限が2つ目のテナントには及ばないようにしてください。