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

Kubespray と Terraform でクラスターを構築する

緑のランプではなく証拠で — インストール結果を層ごとに確かめる

TT Labで続きを見る

目標

kubesprayで構築したクラスターを、ノード → コアPod → DNS → 証明書 → 残ったファイル → 実際のワークロードの順に確認し、「次に何をいつやるべきか」を1枚のレポートにまとめます。

なぜ重要なのか

PLAY RECAPのfailed=0は、「プレイブックが最後まで動いた」という意味であり、「クラスターが使える」という意味ではありません。kubesprayは、kubeadmの上にいくつかのものを独自の方式で載せます。etcdをホストのサービスとして別に構築し、PodのDNSの手前にノードローカルのキャッシュを置き、証明書のディレクトリを移します。 そのため、kubeadmで自分で構築したクラスターを点検していた習慣のままで見ると、etcdの証明書を見落としたり、CoreDNSだけを見てDNSが動いていると判断したりすることになります。層ごとに1回ずつ自分で確認する順序を身につけておけば、インストールの後も、アップグレードの後も、同じ順序で点検できます。

ステップ

  1. /opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.ymlを実行して、出力の全体を残してください(約7分、保存先: /root/ks/logs/cluster-1.log)。PLAY RECAPのnode1がfailed=0である必要があります。
  2. 次のフィールドを書いてください(書き込み先: /root/ks/verify/node.json)。ready(Ready条件のstatus文字列)、kubelet_version、container_runtime(nodeInfo.containerRuntimeVersion)、internal_ip、roles(node-role.kubernetes.io/で始まるラベルのロール名をソートした配列)、taints(키:효과の文字列の配列、なければ空の配列。プレースホルダーはキーと効果です)です。
  3. kube-systemのPodを確認して、次のフィールドを書いてください(書き込み先: /root/ks/verify/pods.json)。apps(各Podのk8s-appラベル、なければcomponentラベルの値を集めた、重複のないソートした配列)、not_ready(ReadyではないPod名の配列、なければ空の配列)、etcd_is_pod(etcdがPodとして起動しているか、ブール値)、etcd_unit(etcdを起動したsystemdユニット名、.serviceを含む)です。
  4. 次のフィールドを書いてください(書き込み先: /root/ks/verify/dns.json)。kubelet_cluster_dns(/var/lib/kubelet/config.yamlのclusterDNSの最初の値)、coredns_service_ip(kube-systemのCoreDNS ServiceのClusterIP)、answer_via_nodelocal、answer_via_coredns(ノードから2つのアドレスにそれぞれkubernetes.default.svc.cluster.localを問い合わせたAレコード)です。2つの答えは、kubernetes ServiceのClusterIPと同じである必要があります。
  5. 次のフィールドを書いてください(書き込み先: /root/ks/verify/certs.json)。apiserver_not_after、ca_not_after(/etc/kubernetes/sslのapiserver.crtとca.crt)、etcd_member_not_after(/etc/ssl/etcd/ssl/member-node1.pem)をUTCの2026-01-01T00:00:00Z形式で、apiserver_valid_days、etcd_member_valid_days(各証明書のnotBeforeからnotAfterまでの日数、整数)とkubeadm_lists_etcd(kubeadm certs check-expirationの出力にetcdの証明書の行があるか、ブール値)です。
  6. 次のフィールドを書いてください(書き込み先: /root/ks/verify/files.json)。kubeadm_config_version(/etc/kubernetes/kubeadm-config.yamlのClusterConfigurationのkubernetesVersion)、etcd_data_dir(/etc/etcd.envのETCD_DATA_DIR)、kubeconfig_server(/root/.kube/configのserverアドレス)、containerd_version(containerd --versionの3番目の列)、releases_mb(/tmp/releasesのサイズ、MiB単位の整数。du -sm)です。
  7. defaultネームスペースにDeploymentweb(イメージはregistry.k8s.io/e2e-test-images/agnhost:2.59、引数はnetexec --http-port=8080、レプリカ2)と、同じ名前のClusterIP Service(ポート80 → 8080)を作成してください。2つのPodがReadyになったら、ノードからcurl http://<web 서비스 IP>/hostnameを何回か実行して(プレースホルダーはwebサービスのIPです)、2つのPod名がどちらも返ってくることを確認し、その2つの名前をソートして、1行に1つずつ書いてください(書き込み先: /root/ks/verify/smoke.txt)。
  8. 次のフィールドを書いてください(書き込み先: /root/ks/verify/report.json)。node_ready(ブール値)、core_apps(ステップ3のappsの個数、数値)、dns_ok(ステップ4の2つの答えがkubernetes ServiceのIPと同じか、ブール値)、first_cert_to_expire(kubeadmのリーフ証明書とetcdのmember証明書のうち、先に期限切れになるほう: "kubeadm"または"etcd")、days_until_first_expiry(その証明書が期限切れになるまでの残りの日数、整数)、smoke_pods(ステップ7で応答したPodの数、数値)です。

