Upgrade to Pro — share decks privately, control downloads, hide ads and more …

#CNDT2021 Kubernetes コントローラーを手軽に自動テストする / Running e2e tests for Kubernetes controllers in CI with #CNDT2021

Abde1cc59b4baaec3c12d65581c5d017?s=47 riita10069
November 05, 2021

#CNDT2021 Kubernetes コントローラーを手軽に自動テストする / Running e2e tests for Kubernetes controllers in CI with #CNDT2021

Kubernetesのカスタムコントローラーに対する自動テストを記述し、CI上で実行するというテーマでの発表です。
Kubernetesは非常に複雑なコンポーネントで成り立っていて、テストのための環境のポータビリティが低く、CIでも手元のMacでも、複数の開発者のPCでも実行したいという要望に答えるのが難しいです。
それに対する回答として、3つの手段を提案しています。
それが、fake-client, envtest, ket の3つです。
それらの使い方や特徴の違いなどについて説明しています。

Keyword:
client-go, fake, fake-client, envtest, setup-envtest, kind, skaffold, kubectl, e2e, test, ket, Kubernetes, Custom Controller, Operator

登壇内容:
https://event.cloudnativedays.jp/cndt2021/talks/1244

参考:
https://engineering.mercari.com/blog/entry/20210831-f666b94b24/
https://pkg.go.dev/k8s.io/client-go/kubernetes/fake
https://github.com/kubernetes-sigs/controller-runtime/tree/master/pkg/envtest
https://github.com/riita10069/ket
https://mercari.connpass.com/event/227024/

Abde1cc59b4baaec3c12d65581c5d017?s=128

riita10069

November 05, 2021
Tweet

