TT Lab
はじめる
学ぶ 学習パス コース

Kubernetesディストリビューション — 自分で立てる

認定ロゴ付きの k3s が適合性テストに落ちた

TT Labで続きを見る

目標

バージョンを固定したk3sで、Kubernetes公式の適合性テストを実際にいくつか選んで実行し、JUnitの結果を読んで、合格・失敗・タイムアウトを区別します。 適合性テストが何を確認し、何を確認しないかを、結果で説明できるようになります。

なぜ重要なのか

ディストリビューションを選ぶとき、「Certified Kubernetes」のロゴは強いシグナルに見えます。しかしその認定は、GAで必須のAPIと動作がアップストリームと同じであることを、テストスイート1つで確認した結果であり、テストにはノード2台以上のような前提があります。 性能・可用性・セキュリティ設定・オプション機能は、範囲外です。ロゴを正しく読むには、テストが何でできていて、失敗がどんな形で記録されるかを自分で見る必要があります。また、テストバイナリとサーバーのバージョンがずれると結果そのものが無意味になるので、バージョンを合わせることから始めます。最後に、わざとDNSを壊して、同じテストが不合格になり、復旧後に再び通過するのを見ると、適合性テストを「復旧の確認ツール」としても使えることがわかります。

ステップ

  1. 次のフィールドを書いてください(書き込み先: /root/conformance/versions.json)。server(APIサーバーのgitVersion)、server_minor(1.36の形式)、e2e_test(e2e.test --versionの出力)、ginkgo(ginkgo versionのバージョン番号だけ。例: 2.0.0)、same_minor(サーバーとe2e.testのマイナーバージョンが同じかどうか、ブール値)です。
  2. /usr/local/conformance/conformance.yaml(v1.36.4タグの一覧)を読み取り、次のフィールドを書いてください(書き込み先: /root/conformance/catalog.json)。total(項目数)、sig_network(codenameが[sig-network]で始まる項目の数)、dns_tests(codenameが[sig-network] DNSで始まるcodenameをソートした配列)、dns_cluster_release([sig-network] DNS should provide DNS for the cluster [Conformance]のreleaseの値)です。
  3. e2e.testを--ginkgo.dry-runで2回実行し、次のフィールドを書いてください(書き込み先: /root/conformance/dryrun.json)。conformance_will_run(focusが\[Conformance\]のときに実行されるspecの数)、total_specs(全体のspecの数)、dns_will_run(focusが\[sig-network\] DNS.*\[Conformance\]のときに実行される数)、matches_catalog(conformance_will_runがステップ2のtotalと同じかどうか、ブール値)です。
  4. [sig-network] DNS should provide DNS for the cluster [Conformance]だけをfocusにして実行し、JUnitの結果を残し(--report-dir、保存先: /root/conformance/dns-pass/junit_01.xml)、標準出力とエラー出力も残してください(保存先: /root/conformance/dns-pass/e2e.log)。通過する必要があります。
  5. [sig-architecture] Conformance Tests should have at least two untainted nodes [Conformance]を実行して、結果を残し(保存先: /root/conformance/two-nodes/junit_01.xml、/root/conformance/two-nodes/e2e.log)、次のフィールドを書いてください(書き込み先: /root/conformance/two-nodes.json)。status(JUnitのそのtestcaseのstatus)、reason(e2e.logの[FAILED]の行のうち、ソースの位置(in [It] - ...)ではなく理由の文が書かれた行の文)、schedulable_nodes(現在テイントのないReadyノードの数、数値)です。
  6. kube-systemのcoredns Deploymentを0に減らし、Podが消えたことを確認してから、ステップ4と同じDNSテストを--ginkgo.timeout=45sで実行して、結果を残してください(保存先: /root/conformance/dns-broken/junit_01.xml、/root/conformance/dns-broken/e2e.log)。次のフィールドを書きます(書き込み先: /root/conformance/broken.json)。coredns_replicas(実行直前のspec.replicas)、coredns_pods(実行直前のCoreDNSのPodの数)、status(JUnitのそのtestcaseのstatus)です。復旧は次のステップで行います。
  7. corednsを1に戻してAvailableにしてから、同じDNSテストをもう一度実行して、結果を残してください(保存先: /root/conformance/dns-restored/junit_01.xml、/root/conformance/dns-restored/e2e.log)。通過する必要があります。
  8. 次のフィールドを書いてください(書き込み先: /root/conformance/report.json)。server(サーバーのgitVersion)、catalog_total(ステップ2のtotal)、passed(ステップ4と7で合格したtestcase名を、[It] なしで、重複なしにソートした配列)、failed_single_node(ステップ5で不合格になったテストのcodename)、timed_out_when_broken(ステップ6の結果がタイムアウトだったかどうか、ブール値)、submission_files(CNCFの認定PRに入れるファイル名4つをソートした配列)、certified_focus(認定のための実行で求められるE2E_FOCUSの値をそのまま)、skip_allowed(認定のための実行でE2E_SKIPを指定できるかどうか、ブール値)です。

参考

テストバイナリとサーバーのバージョンを合わせる

次のフィールドを書いてください(書き込み先: /root/conformance/versions.json)。server(APIサーバーのgitVersion)、server_minor(1.36の形式)、e2e_test(e2e.test --versionの出力)、ginkgo(ginkgo versionのバージョン番号だけ。例: 2.0.0)、same_minor(サーバーとe2e.testのマイナーバージョンが同じかどうか、ブール値)です。

