今回はPodについて勉強していこうと思います。
DevOpsやMLOps、SREなどの肩書を持っている方であれば仕事で使用しているので理解がある方が多いかと思いますが、
他のエンジニアはPodという単語をなんとなく知っているくらいかと思います。
kubernetesを使用していくとも、AWSやGCPの公式ドキュメントではたびたび使用されているような単語ですね。
kubernetesを使用しているクラウドサービスを運用していればもちろん理解しておけなければならないでしょう。
Pod とは?
Podとは、同じ実行環境上で動くアプリケーションコンテナとストレージボリュームの集まりのことです。
Kubernetesクラスタ上でのデプロイ最小単位になります。
これだけ聞いても、馴染みにのない方にとっては、"つまりアプリケーションじゃないの?" とか "運用上どういう考え方でPodとやらをデプロイするべきなのか?" と思うこともあるでしょう。
考え方的なことは後で解説するとして、ここでは、Podが最小のデプロイ単位と覚えておくと良いでしょう。
コンテナの機能
Podについて踏み込んで行く前に、コンテナとOSとの関係をここで簡単にみていきます。
私の記事の#1で、"コンテナはオペレーションシステム(HostOS:kernel)を共有"と説明しました。
【k8s】kubernetes 入門 - #01 - helloworlds
※ ここでは主にコンテナランタイムはDockerを前提に記載します。
コンテナが機能するにあたり、以下のLinuxが持つ機能を利用しています。
- overlayfs
- namespaces
- cgroups
基本的に1つのノードに複数のPod(=複数のコンテナ)がのることは容易に想像できます。
つまりコンテナは、OSカーネルが持っている環境を隔離することができるということになります。
これは、namespacesとcgroupsのOSカーネルの機能が使用されています。
(※overlayfsは割愛)
cgroups
各コンテナは、CPUやメモリといったリソースを制限なく使用できるわけではありませんね。
ここで使用されているのが、Linuxカーネルの機能であるcgroupです。
cgroupはタスクのグループ化、グループ内のタスクに様々なリソース制御を行う仕組みです。
namespaces
ネームスペースは、コンテナを1つの仮想マシンのようにみせるための機能です。
コンテナを区画化し、Linuxカーネルのネームスペースを制御します。
ネームスペース内のプロセスは他のネームスペース内のプロセスとリソースが隔離できることが重要な点です。
これにより、他のノードでも同じ環境を構築することができます。
以下のリソースが分離可能です。
- PID: プロセスID
- Network: ネットワークデバイス、port、ルーティングテーブル、ファイアウォールルールなど
- Cgroup: プロセスの名前空間を分離するためルートディレクトリ
- IPC: System System V IPC, POSIX message queues
- Mount: マウントポイント
- User/Group: ユーザーID(UID)、グループID(GID)
- UTS: Host name、NIS domain name
参考: namespaces(7) - Linux manual page
簡単にまとめ
ここまでくると、このように想像できます。
上記のことは理解できますが、1つ運用面で疑問に思うことができてきます。
"Podに入れるコンテナはどういったものが良いのか?" です。
Podに入れるもの
例えば、AというコンテナとBというDBのコンテナがあったとします。
当然このAとBのコンテナを1つのアプリケーションとして扱う場合、一緒にいれておけばOKと考えますが、
これはアンチパターンになってしまいます。
このアプリケーションに負荷がかかった場合、Podはスケールします。
このとき、フロントエンドを担うコンテナとDBのコンテナを同時にスケールさせてしまいます。
DBの方は他の条件でスケールさせたいとすると、同じPodに入れておくには効率が悪いことになります。
設計時に考えたいのは、"このコンテナはそれぞれ違うマシンに配置されたとしても正常に動作するかどうか" ということです。
- 動作する→ Podを分ける
- 動作しない→ コンテナをまとめて1つのPodにする
必ずしもこの通りではないかもしれまんせんが、基本的には上記を元に設計するのが良さそうです。
(※ アプリケーションやバッチ、APIなどのそれぞれの要件によって、マシンサイズが変動することもありますが、それは違うサービスで実現可能。)
当たり前ですが、Podは違うマシン(ノード)に配置されるということも最初は見落としがちな気がします。
最初の内はマシンが違っていても、動作することを基本的な条件として取り入れておくべきだと思います。
Podの作成してみる
簡単なPodを作成してみます。
適当な場所でYAMLファイルを作成します。
apiVersion: v1 kind: Pod metadata: name: kuard spec: containers: - image: gcr.io/kuar-demo/kuard-amd64:1 name: kuard ports: - containerPort: 8080 name: http protocol: TCP
※ minikubeで試しています笑
マニフェストを作成したら、以下のコマンドでapplyします(Podを作成)。
$ kubectl apply -f kuard-pod.yaml -n default
-n
はネームスペース指定のオプションです。
作成の確認は以下のコマンドです。
$ kubectl get pod -n default NAME READY STATUS RESTARTS AGE kuard 1/1 Running 0 11m
次にPodの詳細を確認してきましょう。
$ kubectl describe pod kuard -n default
たくさんの情報が出力されるので、簡単にみていきます。
まず一番上に記載されているのが当Podの情報ですね。
Name: kuard Namespace: default Priority: 0 Service Account: default Node: minikube/192.168.58.6 Start Time: Sat, 25 Mar 2023 16:58:11 +0900 Labels: <none> Annotations: <none> Status: Running IP: 10.244.0.5 IPs: IP: 10.244.0.5
次にPod内で動作しているコンテナの情報です。
Containers: kuard: Container ID: docker://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Image: gcr.io/kuar-demo/kuard-amd64:1 Image ID: docker-pullable://gcr.io/kuar-demo/kuard-amd64@sha256:bd17153e9a3319f401acc7a27759243f37d422c06cbbf01cb3e1f54bbbfe14f4 Port: 8080/TCP Host Port: 0/TCP State: Running Started: Sat, 25 Mar 2023 16:58:17 +0900 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-mwqxn (ro)
次にコンディションです (参考)
Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True
次にボリュームです。 当Podのボリュームのタイプなどが確認できます。
Volumes: kube-api-access-mwqxn: Type: Projected (a volume that contains injected data from multiple sources) TokenExpirationSeconds: 3607 ConfigMapName: kube-root-ca.crt ConfigMapOptional: <nil> DownwardAPI: true
続いて、QoSについて。
QoS Class: BestEffort
あまり馴染みがないので、簡単に記載すると、
- BestEffort (優先度が一番低)
- Burstable
- Guaranteed (優先度が一番高)
上記のように値があり、Podをkillする優先度合いのことです。 (Podが複数あり、リソースを60%使用したいPodと90%使用したいPodがあった場合に、killされるPodを判別するために使用される)
今回のマニフェストでは定義していませんが、マニフェストにリソースを定義することが可能です。
(Resource Requests
と Resource Limits
)
ノード内にあるPodのリソースの状況をKubernetesが確認し、ある条件で判定しているそうです。(これについては詳しく調べていないので、機会があったら記事にしようと思います。)
なので、人間が手動で定義する項目ではないようです。
以下の2つはPodを特定のノードにスケジューリングする際のもの。
Node-Selectorsは、特定のノードにスケジュールするためのもので、
Tolerationsは、特定のノードにスケジュールしないためのもの。
※ こちらもここでは深く触れないので参考はコチラ
Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
最後にイベント情報。 ログのようなかんじで、Podの起動がうまくいかない場合などにもエラーが表示されることもあります。
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 12m default-scheduler Successfully assigned default/kuard to minikube Normal Pulling 12m kubelet Pulling image "gcr.io/kuar-demo/kuard-amd64:1" Normal Pulled 12m kubelet Successfully pulled image "gcr.io/kuar-demo/kuard-amd64:1" in 4.327812798s (4.327878355s including waiting) Normal Created 12m kubelet Created container kuard Normal Started 12m kubelet Started container kuard
kuardにアクセス
先程起動させたPodにポートフォワードして、ブラウザからアクセスが可能です。
$ kubectl port-forward kuard 8080:8080
まとめ
今回はPodについて勉強していきました。
kubectlコマンドでは、まだまだたくさんのオプションがあります。
重要そうなコマンドや、便利そうなコマンドは随時別の記事にて記載できたらと思います。
次回は、ヘルスチェックとボリュームについて記載した記事を投稿予定です。