Kubernetesで自動復旧するWebサーバを構築することがこの記事の目標です。Kubernetesについては概要がわかった状態で見ていただけると理解しやすいと思います。
特に、Kubernetesを学ぶうえで重要なReplicaSet、Deploymentについても解説し、それらを使ったWebサーバ構築を行っています。実際に手を動かしながら理解できる内容となっておりますので、見ていっていただけると幸いです。
- マニフェストの書き方
- ReplicaSet、Deploymentの概要
- Kubernetesを用いたWebサーバの構築方法
前提
- 筆者のPCはM1 Macobook Pro、macOS 15.6.1
- Kubernetesクラスタは kind を用いて構築
kindの環境構築がまだの方は、この記事を読む前に以下の記事を読んでいただけると良いです。
マニフェストについて
まず、Kubernetes クラスタ上でリソースの設定を行うのに必要な マニフェスト とよばれるファイルの書き方について概説します。
ここでは掻い摘んで解説をするので、詳細については以下の公式ドキュメントを御覧ください。
マニフェストとは
Kubernetesで使用するオブジェクトの設定内容を書いたファイルのことです。マニフェストには、オブジェクトの仕様(sepc)や状態(status)を書いておきます。Kubernetesは、マニフェストに書かれたオブジェクトが常に存在し続けるように動きます。
例えば、マニフェストには2つのPodを実行するよう書かれてあったとき、2つの内1つのPodが停止した際は新しいPodを立ち上げて、常に2つのPodがあるように動いてくれます。これにより、耐障害性の高いアプリケーションの作成の基盤として優れています。
マニフェストの書き方
それでは次に、マニフェストの書き方を見ていきましょう。マニフェストはYAML形式またはJSON形式で記述されます。この節では、YAML形式における書き方および、マニフェストに記載する必須のフィールドについて解説します。
必須のフィールド
マニフェストには以下のことを必ず書く必要があります。
- apiVersion
- 使用するKubernetesAPIのバージョン
- kind
- 作成するオブジェクトの種類
- metadata
- オブジェクトを一意に特定するための情報
- spec
- 作成するオブジェクトのあるべき状態
上記のことを記載した最小構成のマニフェストは以下のようになります。
apiVersion: v1
kind: Pod
metadata:
name: httpd
spec:
containers:
- name: httpd
image: httpd:alpine3.22これは、httpd:alpine3.22 によりデプロイしたコンテナを1つ持つPodを作成するマニフェストです。
specの部分については、作成するリソース毎に書き方が変わります。詳細を知りたい方は、以下のページを参照ください。
上記のマニフェストでは、httpd:alpine3.22 によりデプロイしたコンテナを持つPodを作成しましたが、現場においてはPod単独での作成はコンテナの冗長化ができないため推奨されません。それでは、実際の本番環境ではどうしているかというと、Deployment および その下に位置するReplicaSetというリソースを作り、アプリケーションが稼働するPodはReplicaSetが作成しています。そのため、次にこれら Deployment および ReplicaSet について解説します。
ReplicaSet と Deployment
この節では、実際の現場で使われることが多い ReplicaSet と Deployment について解説します。結論としては、Pod、ReplicaSet、Deployment は以下の図のような関係になっているので、これらを念頭に解説を読んでいただければ理解が深まると思います。

