はじめに
こんにちは!
本記事は「本気で学ぶKubernetes」シリーズの第4回です。このシリーズでは、Kubernetesの基礎から実践まで、段階的に学んでいきます。
このシリーズは、第1回から順に読むことで体系的に学べる構成にしています。
まだご覧になっていない方は、ぜひ最初からご覧ください!
前回は、kubectlやminikubeなどの基本ツールとコマンドを学習しました。クラスタの起動や簡単なリソースの作成もやってみました。
今回は、実際にYAMLマニフェストファイルを書いて、nginxのWebサーバーをKubernetes上にデプロイします。
この記事は人間がKubernetesの公式ドキュメントを読み漁りながら、人間の手で書いていますのでご安心ください!
前提知識
- Kubernetes、Pod、Deployment、Serviceの基本概念を理解している方
- kubectlとminikubeの基本的な使い方を知っている方
- YAMLファイルの基本的な書き方を知っている方
今回作成する構成とゴール
構成図
今回は以下のような構成を作成します。
後の記事でフロー図の正しい書き方も触れていければと思います。
nginxのDeploymentマニフェスト作成
ここからは実際にnginxのDeploymentマニフェストを作成していきます。
まず作業用のディレクトリを作成します。
mkdir -p k8s-nginx-demo
cd k8s-nginx-demo
次に、nginx-deployment.yamlというファイルを作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
このマニフェストでは、replicas: 3で3つのPodを起動します。
そして各Podはnginxコンテナを1つ持ち、それぞれポート80で待ち受けています。selector.matchLabelsとtemplate.metadata.labelsパラメータの両方にapp: nginxを指定することで、DeploymentがどのPodを管理すべきかを判断できるようなっています。
出典: Kubernetes公式ドキュメント - Deployments
Serviceマニフェスト作成
次に、外部からnginxにアクセスできるようにServiceを作成します。
nginx-service.yamlというファイルを作成します。
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
このServiceはtype: NodePortでローカル環境から直接アクセスできるようにしています。selectorでapp: nginxを指定することで、先ほど作成したDeploymentのPodにトラフィックを転送します。Serviceの80番ポートへのリクエストが、Podの80番ポート(targetPort)に転送される仕組みです。
出典: Kubernetes公式ドキュメント - Service
いざ実践
まず、minikubeクラスタを起動します。
# クラスタの起動
minikube start
# 😄 Darwin 14.5 (arm64) 上の minikube v1.37.0
# ...(省略)...
# 🏄 終了しました!kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました
# クラスタの状態確認
minikube status
# minikube
# type: Control Plane
# host: Running
# kubelet: Running
# apiserver: Running
# kubeconfig: Configured
クラスタが起動したら、今回の作業用にネームスペースを作成します。
Kubernetesではネームスペースを使ってリソースを論理的に分離できます。
今回はnginx-demoという名前でネームスペースを作成していきます。
# 現在のコンテキストを確認
kubectl config current-context
# minikube
# ネームスペースを作成
kubectl create namespace nginx-demo
# namespace/nginx-demo created
# ネームスペースの一覧を確認
kubectl get namespaces
# NAME STATUS AGE
# default Active 10m
# kube-node-lease Active 10m
# kube-public Active 10m
# kube-system Active 10m
# nginx-demo Active 5s ← 今作成したネームスペース
# デフォルトのネームスペースを nginx-demo に変更
kubectl config set-context --current --namespace=nginx-demo
# Context "minikube" modified.
これで、以降のkubectlコマンドはすべてnginx-demoネームスペース内で実行されるようになります。
出典: Kubernetes公式ドキュメント - Namespaces
Deploymentのデプロイ
作成したマニフェストを使ってDeploymentをデプロイします。
# Deploymentの適用
kubectl apply -f nginx-deployment.yaml
# deployment.apps/nginx-deployment created
# Deploymentの確認
kubectl get deployments
# NAME READY UP-TO-DATE AVAILABLE AGE
# nginx-deployment 3/3 3 3 10s
次に、ReplicaSetを確認します。
# ReplicaSetの確認
kubectl get rs
# NAME DESIRED CURRENT READY AGE
# nginx-deployment-86dcfdf4c6 3 3 3 30s
ReplicaSetはDeploymentによって自動的に作成され、指定された数のPodレプリカが常に実行されていることを保証します。
出典: Kubernetes公式ドキュメント - ReplicaSet
最後に、実際に作成されたPodを確認します。
# Podの確認
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-86dcfdf4c6-7xqzt 1/1 Running 0 50s
# nginx-deployment-86dcfdf4c6-k9n2p 1/1 Running 0 50s
# nginx-deployment-86dcfdf4c6-xm5lr 1/1 Running 0 50s
3つのPodが起動していることが確認できました!
Pod名の最後の部分(7xqztなど)はランダムに生成され、これがPodの一意な識別子になります。
詳細情報を確認したい場合は、describeコマンドを使います。
# Deploymentの詳細情報
kubectl describe deployment nginx-deployment
# Name: nginx-deployment
# Namespace: nginx-demo
# CreationTimestamp: Mon, 02 Dec 2024 10:30:00 +0900
# Labels: app=nginx
# Annotations: deployment.kubernetes.io/revision: 1
# Selector: app=nginx
# Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
# ...(省略)...
Serviceのデプロイ
次に、Serviceを作成して外部からアクセスできるようにします。
# Serviceの適用
kubectl apply -f nginx-service.yaml
# service/nginx-service created
# Serviceの確認
kubectl get svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-service NodePort 10.97.242.218 <none> 80:30080/TCP 5s
minikubeでServiceにアクセスします。
# minikubeを使ってServiceにアクセス
minikube service nginx-service -n nginx-demo
# |-------------|---------------|-------------|---------------------------|
# | NAMESPACE | NAME | TARGET PORT | URL |
# |-------------|---------------|-------------|---------------------------|
# | nginx-demo | nginx-service | 80 | http://192.168.49.2:30080 |
# |-------------|---------------|-------------|---------------------------|
# 🏃 nginx-service サービス用のトンネルを起動しています。
# 🎉 デフォルトブラウザーで nginx-demo/nginx-service サービスを開いています...
# ❗ Docker ドライバーを darwin 上で使用しているため、実行するにはターミナルを開く必要があります。
ブラウザが自動的に開き、nginxのWelcomeページが表示されます!
これで、KubernetesクラスタにnginxのWebサーバーがデプロイされて外部からアクセスできるようになりました!
ロードバランシングを確認してみる
Serviceは複数のPodにトラフィックを分散します。実際にどのPodにアクセスしているのかを見ていきます。
さらに各Podのnginxが表示する内容を変えて、リロードするたびに別のPodにアクセスされていることを合わせて確認していきます。
Pod名を取得
まず、現在動いているPodの名前を確認します。
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-6f9664446b-7c2kq 1/1 Running 0 10m
# nginx-deployment-6f9664446b-7fsbv 1/1 Running 0 10m
# nginx-deployment-6f9664446b-vtnrp 1/1 Running 0 10m
各Podのindex.htmlを書き換え
それぞれのPodに入って、表示される内容を変更します。
先ほど表示したPodのNameに対して、index.htmlをそれぞれ書き換えていきます。
# 1つ目のPod
kubectl exec nginx-deployment-6f9664446b-7c2kq -- bash -c 'echo "<h1>Pod 1</h1>" > /usr/share/nginx/html/index.html'
# 2つ目のPod
kubectl exec nginx-deployment-6f9664446b-7fsbv -- bash -c 'echo "<h1>Pod 2</h1>" > /usr/share/nginx/html/index.html'
# 3つ目のPod
kubectl exec nginx-deployment-6f9664446b-tchsp -- bash -c 'echo "<h1>Pod 3</h1>" > /usr/share/nginx/html/index.html'
curlで複数回アクセスして確認
curlコマンドで複数回アクセスしてみます。
ポート番号はサービス用のトンネル起動時のポートを利用してください。
# Service経由で複数回アクセス
for i in {1..10}; do curl -s http://localhost:50514; done
# <h1>Pod 2</h1>
# <h1>Pod 3</h1>
# <h1>Pod 3</h1>
# <h1>Pod 1</h1>
# <h1>Pod 1</h1>
# <h1>Pod 2</h1>
# <h1>Pod 2</h1>
# <h1>Pod 1</h1>
# <h1>Pod 3</h1>
# <h1>Pod 1</h1>
表示がPod 1、Pod 2、Pod 3と順番に切り替わっていることが確認できましたね!
これは、Serviceが3つのPodに対してトラフィックを分散しているためです。
Podの自動復旧を試してみる
ここからはPodの自動復旧を試してみます。
まず、現在のPod一覧を確認します。
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-6f9664446b-7c2kq 1/1 Running 0 4m56s
# nginx-deployment-6f9664446b-7fsbv 1/1 Running 0 4m56s
# nginx-deployment-6f9664446b-vtnrp 1/1 Running 0 4m56s
それでは、1つのPodを削除してみます。
# 1つ目のPodを削除
kubectl delete pod nginx-deployment-6f9664446b-vtnrp
# pod "nginx-deployment-6f9664446b-vtnrp" deleted from nginx-demo namespace
# すぐにPod一覧を確認
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-6f9664446b-7c2kq 1/1 Running 0 5m51s
# nginx-deployment-6f9664446b-7fsbv 1/1 Running 0 5m51s
# nginx-deployment-6f9664446b-tchsp 1/1 Running 0 9s ← 新しいPodが作成される
削除したPodの代わりに、新しいPodが自動的に作成されました!
今回の構成ではDeploymentでreplicas: 3を設定していました。これに基づいて、常に3つのPodが動作するように制御されます。
# ReplicaSetを確認
kubectl get rs
# NAME DESIRED CURRENT READY AGE
# nginx-deployment-86dcfdf4c6 3 3 3 10m
スケーリングを試してみる
Kubernetesでは、実行中のPod数を動的に変更できます。
例えば、アクセスが急増してサーバーの負荷が高くなった時はPod数を増やして負荷分散し、夜間などアクセスが少ない時間帯はPod数を減らしてリソースを節約するといった運用が可能です。
今回はkubectl scaleコマンドを使って手動でスケーリングしてみますが、本番環境では後述するHorizontal Pod Autoscaler (HPA)を使って負荷に応じて自動的にスケールする設定も可能です。
スケールアウト(Podの数を増やす)
# Pod数を5つに増やす
kubectl scale deployment nginx-deployment --replicas=5
# deployment.apps/nginx-deployment scaled
# 確認
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-86dcfdf4c6-def34 1/1 Running 0 5m
# nginx-deployment-86dcfdf4c6-ghi56 1/1 Running 0 5m
# nginx-deployment-86dcfdf4c6-jkl78 1/1 Running 0 3s ← 新しく追加
# nginx-deployment-86dcfdf4c6-mno90 1/1 Running 0 3s ← 新しく追加
# nginx-deployment-86dcfdf4c6-xm5lr 1/1 Running 0 20m
kubectl get rs
# NAME DESIRED CURRENT READY AGE
# nginx-deployment-86dcfdf4c6 5 5 5 25m
スケールイン(Podの数を減らす)
# Pod数を2つに減らす
kubectl scale deployment nginx-deployment --replicas=2
# deployment.apps/nginx-deployment scaled
# 数秒後に実行します
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-86dcfdf4c6-def34 1/1 Running 0 9m
# nginx-deployment-86dcfdf4c6-xm5lr 1/1 Running 0 24m
このように、kubectl scaleコマンドで簡単にPod数を増減できます。
実際の運用でのスケーリング例
実際の運用では、こんな場面でスケーリングを使います。
スケールアウトするケース
- アクセスが急増してCPU使用率が80%を超えた
- テレビCMやSNS拡散でトラフィックが10倍になった
- セール開始時刻に合わせて事前にPod数を増やす
本番環境では、トラフィックの増減に応じてPod数を自動的に調整する「Horizontal Pod Autoscaler (HPA)」という機能もあります。
出典: Kubernetes公式ドキュメント - Deploymentのスケーリング
リソースのクリーンアップ
作業が一通り終わったので、作成したリソースを削除します。
# Serviceの削除
kubectl delete -f nginx-service.yaml
# service "nginx-service" deleted from nginx-demo namespace
# Deploymentの削除
kubectl delete -f nginx-deployment.yaml
# deployment.apps "nginx-deployment" deleted from nginx-demo namespace
# リソースが削除されたことを確認します
kubectl get all
# No resources found in nginx-demo namespace.
Deploymentを削除すると、関連するReplicaSetとPodも自動的に削除されます。
最後に、作成したネームスペースも忘れずに削除しておきましょう。
# デフォルトネームスペースに戻します
kubectl config set-context --current --namespace=default
# Context "minikube" modified.
# ネームスペースを削除します
kubectl delete namespace nginx-demo
# namespace "nginx-demo" deleted
ネームスペースを削除すると、その中のすべてのリソース(Pod、Service、Deploymentなど)も一緒に削除されます。
もしminikubeクラスタ自体を停止したい場合は、以下のコマンドを実行します。
# クラスタの停止(データは保持される)
minikube stop
# クラスタの完全削除(全データ削除)
minikube delete
まとめと次回予告
今回はマニフェストファイルを作成して、nginxのWebサーバーをKubernetes上にデプロイするところまで実施しました。
PodへのラウンドロビンのアクセスやPodのスケーリングについてコマンドベースで確認でき、Kubernetes上で稼動する仕組みとその解像度がかなり高くなって来たと思います。
次回はClusterIP / NodePort / LBについて再度焦点を当てて概念や仕組みを確認していければと思います。
それでは、また明日!