参考

検証するクラスターを構築する

/opt/ks/kubesprayでansible-playbook -i /root/ks/inventory/lab/inventory.ini cluster.ymlを実行して、出力の全体を残してください(約7分、保存先: /root/ks/logs/cluster-1.log)。PLAY RECAPのnode1がfailed=0である必要があります。

モジュール3で行ったインストールと同じです。コンソールが切れても動き続けるように、systemd-runやtmuxで起動して、HOME=/rootを渡してください。待っている間に、このラボの次のステップを読んでおくとよいです。

ノード: Readyとテイント

次のフィールドを書いてください(書き込み先: /root/ks/verify/node.json)。ready(Ready条件のstatus文字列)、kubelet_version、container_runtime(nodeInfo.containerRuntimeVersion)、internal_ip、roles(node-role.kubernetes.io/で始まるラベルのロール名をソートした配列)、taints(키:효과の文字列の配列、なければ空の配列。プレースホルダーはキーと効果です)です。

kubeadmは、コントロールプレーンのノードにNoScheduleテイントを付けます。ところが、このノードはインベントリのkube_nodeにも入っています。kubesprayがその事実を見て何をしたかを、テイントの一覧で確認してください。ロール名は、ラベルのキーの最後の部分です。

コアPod: 何が動いていて、何がないのか

kube-systemのPodを確認して、次のフィールドを書いてください(書き込み先: /root/ks/verify/pods.json)。apps(各Podのk8s-appラベル、なければcomponentラベルの値を集めた、重複のないソートした配列)、not_ready(ReadyではないPod名の配列、なければ空の配列)、etcd_is_pod(etcdがPodとして起動しているか、ブール値)、etcd_unit(etcdを起動したsystemdユニット名、.serviceを含む)です。

kubeadmで自分で構築したクラスターとの違いが、ここで見えます。kubesprayのデフォルトのetcdの配置(etcd_deployment_type)が何かを、group_vars/all/etcd.ymlで探し、systemctl list-unitsで実際のユニットを確認してください。

DNS: Podの問い合わせ先はCoreDNSではなく別のアドレス

次のフィールドを書いてください(書き込み先: /root/ks/verify/dns.json)。kubelet_cluster_dns(/var/lib/kubelet/config.yamlのclusterDNSの最初の値)、coredns_service_ip(kube-systemのCoreDNS ServiceのClusterIP)、answer_via_nodelocal、answer_via_coredns(ノードから2つのアドレスにそれぞれkubernetes.default.svc.cluster.localを問い合わせたAレコード)です。2つの答えは、kubernetes ServiceのClusterIPと同じである必要があります。

kubesprayはデフォルトでnodelocaldns(enable_nodelocaldns: true)を有効にします。ノードごとにリンクローカルアドレスでキャッシュDNSが動き、kubeletはPodにそのアドレスを知らせます。CoreDNS Serviceの名前は、kubeadmのデフォルトと異なることがあるので、Serviceの一覧からセレクターで探してください。dig +short @<주소> <이름>が、答えだけを返します(プレースホルダーはアドレスと名前です)。

