これはKubernetes Advent Calendar 2021 16日目の記事です。
この記事ではKubernetesのソフトマルチテナンシー管理を容易にするツール「Accurate」の内部実装について解説します。
Accurateとは?
Accurateはサイボウズ社のnecoチームが開発しているツールで、主にKubernetesのNamespaceの階層化と、階層化されたNamespace間のリソース伝播機能を提供するKubernetes Operatorになります。
Accurateがどういったツールであるかについての詳細は、以前Kubernetes Meetup Tokyo #47で発表しているので、そちらをご覧ください。
Accurateの全体像
Accurateのドキュメントは以下にあります。
アプリケーションはGoを使って実装されていて内容としては
- Kubernetesに登録するCRD(SubNamespace)
- kubebuilderを利用したOperator(Custom Controller/Webhook)
- Accurateを利用するためのkubectlプラグイン
に区分することができます。
インストール方法としてはhelmが提供されていて、
https://cybozu-go.github.io/accurate/helm.html
kubectlプラグインの方はkrewを使ってインストールすることができます。
https://cybozu-go.github.io/accurate/install-plugin.html
また、Opeator側でwebhookが利用されているので、基本的には事前にcert-managerがインストールされている必要があります。
アプリケーションに関してはOperatorとkubectlプラグインそれぞれがcmdディレクトリ以下にエントリーポイントがありhttps://github.com/cybozu-go/accurate/tree/main/cmd
CRDについてはkubebuilderのデフォルト通りapiディレクトリ以下に定義があります。
https://github.com/cybozu-go/accurate/tree/main/api
CRDの定義だけ知りたいときはドキュメントに記載があるのでそちらを読んだ方が楽です。
https://cybozu-go.github.io/accurate/crd_subnamespace.html
CI/CDに関してはGithub Actionsを利用しており
https://github.com/cybozu-go/accurate/tree/main/.github/workflows
のワークフローを見れば詳細がわかりますが主に
- ユニットテスト
- envtest
- E2Eテスト(3つのKubernetesバージョンでのテスト)
- 自動生成されたコードなどの差分チェック
- helm chartのlinter
あたりがcommit毎にチェックされるようになっています。
(このあたりのテスト密度の高さによる品質担保が本当にすごい)
Operator
前述の通りOperator側は
- Custom Controller
- Webhook
があります。
Operatorは起動時に設定ファイルを引数で渡す必要があり、設定内容に応じて
- 伝播を許可するNamespaceのラベル/アノテーションのキー
- 伝播を行うリソース種別
- 作成を許可するNamespaceの名前制約
といったことが制御できます。
(設定ファイルの例は以下のような内容です)
labelKeys:
- teamannotationKeys:
- metallb.universe.tf/address-poolsubNamespaceLabelKeys:
- appsubNamespaceAnnotationKeys:
- foo.bar/bazwatches:
- group: rbac.authorization.k8s.io
version: v1
kind: Role
- group: rbac.authorization.k8s.io
version: v1
kind: RoleBinding
- version: v1
kind: Secret
- version: v1
kind: ResourceQuotanamingPolicies: []
Accurateは上記の設定内容に応じて
- Namespaceの階層化
- Namespaceのテンプレート化
- 作成する子Namespace名のバリデーション
- 設定に応じたNamespaceへのラベル/アノテーションの伝播
- 設定された種類(e.g. Secret)のリソースを子/テンプレート利用Namespaceへ伝播
を行います。
Custom Controller
Custom Controllerには
- SubNamespaceReconciler
- NamespaceReconciler
- PropagateController
の3種類のコントローラーがあります。
SubNamespaceReconciler
SubNamespaceReconcilerは子Namespaceを作るためのCRD「SubNamespace」リソースのためのReconcilerで、SubNamespaceリソースに応じた子となるNamespaceの作成を担当します。
NamespaceReconciler
NamespaceReconcilerはNamespaceのためのReconcilerで
- 子Namespace
- Templateを利用したNamespace
に対して伝播元となるNamespaceのラベル/アノテーションの伝播を行うためのNamespaceです。
また、Namespaceが子Namespaceでなくなったり、Templateの利用を止めた際に伝播されていたリソースを削除したりといった処理も行います。
PropagateController
PropagateControllerは
- 子Namespace
- Templateを利用したNamespace
に対して、伝播元となるNamespaceで作成された各種リソースから、伝播する設定が行われているリソースの伝播を行います。
コードを読んでいて面白かったのが、伝播してリソースを作成する処理について以下のようになっており、unstructured.Unstructuredインターフェイスを利用することで各種Kubernetesリソースに対する伝播処理を1つのControllerで実装されている点でした。
unstructured.Unstructuredはこんなふうに使うんだなというのが勉強になりました。
func (r *PropagateController) propagateCreate(ctx context.Context, obj *unstructured.Unstructured) error {
logger := log.FromContext(ctx)
children, err := r.getChildren(ctx, obj.GetNamespace())
if err != nil {
return err
}name := obj.GetName()
for _, child := range children.Items {
cres := r.res.DeepCopy()
err := r.Get(ctx, client.ObjectKey{Namespace: child.Name, Name: name}, cres)
if err == nil {
continue
}
if !apierrors.IsNotFound(err) {
return fmt.Errorf("failed to look up %s/%s: %w", child.Name, name, err)
}if err := r.Create(ctx, cloneResource(obj, child.Name)); err != nil {
return fmt.Errorf("failed to create %s/%s: %w", child.Name, name, err)
}logger.Info("created a child resource", "subnamespace", child.Name)
}return nil
}
Webhook
Webhookは
- SubNamespace
- Namespace
に対して設定されています。
SubNamespace
SubNamespaceに対するWebhookは
- mutatorによるfinalizerの自動設定
- SubNamespaceリソースの設定値バリデーション
- Nameing Policyに違反してないかのチェック
などを行います。
Namespace
Namespaceに対するWebhookはAccurateに関するNamespaceの操作に問題ないかのバリデーションを行います。
Accurateは”accurate.cybozu.com/”から始まるラベルやアノテーションをNamespaceなどのリソースに埋め込むことにより、Accurateから見たNamespaceやその他伝播するリソースの属性や設定を管理しています。
バリデーション処理ではリソースの作成や変更内容時に上記の設定などに問題が無いかどうかのチェックを行っています。
kubectlプラグイン
Operator側に比べるとkubectlプラグインの実装はかなりシンプルなので、簡単にまとめます。
kubectlプラグインはgit-style プラグイン機構と言われるPATH
の通ったディレクトリに配置された実行ファイルの名前がkubectl-
で開始しているものを呼び出すというものです。
ですので、kubectlプラグイン自体の実装は通常のCLIツールの実装と同じです。
Accurateの場合はKubernetesの様々なコマンドラインツールで使われているのと同様にcobraが使われています。
コマンドのusageは以下のようになっています。
$ kubectl accurate
accurate is a subcommand of kubectl to manage Accurate features.Usage:
accurate [command]Available Commands:
completion generate the autocompletion script for the specified shell
help Help about any command
list List namespace trees hierarchically
namespace namespace subcommand
sub sub-namespace command
template template subcommand...
completionとhelpを除くとその他は
- list
- namespace
- sub
- template
というサブコマンドの構成となっています。
Namespaceの階層化を行ったり、Template機能を利用する際は
kubectl accurate sub create
kubectl accurate template set
といったコマンドを利用していくことになりますが、これらは内部では
- SubNamespaceの作成や削除
- Namespaceへのラベルやアノテーションの設定
といった操作を実行するという処理が行われています。
まとめ
ということで最後に全体のイメージを図にするとこんな感じです。
(サッと作ったので雑な感じです)