Accurateの内部実装

bells17
12 min readDec 15, 2021

--

これは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:
- team
annotationKeys:
- metallb.universe.tf/address-pool
subNamespaceLabelKeys:
- app
subNamespaceAnnotationKeys:
- foo.bar/baz
watches:
- 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: ResourceQuota
namingPolicies: []

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へのラベルやアノテーションの設定

といった操作を実行するという処理が行われています。

まとめ

ということで最後に全体のイメージを図にするとこんな感じです。
(サッと作ったので雑な感じです)

Accurate Architecture Overview

--

--