はじめに
アプリケーションの開発を行うエンジニアであっても、インフラに関する事もある程度は知っておく必要がありそう…。
というわけでコンテナオーケストレーションについて理解を深めておこうと思い、kubernetesのマニフェストファイルについて理解してみたので、その備忘録を残す。
kubernetesについて
kubernetesとは?というのは公式や、以下を参照。
以降では実際にマニフェストファイルを作成して、kubernetesオブジェクトを作成してみようと思う。
初めてのマニフェストファイル Hello Worldコンテナを作成する
マニフェストファイルとは?という話をするより、実物を見る方がいい気がするので実物を見てからマニフェストファイルとは?そのファイルの中身の構成は?などについてみていく。
以下はPodを作成するマニフェストファイル。
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test
namespace: default
labels:
env: study
spec:
containers:
- name: hello-world
image: hello-world
ソースコード全体は以下。
上記のマニフェストファイルを適用して、Pod(以下の「kubernetesのリソース(作成できるオブジェクトの種類)」の章で詳細を見ていく)を作成・状態確認・削除をしてみると以下のような感じになる。
以降の章で何をやったのか?などの詳細については見ていく。
[root@control-plane docker-kubernetes]# kubectl apply -f pod.yaml
pod/test created
[root@control-plane docker-kubernetes]# kubectl get -f pod.yaml
NAME READY STATUS RESTARTS AGE
test 0/1 CrashLoopBackOff 1 11s
[root@control-plane docker-kubernetes]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/test 0/1 Completed 3 63s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d13h
[root@control-plane docker-kubernetes]# kubectl delete -f pod.yaml
pod "test" deleted
[root@control-plane docker-kubernetes]# kubectl get pods
No resources found in default namespace.
[root@control-plane docker-kubernetes]# kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d13h
マニフェストファイルとは?
そもそもkubernetesにはkubectlという、Kubernetes APIを使用したkubernetesを操作するためのコマンドラインツールがある(kubernetes APIのリファレンスに書かれている内容はkubectlでできるという事)。
そのkubectlを使ってkubernetesのオブジェクトを作成する事もできるが、コマンドから作成するのではなく、以下のようにオブジェクトの定義を作成してそれを適用(kubernetesに反映)という手順でオブジェクトを作成する事もできる。この定義を記載したものがマニフェストファイルでありyaml形式で記述する。これによりIaC(インフラのコード化)もできる(なので基本的にはこのマニフェストファイルを用いたオブジェクトの作成(kubernetesリソースの構成定義)が一般的)。
マニフェストファイルの構成
大きく分けて以下の3つのブロックから構成されている(コメントとなっているのはyamlのコメントなのでマニフェストファイルとは関係ない)。
※この3ブロックで構成されるが、yamlのフィールドとして必須である項目は以下の4つフィールドになる(公式を参照)。
・apiVersion
・kind
・metadata
・spec
・参考:必須フィールド
オブジェクトの種別
そのままだが、作成したいオブジェクトの種類を設定するためのフィールド。具体的には、"apiVersion"、"kind"で指定をする。
apiVersion
どのバージョンのKubernetes APIを利用してオブジェクトを作成するか?を設定するもの。これはAPI Referenceを参照する事で判断ができ、例えば今回のようにPodというリソースのオブジェクトを作成したい場合であれば、以下のようにリファレンスに書かれているので"v1"となる。
このapiVersionは次に出てくるkindに応じて異なっており、基本的には"Group/Version"という規則で記載する必要がある。ただしGroupがcoreであるものは省略可能。なのでPodの場合には"v1"と表記できる。逆に、例えば以下のようにkindがIngressである場合(Ingressというリソースのオブジェクトを作成する際)には、Groupが"networking.k8s.io"なのでapiVersionは以下のように書く必要がある。
apiVersion: networking.k8s.io/v1
kind: Ingress
kind
どの種類のオブジェクトを作成するか?を設定するもの。指定できるものはリソースタイプ一覧に書かれている(kubectlで"kubectl api-resources"としてもリソース一覧を確認できる)。
今回はPodのオブジェクトを作成したかったのでPodを指定している。
メタデータ
オブジェクトを一意に特定するための情報で、"name"、"namespace"、"labels"というフィールドで設定する。
namespace、namse
API Conventions(GitHubのページ)を読むと、namespace, name, uidのいずれも必須と書かれているが、以下の理由からnamespaceとuidは省略可能。
・namsespace:未指定の場合"default"というnamespaceが割り当てられるため(以下、公式からの引用)
The default namespace is 'default'.
・uid:kubernetesで自動生成するため(以下、公式からの引用)
オブジェクトを一意に識別するためのKubernetesが生成する文字列
今回は特に意味のある名前を付けなくてもいいのでnameは"test"として、namespaceは"default"とした(namsespaceは何も指定しなければ"default"になるので書かなくてもいいが)。
※ちなみに、上記の事からnameは省略不可という事になるが、実際にnameをコメントアウトして"kubectl apply -f pod.yaml"を実行すると以下のようにエラーになる(labelsは以下で見るようにオプションの項目)。
[root@control-plane docker-kubernetes]# kubectl apply -f pod.yaml
error: error when retrieving current configuration of:
Resource: "/v1, Resource=pods", GroupVersionKind: "/v1, Kind=Pod"
Name: "", Namespace: "default"
from server for: "pod.yaml": resource name may not be empty
apiVersion: v1
kind: Pod
metadata:
# name: test
# namespace: default ← 省略可なのでコメントアウト
# labels: ← 省略可なのでコメントアウト
# env: study
spec:
containers:
- name: hello-world
image: hello-world
※上記のGitHubのページはオブジェクトのspec(仕様)とstatus(状態)の章にある以下の記述の「Kubernetes API Conventions」から飛べる。
spec、status、metadataに関するさらなる情報は、Kubernetes API Conventionsをご確認ください。
labels
ユーザーによる整理を目的としたもので、してしなくも問題ないもの。今回はあえて勉強用のものだよという意味を持たせるために、env(環境)というキーにstudyを設定してみた。
Labels are intended for organizational purposes by end users
・参考:ラベル(Labels)とセレクター(Selectors)
作成するオブジェクトの理想状態の定義
これは少しわかりにくいが、そもそもkubernetesの思想としては、ある状態を維持するように自動で色々調整する事で、人が何かをしなくても済む=運用を楽にする、というものがある。具体的には公式に以下のように書かれている通り、色々なリソースに対してこうなっていてほしいを設定していく。
実行したいアプリケーションやその他のワークロード、使用するコンテナイメージ、レプリカ(複製)の数、どんなネットワークやディスクリソースを利用可能にするかなど
spec
上記で見てきた、理想の状態を実際に定義するフィールド。どんな設定をするのか?は作成するオブジェクトによって様々だが、例えばPodであればPodSpec v1 coreにどんな設定項目があるか?が書かれている。
今回は初めてのマニフェストファイルという事で、特に複雑な設定はしないのでcontainersだけ設定した(containersの中でもさらに設定ができるが、それはContainer v1 coreに書かれている)。具体的にはhello-worldのDockerイメージを使って"hello-world"という名前のコンテナを構築するという設定をしている。
・参考:概要
kubernetesのリソース(作成できるオブジェクトの種類)
続いて、上記の中で出てきたPodについて何か?についてみていく。Podとはkubernetesのリソースの1つで、コンテナを管理するための最小単位。Podは以下の図のようにPod:コンテナ=1:1というわけではなく、Pod:コンテナ=1:xという関係で、Podには複数のコンテナが存在する事もある。複数のコンテナをまとめて1つのユニットとして管理することで、(Docker)コンテナの使いにくさを解消する事ができる(複数のコンテナを1つのPodに作成できるのか?は、おまけの「Podに複数のコンテナを作成できるってホント?」を参照)。
Pod以外のkubernetesのオブジェクトとして作成できるもの一覧(リソースタイプ一覧)は公式に書かれている。また、kubectlで"kubectl api-resources"としてもリソース一覧を確認できる。
[root@control-plane docker-kubernetes]# kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
pods po v1 true Pod
...
※ちなみに、今回「初めてのマニフェストファイル Hello Worldコンテナを作成する」で作成したPodのオブジェクトについてみると、以下のように図示できる(ノードというのが出てきたが、これはおまけの「kubernetesの構成の補足」を参照)。
kubectlから確認するなら以下のようにして確認できる(今回はPod名"test"でPodを作成した(マニフェストファイルのname)ので"kubectl describe pod test"とすればPodの詳細を見る事ができ、実際にhello-worldコンテナがある事が存在することが分かる)。
[root@control-plane docker-kubernetes]# kubectl describe pod test
Name: test
Namespace: default
Priority: 0
Node: control-plane.minikube.internal/192.168.92.128
Start Time: xxx, xx Mar 2022 13:41:35 +0900
Labels: env=study
Annotations: <none>
Status: Running
IP: 172.17.0.3
IPs:
IP: 172.17.0.3
Containers:
hello-world:
Container ID: docker://71582a78517436640864d6061b7cbf29dd34b95b9d491b2000dd0a209dc034b6
Image: hello-world
Image ID: docker-pullable://hello-world@sha256:4c5f3db4f8a54eb1e017c385f683a2de6e06f75be442dc32698c9bbe6c861edd
Port: <none>
Host Port: <none>
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: xxx, xx Mar 2022 13:42:29 +0900
Finished: xxx, xx Mar 2022 13:42:29 +0900
Ready: False
Restart Count: 3
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jb9bf (ro)
...
※公式にも以下のように書かれているが、コンテナはDockerコンテナとは限らないが、はじめのうちはkubernetesのコンテナ=Dockerコンテナというイメージだと理解がしやすいみたいなのでコンテナ=Dockerコンテナでよさそう。
備考: KubernetesはDockerだけでなく複数のコンテナランタイムをサポートしていますが、Dockerが最も一般的に知られたランタイムであるため、Docker由来の用語を使ってPodを説明するのが理解の助けとなります。
・参考:Pod
kubectlのコマンドについて
最後に、マニフェストファイルから実際にオブジェクトを作成するためにkubectlコマンドを使ったが、そのコマンドで何をしていたか?を見ていく。
・"kubectl apply -f pod.yaml"
pod.yamlの定義を使用してPodを作成
・"kubectl get pods"
すべてのPodの一覧をプレーンテキスト形式で表示
・"kubectl delete -f pod.yaml"
pod.yamlファイルで指定された名前を用いてPodを削除
・参考:kubectlの概要
・参考:kubectlリファレンス
・参考:例: 一般的な操作
まとめとして
今回はkubernetesのHello World!に続いて、マニフェストファイルから実際にkubernetesのオブジェクトを作成するのをやってみた。今後さらにkubernetesに関して色々理解を深めて良ければと思っている。
おまけ
Podに複数のコンテナを作成できるってホント?
以下のようなマニフェストファイルを作成して、kubernetesに適用して"kubectl describe pod test"で確認してみると、確かにコンテナが2つ作成されている事が確認できる。
apiVersion: v1
kind: Pod
metadata:
name: test
namespace: default
labels:
env: study
spec:
containers:
- name: hello-world
image: hello-world:linux
- name: centos
image: centos:7
[root@control-plane docker-kubernetes]# kubectl describe pod test
Name: test
Namespace: default
Priority: 0
Node: control-plane.minikube.internal/192.168.92.128
Start Time: xxx, xx Mar 2022 13:49:13 +0900
Labels: env=study
Annotations: <none>
Status: Running
IP: 172.17.0.3
IPs:
IP: 172.17.0.3
Containers:
hello-world:
Container ID: docker://d39b38bed1c62fe56b138ead0a3efb392bba497f722123bd6ea3f2f93cad3c02
Image: hello-world:linux
Image ID: docker-pullable://hello-world@sha256:19c35675aac535e0f5803f12000ed7ffae510a43f1e3a839e7f4a9942a03dace
Port: <none>
Host Port: <none>
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: xxx, xx Mar 2022 13:49:20 +0900
Finished: xxx, xx Mar 2022 13:49:20 +0900
Ready: False
Restart Count: 1
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jb9bf (ro)
centos:
Container ID: docker://9aa4c62ddfc46e346627d301deca3bc6cf68c719ef8061ebfb28bb2a47412f07
Image: centos:7
Image ID: docker-pullable://centos@sha256:c73f515d06b0fa07bb18d8202035e739a494ce760aa73129f60f4bf2bd22b407
Port: <none>
Host Port: <none>
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: xxx, xx Mar 2022 13:49:20 +0900
Finished: xxx, xx Mar 2022 13:49:20 +0900
Ready: False
Restart Count: 1
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-jb9bf (ro)
...
kubernetesの構成の補足
「kubernetesのリソース(作成できるオブジェクトの種類)」で「ノード」というものが出てきたが、kubernetesにはマスターノードとワーカーノードという概念があり、マスターノードは各ワーカーノードを管理する役割を持つ。イメージとしては以下の図のような感じ。そして、この図の中のワーカーノードにPodなどの各種kubernetesのオブジェクト(リソース)が配置される。
※ただし、minikubeの場合にはマスターノード・ワーカーノードの区別がないシングルノードの環境(ネットワーク)になる(以下、公式からの引用)。
PC上のVM内でシングルノードのKubernetesクラスタを実行する
実際にkubectlでノードの中身を見てみると、確かに"control-plane.minikube.internal"というノードが見つかり、そのノードには"test"というPodがある事が分かる(Namespaceが"kube-system"であるものはkubernetesによって作成されたオブジェクト)。
[root@control-plane docker-kubernetes]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
control-plane.minikube.internal Ready control-plane,master 48m v1.20.7
[root@control-plane docker-kubernetes]# kubectl describe nodes control-plane.minikube.internal
Name: control-plane.minikube.internal
Roles: control-plane,master
...
Non-terminated Pods: (8 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
default test 0 (0%) 0 (0%) 0 (0%) 0 (0%) 39m
kube-system coredns-74ff55c5b-6jz4p 100m (5%) 0 (0%) 70Mi (1%) 170Mi (4%) 48m
kube-system etcd-control-plane.minikube.internal 100m (5%) 0 (0%) 100Mi (2%) 0 (0%) 48m
kube-system kube-apiserver-control-plane.minikube.internal 250m (12%) 0 (0%) 0 (0%) 0 (0%) 48m
kube-system kube-controller-manager-control-plane.minikube.internal 200m (10%) 0 (0%) 0 (0%) 0 (0%) 48m
kube-system kube-proxy-mmczz 0 (0%) 0 (0%) 0 (0%) 0 (0%) 48m
kube-system kube-scheduler-control-plane.minikube.internal 100m (5%) 0 (0%) 0 (0%) 0 (0%) 48m
kube-system storage-provisioner 0 (0%) 0 (0%) 0 (0%) 0 (0%) 48m
...
※以下の記事にkubernetesの全体的な概念についてはまとめている。