証明書: 2系統の有効期限

次のフィールドを書いてください(書き込み先: /root/ks/verify/certs.json)。apiserver_not_after、ca_not_after(/etc/kubernetes/sslのapiserver.crtとca.crt)、etcd_member_not_after(/etc/ssl/etcd/ssl/member-node1.pem)をUTCの2026-01-01T00:00:00Z形式で、apiserver_valid_days、etcd_member_valid_days(各証明書のnotBeforeからnotAfterまでの日数、整数)とkubeadm_lists_etcd(kubeadm certs check-expirationの出力にetcdの証明書の行があるか、ブール値)です。

kubesprayは、kubeadmの証明書のディレクトリを/etc/kubernetes/sslにします(kubeadmのデフォルトはpki)。etcdをホストのサービスとして起動するデフォルトの配置では、etcdの証明書をkubeadmではなくkubesprayがopensslで作り、その期間はkubespray_defaultsのcertificates_durationです。片方だけを見て「証明書の期限の点検は終わり」と言ってはいけない理由が、ここにあります。

kubesprayが残したもの

次のフィールドを書いてください(書き込み先: /root/ks/verify/files.json)。kubeadm_config_version(/etc/kubernetes/kubeadm-config.yamlのClusterConfigurationのkubernetesVersion)、etcd_data_dir(/etc/etcd.envのETCD_DATA_DIR)、kubeconfig_server(/root/.kube/configのserverアドレス)、containerd_version(containerd --versionの3番目の列)、releases_mb(/tmp/releasesのサイズ、MiB単位の整数。du -sm)です。

kubesprayは、kubeadmを呼び出すときに使った設定ファイルと、etcdの環境ファイルを、ノードに残します。インストールがどの値で行われたかを、後で確認するための一次資料です。/tmp/releasesは、kubesprayがダウンロードしたバイナリのキャッシュ(local_release_dir)で、再インストールやアップグレードが速い理由でもあります。

最後の証拠はワークロード

defaultネームスペースにDeploymentweb(イメージはregistry.k8s.io/e2e-test-images/agnhost:2.59、引数はnetexec --http-port=8080、レプリカ2)と、同じ名前のClusterIP Service(ポート80 → 8080)を作成してください。2つのPodがReadyになったら、ノードからcurl http://<web 서비스 IP>/hostnameを何回か実行して(プレースホルダーはwebサービスのIPです)、2つのPod名がどちらも返ってくることを確認し、その2つの名前をソートして、1行に1つずつ書いてください(書き込み先: /root/ks/verify/smoke.txt)。

このステップが通過すれば、イメージのダウンロード(containerdとレジストリへのエグレス)、スケジューリング(テイント)、Podネットワーク(calico)、サービス(kube-proxy)が、一度に確認できます。緑の表示の代わりに実際のリクエストを送る理由です。agnhostのnetexecは、/hostnameにPod名を返します。

検証のレポート

次のフィールドを書いてください(書き込み先: /root/ks/verify/report.json)。node_ready(ブール値)、core_apps(ステップ3のappsの個数、数値)、dns_ok(ステップ4の2つの答えがkubernetes ServiceのIPと同じか、ブール値)、first_cert_to_expire(kubeadmのリーフ証明書とetcdのmember証明書のうち、先に期限切れになるほう: "kubeadm"または"etcd")、days_until_first_expiry(その証明書が期限切れになるまでの残りの日数、整数)、smoke_pods(ステップ7で応答したPodの数、数値)です。

前のステップの記録と現在のクラスターから、すべて再計算できます。残りの日数は、現在の時刻からnotAfterまでを切り捨てた整数で計算します。このレポートの目的は、「次に何をいつやるべきか」を1行で残すことです。