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

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

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/

riita10069

November 05, 2021
Tweet

More Decks by riita10069

Other Decks in Technology

Transcript

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

    View Slide

  2. Ryota Yamada riita10069
    Tokyo Institute of Technology
    Working on Kubernetes
    Interested in Distributed Systems, TLA+

    View Slide

  3. Kubernetes
    使っていますよね?

    View Slide

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

    View Slide

  5. 宣⾔型アプローチによる

    ⾼い管理⼒
    Reconcile Loopによる

    ⾼い回復⼒
    ダウンタイムのない

    デプロイ
    ネットワークレイヤを含む

    ⾼い可観測性
    Kubernetesのすごいところ

    View Slide

  6. 真の⼒には
    その拡張性が伴う
    w w w

    View Slide

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

    View Slide

  8. Kubernetesの拡張性がすごい
    ,VCFSOFUFT%BUB1MBOF
    LVCFMFU
    DPOUBJOFSE
    $POUBJOFS3VOUJNF*OUFSGBDF $3*

    SVOD SVOD SVOD
    0QFO$POUBJOFS*OJUJBUJWF 0$*

    IUUQTPQFODPOUBJOFSTPSH
    IUUQTLVCFSOFUFTJPCMPHDPOUBJOFSSVOUJNFJOUFSGBDFDSJJOLVCFSOFUFT
    IUUQTRJJUBDPNNBNPNBNPJUFNTFEECBCGB

    View Slide

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

    View Slide

  10. Kubernetes API とは
    ,VCFSOFUFT%BUB1MBOF
    ,VCFSOFUFT$POUSPM1MBOF
    LVCFBQJTFSWFS LVCFMFU
    $POUBJOFS

    SVOUJNF
    LVCFDUM

    View Slide

  11. Kubernetes API の拡張
    Aggregation

    Layer
    Custom
    Resources
    APIリソースを追加 Kubernetesリソースを追加
    ⾼い⾃由度を誇る 組み込みリソースと同様に
    IUUQTLVCFSOFUFTJPKBEPDTDPODFQUTFYUFOELVCFSOFUFTBQJFYUFOTJPOBQJTFSWFSBHHSFHBUJPO
    IUUQTLVCFSOFUFTJPKBEPDTDPODFQUTFYUFOELVCFSOFUFTBQJFYUFOTJPODVTUPNSFTPVSDFT

    View Slide

  12. カスタムコントローラーの
    ⾃動テストをCIで動かしてますか
    w w w w

    View Slide

  13. なぜテストが難しいのか
    多くのコンポーネントで構成され

    実際に動かすのが困難
    IUUQTLVCFSOFUFTJPKBEPDTDPODFQUTPWFSWJFXDPNQPOFOUT

    View Slide

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

    View Slide

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

    View Slide

  16. fake-client
    IUUQTHJUIVCDPN[email protected]UFTUHP
    IUUQTCFMMTNFEJVNDPNLVCFSOFUFTDMJFOUHPTGBLFDMJFOUBECFGDC
    IUUQTQLHHPEFWLTJPDMJFOUHPLVCFSOFUFTGBLF/FX4JNQMF$MJFOUTFU
    _, err := fakeClient.CoreV1().Pods("namespace1").Create(pod)

    View Slide

  17. fake-client Reactorの登録
    IUUQTHJUIVCDPN[email protected]UFTUHP
    IUUQTCFMMTNFEJVNDPNLVCFSOFUFTDMJFOUHPTGBLFDMJFOUBECFGDC
    IUUQTQLHHPEFWLTJPDMJFOUHPLVCFSOFUFTGBLF/FX4JNQMF$MJFOUTFU
    fakeClient.PrependReactor("get", "customResource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
    WFSC SFTPVSDF

    View Slide

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

    View Slide

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

    View Slide

  20. setup-envtest
    IUUQTQLHHPEFWTJHTLTJPDPOUSPMMFSSVOUJNFUPPMTTFUVQFOWUFTU
    • envtest binaries manager
    • kubeapi-server, etcd, kubectl のバイナリを管理
    • curl, tarを使うとk8sやこれらのバージョン管理が煩雑
    • ポータビリティの向上

    View Slide

  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(
    )

    }()
    )

    }

    View Slide

  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
    ,

    })

    View Slide

  23. envtest
    • Controller-runtimeが提供するテスト⽤のパッケージ
    • kube-apiserverとetcdのバイナリを実際に⽴てる
    • kube-apiserverリソース操作のみしか再現できない
    • Podとしてコントローラーを動作することができない
    Pros.
    IUUQTCPPLLVCFCVJMEFSJPSFGFSFODFFOWUFTUIUNM
    IUUQTQLHHPEFWHJUIVCDPNLVCFSOFUFTTJHTDPOUSPMMFSSVOUJNFQLHFOWUFTU
    IUUQTHJUIVCDPNLVCFSOFUFTTJHTDPOUSPMMFSSVOUJNFUSFFNBTUFSQLHFOWUFTU
    Cons.

    View Slide

  24. 構築が容易で使い捨て可能な

    テスト⽤のKubernetesが欲しくなる
    w w w w w w

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  29. かなり⼤変な実装

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  33. KETがやってくれること

    View Slide

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

    View Slide

  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.
    テストシナリオの実⾏

    View Slide

  36. 真の⼒には
    その拡張性が伴う
    w w w

    View Slide

  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

    }
    サポートされていないコマンドの作成

    View Slide

  38. IUUQTFOHJOFFSJOHNFSDBSJDPNCMPHFOUSZGCC

    View Slide

  39. IUUQTXXXZPVUVCFDPNXBUDI WV&RV+#W[H

    View Slide

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

    View Slide

  41. View Slide