kube-rsに入門したい
kubernetesもRustも分からないけどkube-rsに入門したい
適当にしたの動画をやったリポジトリを作った
watcherというので何かしらの変更を監視できる...でいいのかな
watcher,reflector,Controllerは何が違うんだろう
reflectorはwatcherを内部的に持っていることは分かったけど、なんでこれが必要なのかよくわからない。いったん見なかったことにして進める
reflectorはここにあるキャッシュ機構的なものに思える
Controllerにはreconcileという処理を実装すればよいらしい。これが毎回のループで実行されて、いい感じの状態を維持する。。。みたいな雰囲気か
reconcileには理想状態(object)とコントローラーの状態(context)の2つのみから、理想状態を達成するための処理を書く
これを真似てみる
#[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が何とかという記載があったが設定の仕方がわからない
上の通り書いてみるとちゃんとそれっぽいのが出力されてる
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: {}
RBACとかAdmissionWebhookの話があるが、このあたりの認可周りはどうやるんだろう
公式のサンプル実装
関連リソースの指定
ownsとかの意味はこの部分と多分同じ
これをそれっぽく実装してみるとこんな感じ?
かなり汚い感じなので、何かをミスしてる気はする
サンプルを作成したけど何も反応しない...
なんかどっかでエラーが起きてるっぽい
Kube Error: ApiError: invalid object type: /, Kind=: BadRequest (ErrorResponse { status: "Failure", message: "invalid object type: /, Kind=", reason: "BadRequest", code: 400 })
なんかこんな感じのエラー
いくつか修正してこんな感じのエラーになった
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とは?
Cohere君によると次のような感じらしい
このエラーは、API サーバーによって管理される .metadata.managedFields フィールドを手動で更新しようとしたときに発生します。このフィールドを手動で更新しないでください。
パッチ (JSON Merge Patch、Strategic Merge Patch、JSON Patch) または更新 (HTTP PUT) を使用して、オブジェクトからすべての managedFields を削除することができます。言い換えれば、apply 以外のすべての書き込み操作です。これを行うには、managedFields フィールドを空のエントリで上書きします。
つまり、metadata.ManagedFieldsに記載されている個所しか、コントローラは更新できないということなのかな?
一応確認してみると今のmarkdownviewにstatusはない
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: ""
公式のサンプルコードを見ると.forceとかいうのが付いてる
これもしかしてMarkdownViewStatusEnumにDefaultを実装してないからか?
ここを読むと#[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 { .. }
}
Defaultに実装してもダメだった
公式実装に合わせてserde::json!を使ってみたけど更新される様子がない
いったんあきらめる
とりあえずデプロイしてくれるようになった
kubectl port-forward services/viewer-markdownview-sample 3000:80

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で取得できるっぽい
適当なConfigMapにMarkDownViewへの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
同じように設定したつもりだが若干異なる。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
ここがtrueだと親が削除されないようにできるらしい
finalizer
リソースが削除されたときに管理対象外の何かを操作したいときに使うっぽい。ここではPVの削除を遅らせるために使われているらしい