Transcript

  1. ,VCFSOFUFTίϯτϩʔϥʔ Λखܰʹࣗಈςετ͢Δ /PWFNCFS  !SJJUB

  2. Ryota Yamada riita10069 Tokyo Institute of Technology Working on Kubernetes

    Interested in Distributed Systems, TLA+
  3. Kubernetes 使っていますよね?

  4. 超便利!! 何がどう便利?

  5. 宣⾔型アプローチによる 
 ⾼い管理⼒ Reconcile Loopによる 
 ⾼い回復⼒ ダウンタイムのない 
 デプロイ

    ネットワークレイヤを含む 
 ⾼い可観測性 Kubernetesのすごいところ
  6. 真の⼒には その拡張性が伴う w w w

  7. Kubernetesの拡張性がすごい • コンテナの仕様拡張をサポート(CRI, CNI, CSI) • カスタムスケジューラプラグイン • Validating/Mutating Admission

    WebHook • kube api serverの拡張
  8. Kubernetesの拡張性がすごい ,VCFSOFUFT%BUB1MBOF LVCFMFU DPOUBJOFSE $POUBJOFS3VOUJNF*OUFSGBDF $3* SVOD SVOD SVOD 0QFO$POUBJOFS*OJUJBUJWF

    0$* IUUQTPQFODPOUBJOFSTPSH IUUQTLVCFSOFUFTJPCMPHDPOUBJOFSSVOUJNFJOUFSGBDFDSJJOLVCFSOFUFT IUUQTRJJUBDPNNBNPNBNPJUFNTFEECBCGB
  9. Kubernetesの拡張性がすごい • コンテナの仕様拡張をサポート(CRI, CNI, CSI) • カスタムスケジューラプラグイン • Validating/Mutating Admission

    WebHook • kube api serverの拡張
  10. Kubernetes API とは ,VCFSOFUFT%BUB1MBOF ,VCFSOFUFT$POUSPM1MBOF LVCFBQJTFSWFS LVCFMFU $POUBJOFS 
 SVOUJNF

    LVCFDUM
  11. Kubernetes API の拡張 Aggregation 
 Layer Custom Resources APIリソースを追加 Kubernetesリソースを追加

    ⾼い⾃由度を誇る 組み込みリソースと同様に IUUQTLVCFSOFUFTJPKBEPDTDPODFQUTFYUFOELVCFSOFUFTBQJFYUFOTJPOBQJTFSWFSBHHSFHBUJPO IUUQTLVCFSOFUFTJPKBEPDTDPODFQUTFYUFOELVCFSOFUFTBQJFYUFOTJPODVTUPNSFTPVSDFT
  12. カスタムコントローラーの ⾃動テストをCIで動かしてますか w w w w

  13. なぜテストが難しいのか 多くのコンポーネントで構成され 
 実際に動かすのが困難 IUUQTLVCFSOFUFTJPKBEPDTDPODFQUTPWFSWJFXDPNQPOFOUT

  14. より本番環境に近い GBLFDMJFOU FOWUFTU LFU ࣮Ϋϥελ Kubernetes Controller のテスト

  15. fake-client • Client-goのモッククライアント • Kube-apiserverの実態をロジックから隠蔽可能 IUUQTQLHHPEFWLTJPDMJFOUHPLVCFSOFUFTGBLF

  16. fake-client IUUQTHJUIVCDPNLVCFSOFUFTDMJFOUHPCMPCEFEBBBDDECDBEFGBCBBFYBNQMFTGBLFDMJFOUNBJO@UFTUHP IUUQTCFMMTNFEJVNDPNLVCFSOFUFTDMJFOUHPTGBLFDMJFOUBECFGDC IUUQTQLHHPEFWLTJPDMJFOUHPLVCFSOFUFTGBLF/FX4JNQMF$MJFOUTFU _, err := fakeClient.CoreV1().Pods("namespace1").Create(pod)

  17. fake-client Reactorの登録 IUUQTHJUIVCDPNLVCFSOFUFTDMJFOUHPCMPCEFEBBBDDECDBEFGBCBBFYBNQMFTGBLFDMJFOUNBJO@UFTUHP IUUQTCFMMTNFEJVNDPNLVCFSOFUFTDMJFOUHPTGBLFDMJFOUBECFGDC IUUQTQLHHPEFWLTJPDMJFOUHPLVCFSOFUFTGBLF/FX4JNQMF$MJFOUTFU fakeClient.PrependReactor("get", "customResource", func(action clienttesting.Action) (handled

    bool, ret runtime.Object, err error) { WFSC SFTPVSDF
  18. fake-client • Client-goのモッククライアント • Kube-apiserverの実態をロジックから隠蔽可能 • モックの更新管理が必要になる • モックを使ったテストでは、本番の挙動を保証できない IUUQTQLHHPEFWLTJPDMJFOUHPLVCFSOFUFTGBLF

    Cons. Pros.
  19. envtest • controller-runtimeが提供するテスト⽤のパッケージ • kube-apiserverとetcdのバイナリを実際に⽴てる IUUQTCPPLLVCFCVJMEFSJPSFGFSFODFFOWUFTUIUNM IUUQTQLHHPEFWHJUIVCDPNLVCFSOFUFTTJHTDPOUSPMMFSSVOUJNFQLHFOWUFTU IUUQTHJUIVCDPNLVCFSOFUFTTJHTDPOUSPMMFSSVOUJNFUSFFNBTUFSQLHFOWUFTU

  20. setup-envtest IUUQTQLHHPEFWTJHTLTJPDPOUSPMMFSSVOUJNFUPPMTTFUVQFOWUFTU • envtest binaries manager • kubeapi-server, etcd, kubectl

    のバイナリを管理 • curl, tarを使うとk8sやこれらのバージョン管理が煩雑 • ポータビリティの向上
  21. envtestの使⽤例 func TestMain(m *testing.M) { os.Exit(func() int { cli, done,

    err := testutil.TestK8SClient( ) if err != nil { fmt.Fprintf(os.Stdout, "failed to create k8s client: %s\n", err ) return 1 } defer done( ) k8sClient = cl i return m.Run( ) }() ) }
  22. envtestの使⽤例 _, file, _, _ := runtime.Caller(0 ) testEnv :=

    envtest.Environment { BinaryAssetsDirectory: filepath.Join(path.Dir(file), "..", "..", "..", "_dev", "bin") , CRDDirectoryPaths: []string{filepath.Join(path.Dir(file), "..", "..", "..", "_kubernetes", “kube-github-operator-api", "apis", "v1alpha1", "crd")} , ControlPlaneStartTimeout: 20 * time.Second , ErrorIfCRDPathMissing: true , AttachControlPlaneOutput: false , KubeAPIServerFlags: []string { "--advertise-address=127.0.0.1" , "--etcd-servers={{ if .EtcdURL }}{{ .EtcdURL.String }}{{ end }}" , "--cert-dir={{ .CertDir }}" , "--insecure-port={{ if .URL }}{{ .URL.Port }}{{else}}0{{ end }}" , "{{ if .URL }}--insecure-bind-address={{ .URL.Hostname }}{{ end }}" , "--secure-port={{ if .SecurePort }}{{ .SecurePort }}{{ end }}", "--disable-admission-plugins=ServiceAccount" , "--service-cluster-ip-range=10.0.0.0/24" , "--allow-privileged=true" , } , } cfg, err := testEnv.Start( ) if err != nil { return nil, nil, fmt.Errorf("failed to start test env: %w", err ) } cli, err := client.New(cfg, client.Options { Scheme: s , })
  23. envtest • Controller-runtimeが提供するテスト⽤のパッケージ • kube-apiserverとetcdのバイナリを実際に⽴てる • kube-apiserverリソース操作のみしか再現できない • Podとしてコントローラーを動作することができない Pros.

    IUUQTCPPLLVCFCVJMEFSJPSFGFSFODFFOWUFTUIUNM IUUQTQLHHPEFWHJUIVCDPNLVCFSOFUFTTJHTDPOUSPMMFSSVOUJNFQLHFOWUFTU IUUQTHJUIVCDPNLVCFSOFUFTTJHTDPOUSPMMFSSVOUJNFUSFFNBTUFSQLHFOWUFTU Cons.
  24. 構築が容易で使い捨て可能な 
 テスト⽤のKubernetesが欲しくなる w w w w w w

  25. https://github.com/kubernetes-sigs/kind Kind

  26. Kind • DockerコンテナとしてKubernetesのノードを起動 • 実際のクラスタと同じように振る舞うことができる • リソースやコントローラーのデプロイが必要 • テストフローの構築が⼤変 Pros.

    Cons.
  27. Kindでのe2eテストフロー クラスタのセットアップ コントローラーのビルド・デプロイ 必要なツールのインストール テストシナリオの実⾏

  28. Kindでのe2eテストフロー クラスタのセットアップ コントローラーのビルド・デプロイ 必要なツールのインストール テストシナリオの実⾏ Kind, kubectl, skaffoldなどのインストール Kubernetesクラスタを⽴ち上げ、必要なリソース(Namespace, CRDなど)を作成

    Docker build したものをImageとしてPodへ反映 クラスタを操作し、適切なリソースの状態を再現する
  29. かなり⼤変な実装

  30. https://github.com/riita10069/ket

  31. KETがやってくれること クラスタのセットアップ コントローラーのビルド・デプロイ 必要なツールのインストール テストシナリオの実⾏ Kind, kubectl, skaffoldなどのインストール Kubernetesクラスタを⽴ち上げ、必要なリソース(Namespace, CRDなど)を作成

    Docker build したものをImageとしてPodへ反映 クラスタを操作し、適切なリソースの状態を再現する
  32. KETがやってくれること クラスタのセットアップ コントローラーのビルド・デプロイ 必要なツールのインストール テストシナリオの実⾏ Kind, kubectl, skaffoldなどのインストール Kubernetesクラスタを⽴ち上げ、必要なリソース(Namespace, CRDなど)を作成

    Docker build したものをImageとしてPodへ反映 クラスタを操作し、適切なリソースの状態を再現する
  33. KETがやってくれること

  34. Kindでのe2eテストフロー クラスタのセットアップ コントローラーのビルド・デプロイ 必要なツールのインストール テストシナリオの実⾏ Kind, kubectl, skaffoldなどのインストール Kubernetesクラスタを⽴ち上げ、必要なリソース(Namespace, CRDなど)を作成

    Docker build したものをImageとしてPodへ反映 クラスタを操作し、適切なリソースの状態を再現する
  35. for _, tt := range tests { tt := t

    t t.Run(tt.name, func(t *testing.T) { ctx := context.Background( ) err := kubectl.ApplyAllManifest(ctx, tt.fixture.manifestPaths, false ) for _, expect := range tt.res.A.Items { // check expec t } err = kubectl.DeleteAllManifest(ctx, tt.fixture.manifestPaths, true ) } ) } 1st, Create resources “declaratively” Maybe notify informer of the change. 2nd, Make sure the behavior of the Controller. 3rd, Restore the state of the resource. テストシナリオの実⾏
  36. 真の⼒には その拡張性が伴う w w w

  37. func (k *Kubectl) ApplyFile(ctx context.Context, filePath string) error { args

    := []string { "apply" , "-f" , filePath , } err := k.Execute(ctx, args ) if err != nil { return err } return ni l } サポートされていないコマンドの作成
  38. サポートされていないCLIツールの追加 https://github.com/riita10069/ket/blob/99f18c37c88c73b8108b979c37368786b1636b8a/pkg/cli/cli.go#L8 All CLIs implement the interface https://github.com/riita10069/ket/blob/99f18c37c88c73b8108b979c37368786b1636b8a/pkg/cli/run.go#L12 Run() using

    the interface If not exist the cli’s binary, install it.
  39. サポートされていないCLIツールの追加 https://github.com/riita10069/ket/blob/99f18c37c88c73b8108b979c37368786b1636b8a/pkg/ska ff old/ska ff old.go#L15 Implement to implement the

    interface
  40. IUUQTFOHJOFFSJOHNFSDBSJDPNCMPHFOUSZGCC

  41. IUUQTXXXZPVUVCFDPNXBUDI WV&RV+#W[H

  42. まとめ より本番環境に近い GBLFDMJFOU FOWUFTU LFU ࣮Ϋϥελ 適切な試験を⾏えるツールを選ぶ

  43. None