Open39

kube-rsに入門したい

tunamagurotunamaguro
#[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)]
#[kube(
    group = "view.zoetrope.github.io",
    version = "v1",
    kind = "MarkdownView",
    namespaced
)]
#[kube(status = "MarkdownViewStatus")]
pub struct MarkdonwViewSpec {
    pub markdowns: BTreeMap<String, String>,
    pub replicas: u32,
    #[serde(rename = "viewerImage")]
    pub viewer_image: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct MarkdownViewStatus {
    status: MarkdownViewStatusEnum,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub enum MarkdownViewStatusEnum {
    NotReady,
    Available,
    Healthy,
}

こんな感じだろうか。subresourceが何とかという記載があったが設定の仕方がわからない

tunamagurotunamaguro

https://github.com/kube-rs/controller-rs/blob/main/src/crdgen.rs

上の通り書いてみるとちゃんとそれっぽいのが出力されてる

fn main() {
    print!("{}", serde_yaml::to_string(&MarkdownView::crd()).unwrap())
}
cargo run --bin crdgen
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/crdgen`
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: markdownviews.view.zoetrope.github.io
spec:
  group: view.zoetrope.github.io
  names:
    categories: []
    kind: MarkdownView
    plural: markdownviews
    shortNames: []
    singular: markdownview
  scope: Namespaced
  versions:
  - additionalPrinterColumns: []
    name: v1
    schema:
      openAPIV3Schema:
        description: Auto-generated derived type for MarkdonwViewSpec via `CustomResource`
        properties:
          spec:
            properties:
              markdowns:
                additionalProperties:
                  type: string
                type: object
              replicas:
                format: uint32
                minimum: 0.0
                type: integer
              viewerImage:
                type: string
            required:
            - markdowns
            - replicas
            - viewerImage
            type: object
          status:
            nullable: true
            properties:
              status:
                enum:
                - NotReady
                - Available
                - Healthy
                type: string
            required:
            - status
            type: object
        required:
        - spec
        title: MarkdownView
        type: object
    served: true
    storage: true
    subresources:
      status: {}
tunamagurotunamaguro
tunamagurotunamaguro
Kube Error: ApiError: invalid object type: /, Kind=: BadRequest (ErrorResponse { status: "Failure", message: "invalid object type: /, Kind=", reason: "BadRequest", code: 400 })

なんかこんな感じのエラー

tunamagurotunamaguro

いくつか修正してこんな感じのエラーになった

something went wrong: Kube Error: ApiError: metadata.managedFields must be nil: BadRequest (ErrorResponse { status: "Failure", message: "metadata.managedFields must be nil", reason: "BadRequest", code: 400 })

metadata.managedFieldsとは?

tunamagurotunamaguro

Cohere君によると次のような感じらしい

このエラーは、API サーバーによって管理される .metadata.managedFields フィールドを手動で更新しようとしたときに発生します。このフィールドを手動で更新しないでください。

パッチ (JSON Merge Patch、Strategic Merge Patch、JSON Patch) または更新 (HTTP PUT) を使用して、オブジェクトからすべての managedFields を削除することができます。言い換えれば、apply 以外のすべての書き込み操作です。これを行うには、managedFields フィールドを空のエントリで上書きします。

tunamagurotunamaguro

つまり、metadata.ManagedFieldsに記載されている個所しか、コントローラは更新できないということなのかな?

tunamagurotunamaguro

一応確認してみると今のmarkdownviewstatusはない

kubectl get markdownviews.view.zoetrope.github.io -o yaml --show-managed-fields 
apiVersion: v1
items:
- apiVersion: view.zoetrope.github.io/v1
  kind: MarkdownView
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"view.zoetrope.github.io/v1","kind":"MarkdownView","metadata":{"annotations":{},"labels":{"app.kubernetes.io/created-by":"markdown-view","app.kubernetes.io/instance":"markdownview-sample","app.kubernetes.io/managed-by":"kustomize","app.kubernetes.io/name":"markdownview","app.kubernetes.io/part-of":"markdown-view"},"name":"markdownview-sample","namespace":"default"},"spec":{"markdowns":{"SUMMARY.md":"# Summary\n\n- [Page1](page1.md)\n","page1.md":"# Page 1\n\n一ページ目のコンテンツです。\n"},"replicas":1,"viewerImage":"peaceiris/mdbook:latest"}}
    creationTimestamp: "2024-07-08T13:33:11Z"
    generation: 1
    labels:
      app.kubernetes.io/created-by: markdown-view
      app.kubernetes.io/instance: markdownview-sample
      app.kubernetes.io/managed-by: kustomize
      app.kubernetes.io/name: markdownview
      app.kubernetes.io/part-of: markdown-view
    managedFields:
    - apiVersion: view.zoetrope.github.io/v1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:annotations:
            .: {}
            f:kubectl.kubernetes.io/last-applied-configuration: {}
          f:labels:
            .: {}
            f:app.kubernetes.io/created-by: {}
            f:app.kubernetes.io/instance: {}
            f:app.kubernetes.io/managed-by: {}
            f:app.kubernetes.io/name: {}
            f:app.kubernetes.io/part-of: {}
        f:spec:
          .: {}
          f:markdowns:
            .: {}
            f:SUMMARY.md: {}
            f:page1.md: {}
          f:replicas: {}
          f:viewerImage: {}
      manager: kubectl-client-side-apply
      operation: Update
      time: "2024-07-08T13:33:11Z"
    name: markdownview-sample
    namespace: default
    resourceVersion: "7885"
    uid: 757f13e2-3b54-43f0-b098-f5309227e9e5
  spec:
    markdowns:
      SUMMARY.md: |
        # Summary

        - [Page1](page1.md)
      page1.md: |
        # Page 1

        一ページ目のコンテンツです。
    replicas: 1
    viewerImage: peaceiris/mdbook:latest
kind: List
metadata:
  resourceVersion: ""
tunamagurotunamaguro

これもしかしてMarkdownViewStatusEnumDefaultを実装してないからか?

tunamagurotunamaguro

https://docs.rs/kube-derive/latest/kube_derive/derive.CustomResource.html

ここを読むと#[kube(status = "hoge")]Optionで包まれるらしい


#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct FooCrd {
    api_version: String,
    kind: String,
    metadata: ObjectMeta,
    spec: FooSpec,
    status: Option<FooStatus>,
}
impl kube::Resource for FooCrd { .. }

impl FooCrd {
    pub fn new(name: &str, spec: FooSpec) -> Self { .. }
    pub fn crd() -> CustomResourceDefinition { .. }
}
tunamagurotunamaguro

とりあえずデプロイしてくれるようになった

kubectl port-forward services/viewer-markdownview-sample 3000:80

tunamagurotunamaguro
tunamagurotunamaguro

Kubebuilderのほうで紹介されているownerReferenceはkube-rsではこんな感じに書くらしい

let oref = generator.controller_owner_ref(&()).unwrap();
let cm = ConfigMap {
    metadata: ObjectMeta {
        name: generator.metadata.name.clone(),
        owner_references: Some(vec![oref]),
        ..ObjectMeta::default()
    },
    data: Some(contents),
    ..Default::default()
};

このResource::controller_owner_refで取得できるっぽい
https://docs.rs/kube/latest/kube/trait.Resource.html

tunamagurotunamaguro

適当なConfigMapMarkDownViewへのownerReferenceをつけてみるとこんな感じになった

$ kubectl get configmaps markdowns-markdownview-sample -o yaml
apiVersion: v1
data:
  SUMMARY.md: |
    # Summary

    - [Page1](page1.md)
  page1.md: |
    # Page 1

    一ページ目のコンテンツです。
kind: ConfigMap
metadata:
  creationTimestamp: "2024-07-08T14:19:47Z"
  name: markdowns-markdownview-sample
  namespace: default
  ownerReferences:
  - apiVersion: view.zoetrope.github.io/v1
    controller: true
    kind: MarkdownView
    name: markdownview-sample
    uid: 7ec39fcb-d0b3-43bd-a818-e195223a0efd
  resourceVersion: "493"
  uid: 8a41db84-011c-4595-aade-eca7cecc84f0
tunamagurotunamaguro

同じように設定したつもりだが若干異なる。blockOwnerDeletionは何が違うんだろうか

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: "2021-07-25T09:35:43Z"
  name: markdowns-markdownview-sample
  namespace: default
  ownerReferences:
  - apiVersion: view.zoetrope.github.io/v1
    blockOwnerDeletion: true // ここが違う
    controller: true
    kind: MarkdownView
    name: markdownview-sample
    uid: 8e8701a6-fa67-4ab8-8e0c-29c21ae6e1ec
  resourceVersion: "17582"
  uid: 8803226f-7d8f-4632-b3eb-e47dc36eabf3