テストバイナリは/usr/local/conformanceにあります。k3sのバージョンには、+k3s1のような末尾の印が付きます。適合性テストはバージョンごとに一覧が変わるので、クラスターのバージョンと同じリリースブランチから作ったテストを使わないと、結果に意味がありません。

適合性テストの一覧を読み取る

/usr/local/conformance/conformance.yaml(v1.36.4タグの一覧)を読み取り、次のフィールドを書いてください(書き込み先: /root/conformance/catalog.json)。total(項目数)、sig_network(codenameが[sig-network]で始まる項目の数)、dns_tests(codenameが[sig-network] DNSで始まるcodenameをソートした配列)、dns_cluster_release([sig-network] DNS should provide DNS for the cluster [Conformance]のreleaseの値)です。

YAMLなので、codenameが複数行に折りたたまれている項目があります。grepで行を数えると間違うので、python3のyamlモジュールで読み取ってください。項目ごとに、testname・codename・description・release・fileのキーがあります。releaseは、そのテストが適合性に入ったバージョンです。

実行する前に範囲を数える

e2e.testを--ginkgo.dry-runで2回実行し、次のフィールドを書いてください(書き込み先: /root/conformance/dryrun.json)。conformance_will_run(focusが\[Conformance\]のときに実行されるspecの数)、total_specs(全体のspecの数)、dns_will_run(focusが\[sig-network\] DNS.*\[Conformance\]のときに実行される数)、matches_catalog(conformance_will_runがステップ2のtotalと同じかどうか、ブール値)です。

dry-runは、クラスターに何も作らずに、どのspecが選ばれるかだけを表示します。出力のWill run N of M specsの行を読み取ります。--ginkgo.no-colorを指定すると、色のコードが混ざりません。

適合性テストを1つ実際に実行する

[sig-network] DNS should provide DNS for the cluster [Conformance]だけをfocusにして実行し、JUnitの結果を残し(--report-dir、保存先: /root/conformance/dns-pass/junit_01.xml)、標準出力とエラー出力も残してください(保存先: /root/conformance/dns-pass/e2e.log)。通過する必要があります。

focusは正規表現なので、角括弧をエスケープする必要があります。名前の一部だけを書くと、似た名前のテストが一緒に選ばれることがあるので、dry-runで1個であることを先に確認してください。JUnitには、スキップしたspecもskippedとしてすべて入ります。

1台構成のクラスターが不合格になる適合性テスト

[sig-architecture] Conformance Tests should have at least two untainted nodes [Conformance]を実行して、結果を残し(保存先: /root/conformance/two-nodes/junit_01.xml、/root/conformance/two-nodes/e2e.log)、次のフィールドを書いてください(書き込み先: /root/conformance/two-nodes.json)。status(JUnitのそのtestcaseのstatus)、reason(e2e.logの[FAILED]の行のうち、ソースの位置(in [It] - ...)ではなく理由の文が書かれた行の文)、schedulable_nodes(現在テイントのないReadyノードの数、数値)です。

このテストは、失敗するのが正常です。適合性の提出で、k3sがどんな構成でテストを実行したか(cncf/k8s-conformanceのREADME)と比べてみてください。JUnitでは、failureの子要素とstatus属性を一緒に見ます。

CoreDNSを減らして同じテストを実行する

kube-systemのcoredns Deploymentを0に減らし、Podが消えたことを確認してから、ステップ4と同じDNSテストを--ginkgo.timeout=45sで実行して、結果を残してください(保存先: /root/conformance/dns-broken/junit_01.xml、/root/conformance/dns-broken/e2e.log)。次のフィールドを書きます(書き込み先: /root/conformance/broken.json)。coredns_replicas(実行直前のspec.replicas)、coredns_pods(実行直前のCoreDNSのPodの数)、status(JUnitのそのtestcaseのstatus)です。復旧は次のステップで行います。

このテストは、DNSの参照結果を600秒間待つので、時間制限なしで実行すると10分間止まったままになります。スイートの制限が終わると、ginkgoは失敗ではなくタイムアウトとして記録します。e2e.logで、どの名前の参照が失敗したかを探してみてください。

元に戻して、同じテストで証明する

corednsを1に戻してAvailableにしてから、同じDNSテストをもう一度実行して、結果を残してください(保存先: /root/conformance/dns-restored/junit_01.xml、/root/conformance/dns-restored/e2e.log)。通過する必要があります。

復旧を確認する最も確実な方法は、壊したときに不合格になったまさにそのテストを、もう一度通過させることです。前の実行のネームスペースがTerminatingのまま残っていても、テストは新しいネームスペースを作ります。

結果を適合性の言葉で解釈する

次のフィールドを書いてください(書き込み先: /root/conformance/report.json)。server(サーバーのgitVersion)、catalog_total(ステップ2のtotal)、passed(ステップ4と7で合格したtestcase名を、[It] なしで、重複なしにソートした配列)、failed_single_node(ステップ5で不合格になったテストのcodename)、timed_out_when_broken(ステップ6の結果がタイムアウトだったかどうか、ブール値)、submission_files(CNCFの認定PRに入れるファイル名4つをソートした配列)、certified_focus(認定のための実行で求められるE2E_FOCUSの値をそのまま)、skip_allowed(認定のための実行でE2E_SKIPを指定できるかどうか、ブール値)です。

前のステップのJUnitファイルから、名前とステータスをもう一度読み取ってください。提出ファイルとfocusおよびskipのルールは、cncf/k8s-conformanceのinstructions.mdにあります。