Kubernetesマニフェストファイル完全入門:YAMLの書き方からベストプラクティスまで
やあ、みんな!クラウドインフラの世界へようこそ!
特にKubernetes (k8s) に興味を持ってくれた君、大正解だよ!k8sは、コンテナ化されたアプリケーションを自動化し、デプロイ、スケーリング、管理するための強力なツールなんだ。そして、そのk8sを使いこなす上で避けては通れないのが「マニフェストファイル」。
「YAML?なんだか難しそう…」って思ったかもしれないけど、心配いらないよ。このブログ記事では、マニフェストファイルの役割から、具体的な書き方、そして現場で役立つベストプラクティスまで、優しく丁寧に解説していくからね。これをマスターすれば、日々のk8s運用が劇的に楽になること間違いなし!
さあ、一緒にk8sの世界を深掘りしていこう!
1. マニフェストファイルの役割と基本構造:k8sの「設計図」
まず、マニフェストファイルって一体何者なんだろう?
簡単に言うと、マニフェストファイルはKubernetesクラスタに対して、「こんな状態にしてほしい」と指示するための「設計図」なんだ。例えば、「このアプリケーションを3つ動かしてほしい」「このコンテナイメージを使ってほしい」「このポートを開放してほしい」といった、クラスタに望む状態をYAML形式で記述するんだ。
k8sは、このマニフェストファイルを受け取って、そこに書かれた状態と現在のクラスタの状態を常に比較し、乖離があれば自動的に修正してくれる。まるで、優秀な執事のように、君の指示通りにクラスタを動かしてくれるわけだね。
マニフェストファイルの基本構造
マニフェストファイルは、主に以下の要素で構成されているよ。
これはコメントです。
apiVersion: v1 # Kubernetes APIのバージョンを指定します。
kind: Pod # 作成するオブジェクトの種類を指定します。(例: Pod, Deployment, Serviceなど)
metadata:
name: my-first-pod # オブジェクトの名前を指定します。
labels:
app: my-app # オブジェクトにラベルを付けます。後で検索などに使えます。
spec:
containers:
- name: my-container # コンテナの名前を指定します。
image: nginx:latest # 使用するコンテナイメージを指定します。
ports:
- containerPort: 80 # コンテナが公開するポートを指定します。
- `apiVersion`: Kubernetes APIのバージョンを指定します。APIにはバージョンがあり、利用できるフィールドや機能が異なる場合があります。
- `kind`: 作成したいKubernetesオブジェクトの種類を指定します。後述する「APIバージョンとキンド(Kind)の種類」で詳しく解説するね。
- `metadata`: オブジェクトに関するメタデータ(名前、ラベル、アノテーションなど)を定義します。
- `name`: オブジェクトの名前。クラスタ内で一意である必要があります。
- `labels`: オブジェクトにキーと値のペアでラベルを付けます。これを使うと、特定のオブジェクト群をまとめて管理したり、検索したりするのが楽になります。
- `spec`: オブジェクトの「仕様」を定義します。これは、そのオブジェクトがどのような状態であるべきかを具体的に記述する部分なんだ。`kind`によって `spec` の内容は大きく変わるよ。
2. APIバージョンとキンド(Kind)の種類:k8sの「命令書」の種類
`apiVersion` と `kind` は、マニフェストファイルの最も基本的な部分であり、k8sに「何を」してほしいのかを伝えるための重要な要素だ。
APIバージョン (`apiVersion`)
Kubernetesは、APIの進化に合わせてバージョン管理を行っている。一般的に、以下のようなバージョンが存在するよ。
- `v1`: コアAPIグループ。Pod, Service, Namespaceなど、最も基本的なオブジェクトに使われることが多い。
- `apps/v1`: Deployment, StatefulSet, DaemonSetなど、アプリケーションのデプロイや管理に関連するオブジェクトに使われる。
- `batch/v1`: Job, CronJobなど、バッチ処理に関連するオブジェクトに使われる。
- `networking.k8s.io/v1`: Ingress, NetworkPolicyなど、ネットワーク関連のオブジェクトに使われる。
新しいバージョンほど、機能が豊富だったり、より洗練された設計になっていることが多い。しかし、古いバージョンでも問題なく動作するものもあるので、ドキュメントを確認しながら適切なバージョンを選択することが大切だよ。
キンド(Kind)の種類
`kind` は、作成したいKubernetesオブジェクトの種類を表す。代表的なものをいくつか紹介しよう。
- `Pod`: Kubernetesで管理できる最小のデプロイ可能な単位。1つ以上のコンテナとその共有リソース(ストレージ、ネットワーク)のセット。
- ポイント: Podは通常、直接作成するよりも、Deploymentなどのコントローラーを使って管理されることが多い。これは、Podは一度作成されると、そのPod自体は再起動しないため、障害発生時に自動的に再作成されないからなんだ。
- `Deployment`: Podのデプロイメントとローリングアップデートを管理するためのオブジェクト。Podのレプリカ数(いくつ動かすか)を指定し、k8sがその数を維持してくれる。
- ポイント: アプリケーションのデプロイに最もよく使われる。障害発生時には、k8sが自動的に新しいPodを作成して、指定した数のPodが常に稼働するようにしてくれるんだ。
- `Service`: Pod群へのアクセスを抽象化し、安定したネットワークエンドポイントを提供するオブジェクト。PodのIPアドレスは変動する可能性があるけど、ServiceのIPアドレスは固定される。
- ポイント: アプリケーション間の通信や、外部からのアクセスを可能にするために不可欠。
- `Namespace`: クラスタ内に論理的な分離空間を作成するオブジェクト。複数のチームやプロジェクトでクラスタを共有する際に、リソースを整理するために使われる。
- ポイント: 権限管理やリソースの隔離に役立つ。
- `Ingress`: HTTP/HTTPSトラフィックをクラスタ内のServiceにルーティングするためのAPIオブジェクト。外部からクラスタ内のWebアプリケーションにアクセスする際に利用される。
- ポイント: ホスト名やパスに基づいてルーティングを設定できる。
これらの他にもたくさんの`kind`があるけど、まずはこれらを理解しておけば、基本的なアプリケーションのデプロイはできるようになるよ。
HelloWorld的な動作確認:最初のPodを動かしてみよう!
それでは、実際に簡単なマニフェストファイルを作成して、Podを動かしてみよう!
my-first-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: hello-world-pod # Podの名前
labels:
app: hello-world # ラベル
spec:
containers:
- name: hello-container # コンテナの名前
image: busybox:1.28 # lightweightなコンテナイメージを使用
command: [“sh”, “-c”, “echo ‘Hello, Kubernetes! This is my first Pod.’ && sleep 3600”] # コンテナで実行するコマンド
このファイルを `my-first-pod.yaml` という名前で保存して、以下のコマンドでクラスタに適用してみよう。
kubectl apply -f my-first-pod.yaml
`kubectl apply` コマンドは、マニフェストファイルの内容をk8sに伝えて、望む状態を実現するように指示してくれる。
適用が成功したら、以下のコマンドでPodの状態を確認できるよ。
kubectl get pods
`hello-world-pod` という名前のPodが `Running` 状態になっていれば成功だ!
さらに、Podの中身を確認するには `kubectl describe pod
kubectl describe pod hello-world-pod
kubectl logs hello-world-pod
これで、君の最初のKubernetes Podが動いた!おめでとう!🎉
3. リクエストとリミット(リソース管理)の重要性:クラスタの「健全性」を守るために
さて、アプリケーションを動かす上で、リソース管理は非常に重要だ。特に、Kubernetesクラスタのように複数のアプリケーションがリソースを共有する環境では、健全な運用のためには欠かせない設定なんだ。
マニフェストファイルでは、`spec.containers` の下に `resources` というフィールドで、コンテナが要求するCPUとメモリの量(リクエスト)と、使用できる上限(リミット)を設定できる。
… (前略) …
spec:
containers:
- name: my-app-container
image: my-app-image
resources:
requests: # コンテナが要求するリソース量
memory: “64Mi” # 64メガバイトのメモリ
cpu: “250m” # 0.25 CPUコア (1000m = 1 CPUコア)
limits: # コンテナが使用できるリソースの上限
memory: “128Mi” # 128メガバイトのメモリ
cpu: “500m” # 0.5 CPUコア
… (後略) …
リクエスト (Requests)
- CPU: コンテナが「最低限これだけは必要」と主張するCPU時間。スケジューラ(Podをどのノードに配置するかを決めるk8sのコンポーネント)は、このリクエスト値を元に、ノードの空きリソースを計算してPodを配置する。
- Memory: コンテナが「最低限これだけは確保してほしい」と主張するメモリ量。k8sは、Podがリクエストされたメモリを超えて使用しようとした場合、そのPodをOOMKilled(Out Of Memory Killed)という状態にして終了させる可能性がある。
リミット (Limits)
- CPU: コンテナが使用できるCPU時間の「上限」。この上限を超えた場合、コンテナのCPU使用は制限される(throttling)。
- Memory: コンテナが使用できるメモリの「上限」。この上限を超えた場合、コンテナはOOMKilledされて強制終了される。
なぜリクエストとリミットが重要なのか?
1. クラスタの安定性維持:
- リクエストを設定することで、各Podが必要とするリソースが確保され、他のPodがリソースを使いすぎることで発生するパフォーマンス低下やクラッシュを防ぐことができる。
- リミットを設定することで、特定のPodが暴走してクラスタ全体のリソースを枯渇させることを防ぎ、他のPodやシステムプロセスに影響が及ぶのを抑制できる。
2. 効率的なリソース利用:
- スケジューラはリクエスト値を元にPodを配置するため、リクエストを適切に設定することで、ノードのリソースをより効率的に利用できるようになる。
- リミットを設定することで、過剰なリソース消費を防ぎ、コスト最適化にも繋がる。
3. 予測可能性の向上:
- アプリケーションのパフォーマンスが、リソース不足によって突然悪化するリスクを減らすことができる。
設定のベストプラクティス
- リクエストとリミットを同じ値に設定する: これが最もシンプルで、リソースの予測可能性を高める方法。ただし、CPUに関しては、コンテナが一時的にリクエスト値を超える処理を行う場合があるため、CPUリミットをリクエスト値より少し高く設定することも検討する。
- 実際の使用量を計測する: アプリケーションの実際のCPU/メモリ使用量をモニタリングツール(Prometheusなど)で計測し、それを元にリクエストとリミットを設定するのが理想。
- デフォルト値の理解: もしリクエストやリミットを設定しない場合、k8sは「無制限」として扱う。これは開発環境では許容されることもあるが、本番環境では絶対に避けるべき。
- LimitRangeの活用: Namespaceごとにデフォルトのリクエスト/リミットを設定するLimitRangeというリソースを使うと、マニフェストファイルに毎回記述する手間を省ける。
リソース設定は、最初は少し難しく感じるかもしれないけど、クラスタを安定稼働させるためには絶対にマスターしておきたいスキルだよ。
4. 可読性と保守性を高めるYAML記述のコツ:チームで「読みやすい」コードを
マニフェストファイルは、単にk8sに指示を出すだけでなく、チームメンバーと共有し、長期的に保守していくための「コード」でもあるんだ。だからこそ、可読性と保守性を意識した書き方が重要になる。
1. コメントを効果的に活用する
YAMLはコメントが書ける。なぜその設定にしたのか、この部分は何を意味するのか、などをコメントで補足しておくと、後から見返したときに理解しやすくなる。
Deployment for the main web application
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-deployment
namespace: production # このDeploymentはproduction Namespaceにデプロイされます
spec:
replicas: 3 # 常に3つのPodを起動させておく
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp # Podのラベル。Deploymentのselectorと一致させる必要があります。
spec:
containers:
- name: webapp-container
image: my-docker-repo/my-webapp:v1.2.0 # 使用するコンテナイメージとそのバージョン
ports:
- containerPort: 8080
resources: # リソース要求と制限を設定
requests:
memory: “128Mi”
cpu: “250m”
limits:
memory: “256Mi”
cpu: “500m”
2. インデントと空白を意識する
YAMLはインデント(字下げ)が非常に重要。インデントがずれると、パースエラーの原因になる。エディタの自動インデント機能や、YAML Linter(後述)を活用しよう。
- スペースを使用する: タブではなくスペースでインデントするのが一般的。
- 一貫したインデント幅: 通常は2スペースか4スペースで統一する。
3. 命名規則を定める
`metadata.name` や `labels` のキー、コンテナ名などは、チームで一貫した命名規則を定めることが大切。例えば、
- 小文字の英数字とハイフン (`-`) を使用する。
- 意味のある名前をつける(例: `user-service-api`, `frontend-webserver`)。
- 環境(`dev`, `staging`, `prod`)やアプリケーション名を含める。
4. YAML Linter / Formatter を利用する
IDE(VS Codeなど)には、YAMLの構文チェックや整形をしてくれる拡張機能がたくさんある。
- VS Code: `YAML` 拡張機能などをインストールすると、リアルタイムで構文エラーを指摘してくれたり、整形機能が使えるようになる。
- CLIツール: `yamllint` や `prettier` などのツールをCI/CDパイプラインに組み込むことで、マニフェストファイルの品質を維持できる。
5. テンプレート化と再利用 (Helm, Kustomize)
マニフェストファイルが増えてくると、似たような設定を何度も書くことになる。そんなときに役立つのが、テンプレート化やカスタマイズツールだ。
- Helm: Kubernetesのパッケージマネージャー。テンプレートエンジンを使って、再利用可能なアプリケーションのチャート(パッケージ)を作成できる。変数を渡すことで、簡単にデプロイ設定を変更できる。
- Kustomize: Kubernetesネイティブな設定管理ツール。ベースとなるマニフェストに、パッチを当てたり、リソースを追加したりして、環境ごとの設定を差分で管理できる。
これらは初心者向けではないかもしれないけど、k8sに慣れてきたらぜひ触れてみてほしい。マニフェストファイル管理の生産性が格段に向上するはずだよ。
6. バージョン管理システム (Git) で管理する
マニフェストファイルは、アプリケーションのコードと同じように、Gitなどのバージョン管理システムで管理しよう。
- 変更履歴の追跡: いつ、誰が、どのような変更を加えたのかを記録できる。
- ロールバック: 問題が発生した場合に、以前の状態に簡単に戻せる。
- コードレビュー: チームメンバーによるレビューを経て、マニフェストファイルの品質を向上させることができる。
まとめ:マニフェストファイルはk8s運用の「要」
どうだったかな? Kubernetesマニフェストファイルの世界、少しは身近に感じられただろうか?
マニフェストファイルは、k8sクラスタに「何を」してほしいのかを指示する「設計図」であり、その書き方一つで、クラスタの安定性、効率性、そして保守性が大きく変わってくる。
今回学んだこと、
- マニフェストファイルの基本構造と役割
- `apiVersion` と `kind` の重要性
- `requests` と `limits` によるリソース管理の必要性
- 可読性と保守性を高めるYAML記述のコツ
これらは、k8sを現場で活用していく上で、まさに「根幹」となる知識だ。
最初は覚えることも多くて大変かもしれないけど、一つずつ試しながら、実際に手を動かしていくことで、必ず身についていくよ。そして、その先に、運用が劇的に楽になる未来が待っている。
もし分からないことがあったら、いつでも聞いてほしい。君のk8sエンジニアとしての旅を、心から応援しているよ!頑張ってね!