ReplicaSet
ReplicaSetは、指定した数だけPodを複製するリソースになります。具体的には、 replicasで複製する数を指定します。実際のマニフェストの例としては以下になります。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: httpd-server
labels:
name: httpd-server
spec:
# replicasに指定した数だけ Pod を複製。ここでは3つ作成する。
replicas: 3
selector:
matchLabels:
# templateで指定するlabelsと一致する必要あり
app: httpd
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: httpd
image: httpd:alpine3.22コメントでも書いてる通りselector内のmatchLabelsで指定する文字列は、その下のtemplate内のlabelsと一致する必要があります。
上記マニフェストを実行してPodの状態を確認すると、以下のように3つのPodが作成されることが分かります。
$ kubectl get pod --namespace default
NAME READY STATUS RESTARTS AGE
httpd-server-28b94 1/1 Running 0 2m27s
httpd-server-6lpkz 1/1 Running 0 2m27s
httpd-server-k6mbj 1/1 Running 0 2m27sDeployment
Deployment は ReplicaSet の上位概念にあたり、実際の現場では ReplicaSetと併せて使用されています。Podの冗長化という点だけ見ると、ReplicaSetまでで十分と感じるかもしれません。しかし、本番サービスのコンテナを更新したい場合、ReplicaSet だけだとすべてのPodを作り直す必要があり、サービスを提供できない時間が発生してしまいます。
Deployment を用いると、変更前の ReplicaSet を継続させながら、更新を加えた新しいReplicaSet を動かすことができるため、ダウンタイム無しでメンテナンスをすることが可能になります。
実際のマニフェストの例としては以下になります。
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd-deployment
labels:
app: httpd
spec:
replicas: 3
selector:
matchLabels:
app: httpd
template:
metadata:
name: httpd-pod
labels:
app: httpd
spec:
containers:
- name: httpd
image: httpd:alpine3.22このマニフェストを適用すると、以下のようにDeployment、ReplicaSet、Pod(replicasで設定している通り3つ)が作成されている事がわかります。
$ kubectl get deployment --namespace default
NAME READY UP-TO-DATE AVAILABLE AGE
httpd-deployment 3/3 3 3 45s
$ kubectl get replicaset --namespace default
NAME DESIRED CURRENT READY AGE
httpd-deployment-5c9c5dbdf9 3 3 3 58s
$ kubectl get pod --namespace default
NAME READY STATUS RESTARTS AGE
httpd-deployment-5c9c5dbdf9-2rg78 1/1 Running 0 6m18s
httpd-deployment-5c9c5dbdf9-lkzpg 1/1 Running 0 6m18s
httpd-deployment-5c9c5dbdf9-lp8p9 1/1 Running 0 6m18sKubernetes で 自動復旧する Web サーバを立てる
早速 Kubernetes で Web サーバを構築し、自動復旧する様子を見てみましょう。
適当なディレクトリを作って、以下のマニフェストを配置します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd-deployment
labels:
app: httpd
spec:
replicas: 1
selector:
matchLabels:
app: httpd
template:
metadata:
name: httpd-pod
labels:
app: httpd
spec:
containers:
- name: httpd
image: httpd:alpine3.22
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: httpd-service
spec:
selector:
app: httpd
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
新しいリソースのServiceについて軽く説明します。
ServiceはPodで実行されているアプリケーションを公開するために使われるリソースです。このリソースは仮想IPを持った状態でPodの前面に配置され、クライアントがSeviceに設定されたIPアドレスにアクセスすると、各Podにアクセスを転送します。
そのため、イメージとしてはロードバランサーに近い概念です(もちろん厳密には違います)。
それでは、上記マニフェストを適用してみましょう。以下のコマンドを実行してください。
kubectl apply --filename http_server.yaml --namespace default次の表示がされれば、無事 Deployment と Service が起動しました。
$ kubectl apply --filename http_server.yaml --namespace default
deployment.apps/httpd-deployment created
service/httpd-service created念の為、Pod、Replicaset、Deployment、Serviceを確認してみましょう。
$ kubectl get pod --namespace default
NAME READY STATUS RESTARTS AGE
httpd-deployment-6bd99c794d-fh9z5 1/1 Running 0 2m11s
$ kubectl get replicaset --namespace default
NAME DESIRED CURRENT READY AGE
httpd-deployment-6bd99c794d 1 1 1 2m20s
$ kubectl get deployment --namespace default
NAME READY UP-TO-DATE AVAILABLE AGE
httpd-deployment 1/1 1 1 2m27s
$ kubectl get service --namespace default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-service NodePort 10.96.59.52 <none> 80:30080/TCP 2m34s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 47hちゃんと起動していることがわかりますね。それではブラウザでもapacheのデフォルトのコンテンツが見れるか確認してみましょう。まず、以下のコマンドで、localhostの8080番ポートをPodの80番ポートに転送する設定を行います。
kubectl port-forward svc/httpd-service 8080:80実行すると、以下のようにターミナルが止まるので、この間にブラウザで http://localhost:8080にアクセスしてみます。以下のデフォルトのコンテンツが返ってくればアクセス確認完了です。

復旧動作確認
最後に、作成したPodを削除してもすぐに起動する様子を観察しましょう。
まず、今まで開いていたターミナルとは別のターミナルを開き、以下のコマンドを実行してください。
kubectl get pod --watch --namespace defaultこのコマンドは指定したリソースの更新を監視するコマンドであり、実行結果は以下です。
$ kubectl get pod --watch --namespace default
NAME READY STATUS RESTARTS AGE
httpd-deployment-6bd99c794d-2dnhn 1/1 Running 0 33sこれを実行し続けた状態で、もとのターミナルに戻りPodを削除してみましょう。まず作成されたPod名を取得します。
$ kubectl get pod --namespace default
NAME READY STATUS RESTARTS AGE
httpd-deployment-6bd99c794d-2dnhn 1/1 Running 0 16m渡しの環境の場合、httpd-deployment-6bd99c794d-2dnhnがPod名なので、次のコマンドで削除してみます。
kubectl delete pod httpd-deployment-6bd99c794d-2dnhn --namespace defaultそうすると、監視をしていたターミナルの出力が変化し、次のような表示がされます。
$ k get pod --watch --namespace default
NAME READY STATUS RESTARTS AGE
httpd-deployment-6bd99c794d-2dnhn 1/1 Running 0 33s
httpd-deployment-6bd99c794d-2dnhn 1/1 Terminating 0 17m
httpd-deployment-6bd99c794d-z5pzz 0/1 Pending 0 0s
httpd-deployment-6bd99c794d-z5pzz 0/1 Pending 0 0s
httpd-deployment-6bd99c794d-z5pzz 0/1 ContainerCreating 0 0s
httpd-deployment-6bd99c794d-2dnhn 0/1 Completed 0 17m
httpd-deployment-6bd99c794d-z5pzz 1/1 Running 0 1s
httpd-deployment-6bd99c794d-2dnhn 0/1 Completed 0 17m
httpd-deployment-6bd99c794d-2dnhn 0/1 Completed 0 17m上記出力を見ると、httpd-deployment-6bd99c794d-2dnhnの削除が開始されたタイミングで別のPodであるhttpd-deployment-6bd99c794d-z5pzzが作成されたのが分かりますね。ここでは確認しませんが、再度ポートフォワーディング設定をしてあげると、ブラウザでコンテンツが表示されることを確認できます。
まとめ
今回は、前回解説したKubernetesから少し踏み込んで、実際にWebサーバを構築し自動復旧する動作の確認を行いました。今回の記事を通して、少しでもKubernetesの使い方に慣れていただければ幸いです。
また、もっと学んでみたい方は以下の本がおすすめです。この本は実際に手を動かしながらKubernetesを学んでいける内容となっているので、より詳しい内容を知りたいという方がいれば是非購入をご検討ください。
- マニフェストの書き方
- ReplicaSet、Deploymentの概要
- ReplicaSetはPodをまとめたもの
- DeploymentはReplicaSetをまとめたもの
- 自動復旧するWebサーバを構成し、実際にアクセスして動作を確認。
- わざとサーバを壊して、自動復旧するか確認














