Kustomize オーバーレイとリソースメトリクスのパイプライン
一言でいうと
Kustomizeは、元のYAMLを修正せずに、環境ごとの違いを重ねるツールで、kubectl topは、metrics-serverが各ノードのkubeletから集めてMetrics APIとして提供する値を読み取ってくるコマンドです。どちらも、「この結果がどこで作られるのか」を知っていてはじめて、試験会場でも現場でも詰まりません。
なぜ必要なのか
同じアプリケーションを、開発・本番の環境にデプロイしていると、YAMLをコピーして、名前とレプリカ数だけを変えた複製が増えていきます。複製が3つを超えると、どれが原本なのか誰もわからなくなり、片方だけを直した変更が、もう一方に静かに抜け落ちます。Helmは、この問題をテンプレート言語で解きますが、テンプレートを学ぶコストがあります。Kustomizeは、テンプレートなしに、原本はそのままにして、その上にパッチを載せる方式を選び、KubernetesオブジェクトをKustomizeで宣言的に管理するドキュメントによると、kubectl 1.14からは別途インストールなしに、kubectl apply -kで使えます。
リソース使用量側の問題は異なります。新しく作ったクラスターでkubectl top nodesを実行すると、「Metrics API not available」という答えが返ってきます。kubeletは、自分のノードの使用量しか知らず、それをクラスター全体に集めてAPIとして提供するコンポーネントが、デフォルトのインストールにはないからです。リソースメトリクスパイプラインのドキュメントは、「Metrics APIにアクセスするには、metrics-serverまたはそれに代わるアダプターを必ずデプロイしなければならない」と明記しています。したがって、kubectl topが動かないということは、コマンドが故障したのではなく、パイプラインの一部が抜けているということです。
どう動くのか
Kustomize: baseとoverlay
baseは、kustomization.yamlとリソースファイルが入っているディレクトリです。overlayは、別のkustomizationディレクトリをresourcesとして参照するディレクトリで、参照したリソースの上に、自分の変更を載せます。ドキュメントが強調する性質は1つです。baseはoverlayの存在を知りません。そのため、1つのbaseを、複数のoverlayが一緒に使えます。
# base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
# overlays/dev/kustomization.yaml
resources:
- ../../base
namePrefix: dev-
patches:
- path: replicas.yaml
パッチは、patchesフィールドに書きます。ドキュメントによると、KustomizeはStrategicMergeとJson6902の2つのパッチ方式をサポートし、パッチはファイルでもインライン文字列でもよく、書かれた順に適用されます。パッチの対象は、group・version・kind・name・namespace・labelSelector・annotationSelectorで選びます。ドキュメントは「1つのことだけを行う小さなパッチ」を勧めています。レプリカ数を上げるパッチと、メモリ制限を設定するパッチを、別々に置くという意味です。StrategicMergeパッチは、原本と同じ形のYAMLの断片を重ね書きする方式なので読みやすく、Json6902パッチは、パスを指定してadd・replace・removeを行う方式なので、リストの中の特定の項目のように、重ね書きでは表現しにくい箇所に使います。
パッチのほかにも、よく使うフィールドがあります。imagesは、パッチなしに、イメージ名・タグ・ダイジェストだけを変更し、namePrefix・nameSuffixは、すべてのリソース名の前後に文字列を付け、configMapGenerator・secretGeneratorは、ファイルやリテラルからConfigMap・Secretを生成します。ジェネレーターが作ったオブジェクトには、内容のハッシュが名前の後ろに付きます。内容が変わると名前が変わり、それを参照するDeploymentのスペックも変わるので、ロールアウトがひとりでに起こります。この動作を無効にするには、generatorOptionsのdisableNameSuffixHashを使います。
適用前に結果を見るには、kubectl kustomize <디렉터리>でレンダリングされたYAMLを出力して(プレースホルダーはディレクトリです)、確認が終わったら、kubectl apply -k <디렉터리>で適用します。kubectl diff -k・kubectl delete -kも同じ方式です。-kは、ファイルではなく、kustomization.yamlがあるディレクトリを指す必要があります。
リソース使用量: メトリクスが通る道
リソースメトリクスパイプラインのドキュメントが描いた流れは、次のとおりです。
| 段階 | コンポーネント | 行うこと |
|---|---|---|
| 1 | cAdvisor | kubeletに含まれるデーモン。コンテナのメトリクスを収集・集計・公開します |
| 2 | kubelet | /metrics/resourceと/statsエンドポイントで、ノード単位の要約を提供します |
| 3 | metrics-server | 各kubeletからメトリクスを引き取って集計する、クラスターアドオンです |
| 4 | Metrics API | metrics.k8s.ioグループ。APIサーバーが拡張APIとして提供します |
| 5 | 利用者 | HPA・VPA、そしてkubectl topです |
metrics-serverは、Metrics APIのリファレンス実装です。APIサーバーにつなぐには、aggregation layerが有効になっている必要があり、metrics.k8s.ioに対するAPIServiceが登録されている必要があります。metrics-serverリポジトリは、要件をさらに書いています。ノードのkubeletでWebhookの認証・認可が有効になっていること、kubeletの証明書がクラスターのCAで署名されていること(そうでなければ、--kubelet-insecure-tlsで検証を無効にすること)、コントロールプレーンがmetrics-serverのPodに届くこと、metrics-serverがすべてのノードのkubeletポートに届くことです。収集周期は15秒で、metrics-server v0.6.0以上は、kubeletの/metrics/resourceを読みます。
値の意味も知っておく必要があります。CPUは、カーネルが提供する累積カウンターの変化率で計算した平均コア使用量で、計算区間は、Metrics APIのレスポンスのwindowフィールドに出ます。メモリは、収集時点のworking setで、メモリ逼迫の下でも解放できない、使用中のメモリです。そのため、kubectl top podのメモリ値は、RSSとも異なり、キャッシュをすべて含んだ値とも異なります。
リポジトリのドキュメントには、注意書きが1つあります。metrics-serverはオートスケーリング専用であり、モニタリングシステムのデータソースとして使ってはいけない、というものです。正確な使用量の記録が必要なら、Prometheusのようなモニタリングツールに、kubeletの/metrics/resourceを直接スクレイプさせるようにと案内しています。
現場での姿
オーバーレイを適用したのにオブジェクトが見えない。overlayにnamePrefix: dev-を設定すると、作成されるDeploymentの名前は、my-nginxではなくdev-my-nginxです。kubectl get deploy my-nginxで探すと、ないと出ます。ドキュメントのサンプル出力も、deployment.apps/dev-my-nginx createdです。適用前に、kubectl kustomizeでレンダリング結果を一度見る習慣が、この混乱をなくします。
metrics-serverをデプロイしたのに、kubectl topが失敗し続ける。kubeadmで作ったクラスターでよく見かけます。kubeadmの証明書管理のドキュメントによると、kubeadmがデプロイするkubeletのserving証明書は、デフォルトで自己署名なので、metrics-serverのような外部サービスがkubeletにTLSでつなぐときに、検証に失敗します。実習用のクラスターでは、--kubelet-insecure-tlsで回避し、本番のクラスターでは、同じドキュメントの「署名されたkubeletのserving証明書を有効にする」手順に従い、クラスターのCAが署名した証明書を受け取るようにします。
次の理論で見ること
次の読み物では、名前解決を扱います。Podがmy-svcと呼ぶと、どのサーバーがどの順序で答えるのか、CoreDNSのCorefileはどんな構造なのか、そして、解決が詰まったときにどこから見るのかを、公式のデバッグ手順に沿って身につけます。