kubebuilderとは
Kubebuilderは、カスタムリソース定義(CRD)を使ってKubernetes APIを構築するためのフレームワーク。
依存するcontroller-tools,controller-runtimeを用いてコードテンプレ/マニュフェスト群を生成してくれる
注意書き
「kubebuilderはコピペするための例として存在するのではなく、Kubernetes APIをゼロから構築して公開することを簡単にするための強力なライブラリやツールを提供している」
kubebuilderの思想
KubernetesのツールやAPIを構築するには、多くの決定を行い、多くの定型文を書く必要がある。
このkubebuilderでは、カノニカルアプローチを用いてKubernetesのAPIやツールを簡単に構築できるようにするために、Kubernetesの開発ツールをまとめて提供し、労力を最小限に抑えている。
Kubebuilder は、API を構築するための以下のような開発者のワークフローを容易にすることを試みている。
1.新しいプロジェクトディレクトリの作成
2.1つ以上のリソースAPIをCRDとして作成し、リソースにフィールドを追加。
3.コントローラにリコンサイルループを実装し、追加リソースを見る
4.クラスタに対して実行してテストする(CRDをセルフインストールし、コントローラを自動的に起動する
5.新しいフィールドとビジネスロジックをテストするために、ブートストラップされた統合テストを更新。
6.提供されたDockerfileからコンテナをビルドして公開
そもそもCRDって?
k8sのアーキテクチャ
コンポーネントレベルでみると、Master には etcd, kube-apiserver, kubescheduler, etcd, kube-controller-manager, cloud-controller-manager,kube-dns がWorker には kubelet, kube-proxy, Container Runtimeが動いている
api-server
api-server は、kubectl からのリクエストを受けた際に DeploymentやService などのObjectの作成・更新・削除などを⾏う。Resource の作成・更新・削除などを⾏う際は、api-server がリクエストを受け付けて、その Object の情報を etcd に永続化する。scheduler や controller-manager が Resource を操作しようとする 時も、api-server を経由する。 データストアである etcd にアクセスできるのは、api-serverのみ。
Reconciliation Loop
controller-managerがDeploymentやServiceなどのObject管理を行う。controller-manager野中ではDeployment, ServiceなどのControllerが一つのバイナリに纏まっている
ここでk8sのあるべき姿と実際の状態を比較して実際の状態をあるべき状態へと近づけるReconciliation Loopと呼ばれる処理時が実行される。
処理の流れ
1.現在のResourceのStatusを読み込む
2.Desired Stateに合わせてCurrentStateを変更する
3.現在のResourceのStatusを更新する
ReplicaSet ControllerからPodが作成される一連の流れ
1.ReplicaSet Controller は、ReplicaSetが作成されたことを検知し、メインロジックの中で spec.nodeName が空のPodを作成
2. Schedulerがspec.nodeNameが空であることを検知し、Scheduler queueに追加
3. kubeletが新しいPodの存在を検知するが、spec.nodeNameが空なのでコンテナ起動をスキップ
4. SchedulerがPodをScheduler queueから取り出して、スケジューリング可能かつSystem Resourceが充分なNodeにアサインする。アサイン時に、spec.nodeNameをapi-server経由で更新
5. kubeletがPodの更新Eventを検知し、spec.nodeNameが自身のNodeと合致するかを比較。合致していたらコンテナを起動し、api-server 経由でstatusを更新します
6. Pod が(何らかの理由で)Terminating
7. kubeletがapi-server経由で、Podのstatus.condition を"terminated"に更新
8. ReplicaSet ControllerはPodのTerminateを検知し、api-server経由でPodを削除し、新しくPodを生成。
-この処理の繰り返し-
Kubernetes is more jazz improv than orchestration.(By Kubernetes co-founder Jooe Beda)
api-serverが指揮者となって全てを命じるのではなく、各コンポーネントがプレイヤーとなり演奏をし、それらが重なることで即興楽曲のように成立している
CRDとは
k8sでは、表中のResourceに加え、ユーザーが独自のResourceを定義し、クラスタ上で利用できる。それがCRD(Custom Resource Definition)
sample CRD
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.2.5
creationTimestamp: null
name: guestbooks.webapp.my.domain
spec:
group: webapp.my.domain
names:
kind: Guestbook
listKind: GuestbookList
plural: guestbooks
singular: guestbook
scope: Namespaced
validation:
openAPIV3Schema:
description: Guestbook is the Schema for the guestbooks API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: GuestbookSpec defines the desired state of Guestbook
properties:
foo:
description: Foo is an example field of Guestbook. Edit Guestbook_types.go
to remove/update
type: string
type: object
status:
description: GuestbookStatus defines the observed state of Guestbook
type: object
type: object
......
CRDの作成
kubectl apply -f webapp.my.domain_guestbooks.yaml
kubectl get crd
NAME CREATED AT
guestbooks.webapp.my.domain 2020-07-19T18:03:39Z
ただし、コントローラがなければ何も効果がないObjectが生成されるだけ。
ControllerとCRDを自作するために
kubebuilder以外のCRD作成手段
- Operator SDK
プロジェクトテンプレート生成、ビルド、デプロイをするCLIツール。AnsibleでもOperatorを書けるのが面白い。Operator FrameworkとしてLifecycle Managerなどが提供されていたり、OperatorHub.ioというコミュニティサイトがあったり、エコシステムが充実している。kubebuilder同様必要なもの一式が提供される。Helm Chart,Ansibleなどのサポートもある
- Kubernetes way
Client-go,code-generatorを使用する方法(Kubernetes内部にある既存のControllerの多くがこの方法で実装されており、伝統的らしい)低レベルAPIを扱うため、実装の自由度が高いが覚えることがたくさんある。
Kubebuilderを使ってみる
インストール
os=$(go env GOOS)
arch=$(go env GOARCH)
# download kubebuilder and extract it to tmp
curl -L https://go.kubebuilder.io/dl/2.3.1/${os}/${arch} | tar -xz -C /tmp/
# move to a long-term location and put it on your path
# (you'll need to set the KUBEBUILDER_ASSETS env var if you put it somewhere else)
sudo mv /tmp/kubebuilder_2.3.1_${os}_${arch} /usr/local/kubebuilder
export PATH=$PATH:/usr/local/kubebuilder/bin
アプリケーションの作成
kubebuilder init --domain my.domain
kubebuilder create api --group webapp --version v1 --kind Guestbook
## 以下のようなファイルが生成される
.
├── Dockerfile
├── Makefile
├── PROJECT
├── api
│ └── v1
│ ├── groupversion_info.go
│ ├── guestbook_types.go
│ └── zz_generated.deepcopy.go
├── bin
│ └── manager
├── config
│ ├── certmanager
│ │ ├── certificate.yaml
│ │ ├── kustomization.yaml
│ │ └── kustomizeconfig.yaml
│ ├── crd
│ │ ├── kustomization.yaml
│ │ ├── kustomizeconfig.yaml
│ │ └── patches
│ │ ├── cainjection_in_guestbooks.yaml
│ │ └── webhook_in_guestbooks.yaml
│ ├── default
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ ├── manager_webhook_patch.yaml
│ │ └── webhookcainjection_patch.yaml
│ ├── manager
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ ├── rbac
│ │ ├── auth_proxy_client_clusterrole.yaml
│ │ ├── auth_proxy_role.yaml
│ │ ├── auth_proxy_role_binding.yaml
│ │ ├── auth_proxy_service.yaml
│ │ ├── guestbook_editor_role.yaml
│ │ ├── guestbook_viewer_role.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ └── role_binding.yaml
│ ├── samples
│ │ └── webapp_v1_guestbook.yaml
│ └── webhook
│ ├── kustomization.yaml
│ ├── kustomizeconfig.yaml
│ └── service.yaml
├── controllers
│ ├── guestbook_controller.go
│ └── suite_test.go
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
└── main.go
-
api/
CRDに相当するtypeを書く。これをもとにCRD manifestが生成される
生成されるテンプレをもとに定義したいspec,statusをかく -
controllers/
Reconcile 関数にロジックを書く
生成されるテンプレレートをもとにcontroller-runtimeを使って実装
-config
各種manifestファイル、kustomizeのAppが生成される
ソースに書いたアノテーションをもとにcontroller-toolsが生成してくれる
実行
make install
# Install CRDs into a cluster
install: manifests
kustomize build config/crd | kubectl apply -f -
make run
# Run against the configured Kubernetes cluster in ~/.kube/config
run: generate fmt vet manifests
go run ./main.go
controller-toolsとcontroller-runtime
controller-tools
controller-toolsには内部にcontroller-genというコマンドがあり、これがKubernetesマニフェスト群などを生成してくれる。
controller-genがGoファイルのコードを解析して自動生成する
// +kubebuilder:object:root=trueのような箇所が解析対象であることを示している。
// +kubebuilder:object:root=true
// Guestbook is the Schema for the guestbooks API
type Guestbook struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec GuestbookSpec `json:"spec,omitempty"`
Status GuestbookStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// GuestbookList contains a list of Guestbook
type GuestbookList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Guestbook `json:"items"`
}
controller-runtime
Kubernetes CRD と集約/組み込みの Kubernetes API の両方を操作する Kubernetes スタイルのコントローラを構築するためのツールを提供
Kubernetes API を実装しており、Operator、Workload API、Configuration API、Autoscalers などを構築するための基盤になっている。
controller-runtimeを利用することで、実装stageがk8s特有のコンポーネントを意識して実装する必要がなくなる。
Controller-Manager
controller-managerが複数のCustom Controllerを監督する
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
//Manager作成
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Port: 9443,
//リーダー選出機能
LeaderElection: enableLeaderElection,
LeaderElectionID: "bce3f8f2.my.domain",
})
if err != nil {
setupLog.Error(err, "unable to start manager")
os.Exit(1)
}
if err = (&controllers.GuestbookReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Guestbook"),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Guestbook")
os.Exit(1)
}
//guestbook_controller.go
func (r *GuestbookReconciler) SetupWithManager(mgr ctrl.Manager) error {
//監視のリソースを指定これによりEventが監視対象になる。これによりEvent発生時にReconcile処理が呼び出される
return ctrl.NewControllerManagedBy(mgr).
For(&webappv1.Guestbook{}).
Complete(r)
}
Reconcile関数
// +kubebuilder:rbac:groups=webapp.my.domain,resources=guestbooks,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=webapp.my.domain,resources=guestbooks/status,verbs=get;update;patch
func (r *GuestbookReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
_ = context.Background()
_ = r.Log.WithValues("guestbook", req.NamespacedName)
// your logic here
return ctrl.Result{}, nil
}
Controller起動中はこの関数のLoopが延々と続く
どのようにAPIをデザインしていくかby公式(直訳)
Kubernetesでは、APIの設計方法にいくつかのルールがあるシリアル化されたフィールドはすべてキャメルケースでなければならないので、これを指定するためにJSON構造タグを使用する。また、フィールドが空の場合はシリアライズから省略されるべきであることをマークするために omitempty 構造タグを使用することも可能。
フィールドはほとんどのプリミティブ型を使用することができるが、数値は例す。API の互換性のために、整数には int32 と int64、小数には resource.Quantityの3つの形式の数値を受け入れている。
もう一つの特別な型がある。それは metav1.Time。固定されたポータブルなシリアル化フォーマットを持っていることを除いて、time.Timeと同じように機能する
基本的にCronJobに必要な要素。
- スケジュール(CronJobのcron)
- 実行するジョブのテンプレート(CronJob内のジョブ)
- ユーザーの生活が楽になるようなおまけもいくつか欲しいところです。
- 仕事を開始するための期限(この期限を逃すと、次の予定時間まで待つことになります
- 複数のジョブが一度に実行される場合はどうすればいいのか(待つのか、古いものを止めるのか、両方実行するのか?)
- 何か問題がある場合に備えて、CronJobの実行を一時停止する手段
追加のメタデータを指定するために、いくつかのマーカー (// +comment) を使用する。これらは、CRD マニフェストを生成する際に controller-tools によって使用される。GoDocの書き方も使える