クラスタを手で開けてみる
目標
本物のKubernetesクラスターに接続してネームスペース・ノード・APIリソースを直接調べ、ラベルセレクターと-o jsonpathで必要な値だけを取り出したうえで、同じDeploymentを命令型と宣言型の2つの方法で作り、違いを目で確認します。
なぜ重要なのか
Kubernetesを使う人は大きく2つに分かれます。毎回ドキュメントサイトを検索する人と、クラスターに直接尋ねる人です。kubectl api-resourcesとkubectl explainは、このクラスターが今実際に知っていることを教えてくれるので、ドキュメントより正確です。CRDで拡張されたリソースまで出てくるからです。
そしてラベルセレクター。Kubernetesにはオブジェクト同士の直接参照がほとんどありません。ServiceがPodを見つける方法も、ReplicaSetが自分のPodを数える方法も、すべてラベルセレクターです。この疎結合のおかげでPodを自由に入れ替えられますが、その代償として、セレクターのタイプミスはエラーなしに静かに何も見つけられません。
最後に宣言型。kubectl runは手軽ですが、何を作ったのか記録が残りません。マニフェストをファイルとして置いてapplyすれば、そのファイルがそのままこのクラスターの真実になり、レビュー・バージョン管理・ロールバックが可能になります。GitOpsという言葉は、この習慣を組織規模に広げたものにすぎません。
ステップ
- ネームスペース
kcna-archを作成し、ラベルtier=labを付けてください。 - クラスターのすべてのノード名を1行に1つずつ
/root/kcna-arch/nodes.txtに保存してください。名前だけを入れ、node/のような接頭辞は入れないでください。 kubectl api-resourcesを見て、deploymentsのAPIVERSIONの値を/root/kcna-arch/deploy-apiversion.txtに、servicesの短縮形(SHORTNAMES)を/root/kcna-arch/svc-short.txtに、それぞれ1行で保存してください。kubectl explainで、Podをスケジューラーを介さず特定のノードに直接配置するspecフィールドを探し、そのフィールドを使ってネームスペースkcna-archにイメージがnginx:1.27-alpineのPodpinnedを作成してください。ノード名は、ステップ2の一覧にあるもののどれかにしてください。/root/kcna-arch/components.txtに次の4行をそのまま記入してください。serve-rest-api=、store-cluster-state=、watch-and-place-pods=、reconcile-desired-state=の後ろに、それぞれ適切なコンポーネント名(kube-apiserver、etcd、kube-scheduler、kube-controller-manager)を付けます。そしてkubectl get --rawでAPIサーバーの/healthzを呼び出し、その応答を/root/kcna-arch/healthz.txtに保存してください。- ネームスペース
kcna-archにPodを3つ作成してください。web-1(app=web,tier=front)、web-2(app=web,tier=back)、db-1(app=db,tier=back)です。次に、セレクターapp=web,tier=backで選んだPodの名前を、1行に1つずつ/root/kcna-arch/selected.txtに保存してください。 kubectl create deploymentに--dry-run=client -o yamlを付けて、名前kcna-web、イメージnginx:1.27-alpine、replicas 2のDeploymentマニフェストを/root/kcna-arch/kcna-web.yamlに保存し、そのファイルをネームスペースkcna-archに宣言型で反映してください。
参考
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'のようにrangeで繰り返すと、1行に1つずつ取り出せます。kubectl explain pod.spec --recursiveは、フィールドツリー全体を表示します。名前がわからないときはgrepと組み合わせると速いです。- よくあるミス1: ステップ3で
deployments.appsのようにリソース名を書いてしまうことです。必要なのはAPIVERSION列の値です。 - よくあるミス2: ステップ7で
kubectl create deploymentによってクラスターにいきなり作ってしまうことです。そうするとマニフェストファイルはあっても、オブジェクトには宣言型で反映した痕跡が残らず、採点を通過できません。
作業用ネームスペースを作成する
ネームスペースkcna-archを作成し、ラベルtier=labを付けてください。
ネームスペースはクラスター内の名前空間です。作成するときにラベルを一緒に指定するか、作成後にkubectl labelで付けられます。ラベルのキーはtier、値はlabです。
ノード一覧をファイルに取り出す
クラスターのすべてのノード名を1行に1つずつ/root/kcna-arch/nodes.txtに保存してください。名前だけを入れ、node/のような接頭辞は入れないでください。
kubectl get nodesのデフォルト出力には、ヘッダーと複数の列が混ざっています。名前だけを1行に1つずつ取り出したいので、-oで出力形式を変えるのがすっきりします。-o nameを使うとnode/の接頭辞が付く点も確認してみてください。
api-resourcesでAPIグループと短縮形を探す
kubectl api-resourcesを見て、deploymentsのAPIVERSIONの値を/root/kcna-arch/deploy-apiversion.txtに、servicesの短縮形(SHORTNAMES)を/root/kcna-arch/svc-short.txtに、それぞれ1行で保存してください。
kubectl api-resourcesは、このクラスターが知っているすべてのリソースをNAME/SHORTNAMES/APIVERSION/NAMESPACED/KINDの列で表示します。検索はgrepで絞り込めばよいです。APIVERSIONは「グループ/バージョン」の形で、コアグループはグループ名が空である点に注意してください。
explainでフィールドを探してPodをノードに固定する
kubectl explainで、Podをスケジューラーを介さず特定のノードに直接配置するspecフィールドを探し、そのフィールドを使ってネームスペースkcna-archにイメージがnginx:1.27-alpineのPodpinnedを作成してください。ノード名は、ステップ2の一覧にあるもののどれかにしてください。
kubectl explain pod.specを実行すると、spec配下のフィールドの説明がずらりと出ます。スケジューラーを飛ばして特定のノードに直接配置するフィールドが、その中にあります。ノード名はステップ2で取り出した一覧のどれを使ってもかまいません。
コンポーネントの役割を整理してAPIサーバーの状態を取得する
/root/kcna-arch/components.txtに次の4行をそのまま記入してください。serve-rest-api=、store-cluster-state=、watch-and-place-pods=、reconcile-desired-state=の後ろに、それぞれ適切なコンポーネント名(kube-apiserver、etcd、kube-scheduler、kube-controller-manager)を付けます。そしてkubectl get --rawでAPIサーバーの/healthzを呼び出し、その応答を/root/kcna-arch/healthz.txtに保存してください。
前の読み物で扱った4つのコンポーネントの役割を、key=valueで1行ずつ書きます。そしてkubectlは--rawオプションで、APIサーバーの任意のパスをそのまま呼び出せます。ヘルスエンドポイントの応答はとても短いです。
ラベルを付けてセレクターで選び出す
ネームスペースkcna-archにPodを3つ作成してください。web-1(app=web,tier=front)、web-2(app=web,tier=back)、db-1(app=db,tier=back)です。次に、セレクターapp=web,tier=backで選んだPodの名前を、1行に1つずつ/root/kcna-arch/selected.txtに保存してください。
3つのPodに、それぞれ異なるラベルの組み合わせを付けます。次にkubectl getの-lオプションに条件をカンマでつなげて書くと、ANDとして動作します。結果をファイルに残すときは、名前だけが出るように出力形式を指定してください。
命令型で作ったYAMLを宣言型で反映する
kubectl create deploymentに--dry-run=client -o yamlを付けて、名前kcna-web、イメージnginx:1.27-alpine、replicas 2のDeploymentマニフェストを/root/kcna-arch/kcna-web.yamlに保存し、そのファイルをネームスペースkcna-archに宣言型で反映してください。
kubectl createに--dry-run=client -o yamlを付けると、クラスターに触れずにマニフェストだけを取り出せます。そのファイルをapplyで反映すると、createで作ったときにはなかったアノテーションがオブジェクトに1つ付きます。採点は、そのアノテーションの有無で2つの方式を区別します。