- 内堀航輝
- 約 3,200 文字
- 500 View
目次
はじめに
最近、コンテナオーケストレーションの技術領域に興味をもち、Kubernetesを触り始めました。早速自宅で飼ってるMiniPC(ホームサーバ)にArgoCDやLonghornを入れてみたものの、Deployment、Pod、Serviceなど初めましての概念ばかり。気づいたら、AIの指示通りにただコマンド打つマンになっていました。
このままではまずいと思い、Kubernetesの基礎的な挙動を追うことにしました。今回は、どのような流れでPodが作られているのかを実験し、そのアウトプットとしてこの記事にまとめています。
※実験にはMinikubeを使っています。初学者が調べながらまとめたものなので、誤りがあればご指摘ください。
Pod起動までの流れの概要
Podが起動するまでの流れを紹介します。複数のKubernetesコンポーネントが登場しますが、この記事のメインテーマではないため、用語は簡単な説明に留めます。詳細が気になる方は、既存の解説記事や公式ドキュメントをご参照ください。
kubectl run |
- etcd:Kubernetesの全状態を保存するデータベース
- API Server:全コンポーネントからのリクエスト受付と、状態変更の通知する窓口
- Scheduler:Podをどのノードで動かすかを決定するスケジューラ
- kubelet:各ノード上で実際にコンテナを起動・管理する実行エンジン
補足:
kubectl runはPodを直接作成します。Deployment経由の場合は、Controller ManagerがDeploymentデータ → ReplicaSetデータ → Podデータ と各種データを作成するステップが加わります。この記事では、簡略化のためkubectl runによる直接的な作成を追いかけます。
実験1:イベントログでPod作成の流れを確認する
最初の実験として、実際にkubectl runを実行し、出力されるイベントログを確認してみます。
kubectl run log-test --image=nginx |
REASON列とMESSAGE列を見ると、まずScheduledでPodがノード(ここではminikube)に割り当てられ、その後にコンテナの立ち上げ処理が始まっていることがわかります。
さらにkubectl get events -o yaml とオプションを追加すると、各イベントがどのコンポーネントから出力されたのかを詳しく確認できます。
kubectl get events -o yaml の出力
% kubectl get events -o yaml |
出力されたイベントログの reportingComponent フィールドを確認すると、各イベントの出力元は以下です。
- Scheduled →
reportingComponent: default-scheduler - Pulling / Pulled / Created / Started →
reportingComponent: kubelet
概要で確認した通り、まずSchedulerがノードを割り当てた後、そのノードのkubeletがコンテナの起動処理を行っていることが、実際のログからも確認できました。
Static PodとMirror Pod
ここまででpodが起動するまでの流れはわかったのですが、ここで1つ疑問が湧きました。
先ほど確認した通り、Podが起動するにはSchedulerによるノード割り当てが必要です。しかし、そのScheduler自身もPodとして動いています。となると、Schedulerを起動するためのSchedulerが必要で、そのSchedulerを起動するためにさらにSchedulerが必要で、、、と無限ループに陥ってしまいます。最初のSchedulerは一体どのように起動されているのでしょうか?
結論から言うと、 SchedulerはAPI Serverや別のSchedulerを経由せず、kubeletがマニフェストファイルから直接起動していました。
実際のSchedulerのマニフェストファイルを確認すると、以下のようになっています。kindが Deployment ではなく Pod となっており、Podデータそのものが定義されていることがわかります。
% minikube ssh |
このように、特定のディレクトリにマニフェストを配置し、API Serverを経由せずにkubeletが直接起動・管理するPodをStatic Podと呼びます。Kubernetesの起動時には、コントロールプレーンのkubeletがこの仕組みを利用して、API Serverやetcd、Schedulerなどの主要なコンポーネントをStatic Podとして起動しています。
ただ、このStatic PodはAPI Serverを経由しないため、etcd上に実体がありません。そのままでは、kubectl get podsで確認できず、クラスタ全体の状態を一元管理する上で不便です。そこでkubeletは、Mirror Podと呼ばれる読み取り専用のPodを作成します。kubectl get pods -n kube-systemで見えるkube-scheduler-minikubeは、実はこのMirror Podでした。
実験2:Schedulerを止めてみる
ここまでの話が本当なら、以下が成り立つはずです。
- Mirror Podを削除しても、Schedulerは止まらない(本体はマニフェストファイルだから)
- マニフェストファイルを削除(移動)すると、Schedulerが止まる
- Schedulerが止まると、新しいPodはノードに割り当てられずPendingのままになる
というわけで、さっそく試してみましょう。
1. Mirror Podを削除する
kubectl delete podでkube-scheduler-minikubeを削除してみます。しかし、何度削除しても、即座に復活し、kubectl get podsの結果に出てきます。
kubectl delete pod kube-scheduler-minikube -n kube-system |
2. マニフェストファイルを移動する
次にminikube sshでMinikubeのノード内入り、マニフェストファイルを他の場所に動かしてみます(削除すると戻すのが面倒なのでmvにしました)。
すると、あれだけ何度削除しても復活していたkube-scheduler-minikubeが、kubectl get podsから消えました。
minikube ssh |
3. Schedulerなしで新しいPodを作成する
このSchedulerがいない状態で、新しいPodを作成してみます。Podデータ自体は作成できましたが、STATUSがPendingのまま動かず、NODEも<none>のままです(必要な情報を出力するためcustom-columnsオプションをつけています)。
kubectl run new-pod --image=nginx |
どれだけ待ってもRunningになることはありませんでした。
Schedulerがいないと、Podデータは作成されても、ノードが割り当てられないため、冒頭で確認したフローのSchedulerのステップで処理が止まってしまうことが実際の挙動でも確認できました。
おわりに
解説動画や記事を見ても、Kubernetesの各概念やその関係性がピンとこず、「デプロイするとPodが作れてその中にコンテナがいるらしい」くらいの認識でした。そんな状態だったので、当然kubectlコマンドの意味がわかるはずもなく、結果としてAIの指示通りにコマンド打つマンと化していました。
しかし今回、小さな実験を通して手を動かしてみたことで、裏側で各コンポーネントがどのように連携して動いているのかを具体的に追うことができ、一気に理解が深まりました。特にSchedulerは、こうして実験してみなければ存在すら知らなかった概念だったため、非常に学びになりました。
今回の実験で、何度も消されたりファイルを移動させられたりと散々な目に遭わせてしまったSchedulerには、この場を借りて感謝と謝罪を述べて締めくくりたいと思います。