Kubernetesにアプリケーションをデプロイする上で最も基本的なPod, ReplicaSet, Deploymentについて説明します。
Podはアプリケーションを動かすための最小の単位で、1つ以上のコンテナから構成されます。
ReplicaSetはPodを複製し、指定されたレプリカ数を維持するようにPodを管理します。
DeploymentはReplicaSetを生成、管理しローリングアップデートやロールバックを実現します。

通常、アプリケーションをデプロイする際はDeploymentを作成し、ReplicaSetやPodはそれぞれDeployment、ReplicaSetに管理させます。
目次
Podのデプロイ
まずはPod単体でデプロイすることから試しましょう。
hello-pks-pod.ymlを作成して、次の内容を記述してください。
apiVersion: v1
kind: Pod
metadata:
name: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.1
name: hello-pks
ports:
- containerPort: 8080
このmanifestファイルを使い、次のコマンドでPodをデプロイします。
kubectl apply -f hello-pks-pod.yml
出力結果
pod/hello-pks created
kubectl get podでPodを一覧表示します。
kubectl get pod
出力結果
NAME READY STATUS RESTARTS AGE
hello-pks 1/1 Running 0 25s
kubectl describe pod <Pod名>でPodの詳細情報を確認できます。
kubectl describe pod hello-pks
出力結果
Name: hello-pks
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: ip-10-0-8-6.ap-northeast-1.compute.internal/10.0.8.6
Start Time: Mon, 02 Sep 2019 01:56:51 +0900
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"hello-pks","namespace":"default"},"spec":{"containers":[{"image":"mak...
Status: Running
IP: 10.200.74.52
Containers:
hello-pks:
Container ID: docker://3e6c04ce22a7ec591a5f485bded17a83ecbd89eb8e0e100a7836765acf3498a9
Image: making/hello-pks:0.0.1
Image ID: docker-pullable://making/hello-pks@sha256:cdceb399a5b4a11216792d662dbc23ecbdef04d6e49b9af48fd730a0173384cc
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Mon, 02 Sep 2019 01:57:12 +0900
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-hdrng (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-hdrng:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-hdrng
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 38s default-scheduler Successfully assigned default/hello-pks to ip-10-0-8-6.ap-northeast-1.compute.internal
Normal Pulling 37s kubelet, ip-10-0-8-6.ap-northeast-1.compute.internal Pulling image "making/hello-pks:0.0.1"
Normal Pulled 18s kubelet, ip-10-0-8-6.ap-northeast-1.compute.internal Successfully pulled image "making/hello-pks:0.0.1"
Normal Created 17s kubelet, ip-10-0-8-6.ap-northeast-1.compute.internal Created container hello-pks
Normal Started 17s kubelet, ip-10-0-8-6.ap-northeast-1.compute.internal Started container hello-pks
PodにアクセスするためPodの8080番ポートをlocalhostの8080番ポートにフォワードします。
kubectl port-forward hello-pks 8080:8080
出力結果
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
既存のプロセスが8080番ポートを使用している場合はエラーになります。
kill $(lsof -i:8080 | awk 'NR>1 { print $2}')等でプロセスを終了してください。
ターミナルからhttp://localhost:8080/actuator/healthにアクセスして下さい。
curl http://localhost:8080/actuator/health
出力結果
{
"status" : "UP"
}
kubectl deleteで作成したリソースを削除してください。
kubectl delete -f hello-pks-pod.yml
出力結果
pod "hello-pks" deleted
Ctrl+Cでkubectl port-forwardを止めてください。
ReplicaSetのデプロイ
ReplicaSetはPodを複製し、複数インスタンスで起動したり、指定したレプリカ数を維持するように管理します。
hello-pks-rs.ymlを作成して、次の内容を記述してください。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: hello-pks
spec:
replicas: 1
selector:
matchLabels:
app: hello-pks
template:
metadata:
labels:
app: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.1
name: hello-pks
ports:
- containerPort: 8080
spec.template以下が複製するPodの情報です。レプリカ数(spec.replicas)が1なので、この場合は1Podのみ作成されます。spec.template.metadata.labelsに設定したラベルをspec.selector.matchLabelsに設定して結びつける必要があります。
kubectl applyでデプロイします。
kubectl apply -f hello-pks-rs.yml
出力結果
replicaset.apps/hello-pks created
kubectl get pod,rsでPodとReplicaSetを一覧表示します。
kubectl get pod,rs
出力結果
NAME READY STATUS RESTARTS AGE
pod/hello-pks-gvgh6 1/1 Running 0 9s
NAME DESIRED CURRENT READY AGE
replicaset.extensions/hello-pks 1 1 1 9s
1Pod作成されていることがわかります。Pod名は"ReplicaSet名-一意な文字列"になっています。
次にレプリカ数を2に変更します。
# ...
spec:
replicas: 2
# ...
再度、kubectl applyを実行してください。
kubectl apply -f hello-pks-rs.yml
出力結果
replicaset.apps/hello-pks configured
kubectl get pod,rsでPodとReplicaSet一覧を確認できます。
kubectl get pod,rs
出力結果
NAME READY STATUS RESTARTS AGE
po/hello-pks-dp9tb 1/1 Running 0 15s
po/hello-pks-x9gdm 1/1 Running 0 3s
NAME DESIRED CURRENT READY AGE
rs/hello-pks 2 2 2 23m
hello-pksから始まる名前を持つPodが2つ作成されていることがわかります。
次は-o wideをつけて実行してください。
$ kubectl get pod -o wide
出力結果
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello-pks-gvgh6 1/1 Running 0 93s 10.200.74.53 ip-10-0-8-6.ap-northeast-1.compute.internal <none> <none>
hello-pks-r7qx6 1/1 Running 0 52s 10.200.6.17 ip-10-0-9-4.ap-northeast-1.compute.internal <none> <none>
NODE列にPodが起動しているWorker Nodeが表示されています。Nodeが複数台ある場合は、NODE列に別々の値が表示されるかもしれません。
ここでPodを一つ削除して見ます。
kubectl delete pod hello-pks-gvgh6
出力結果
pod "hello-pks-gvgh6" deleted
この状態で、Pod一覧を表示してください。
kubectl get pod,rs
出力結果
NAME READY STATUS RESTARTS AGE
pod/hello-pks-gvgh6 0/1 Terminating 0 29s
pod/hello-pks-r7qx6 1/1 Running 0 17s
pod/hello-pks-tml22 1/1 Running 0 1s
NAME DESIRED CURRENT READY AGE
replicaset.extensions/hello-pks 2 2 2 29s
1つPodが削除されるとほぼ同時に新しいPodが起動しています。しばらくすると再びPodが2つ起動している状態になります。
kubectl get pod,rs
出力結果
NAME READY STATUS RESTARTS AGE
pod/hello-pks-r7qx6 1/1 Running 0 4m19s
pod/hello-pks-tml22 1/1 Running 0 21s
NAME DESIRED CURRENT READY AGE
replicaset.extensions/hello-pks 2 2 2 5m
Podのインスタンス数を管理しているのはReplicaSetであるため、kubectlコマンドでPodを意図的に削除してもReplicaSetにより、元々指定していたインスタンス数になるように復元されます。
kubectl describe rs <ReplicaSet名>でReplicaSetの詳細情報を確認できます。
kubectl describe rs hello-pks
出力結果
Name: hello-pks
Namespace: default
Selector: app=hello-pks
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"name":"hello-pks","namespace":"default"},"spec":{"replicas":2,"s...
Replicas: 2 current / 2 desired
Pods Status: 2 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=hello-pks
Containers:
hello-pks:
Image: making/hello-pks:0.0.1
Port: 8080/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 8m20s replicaset-controller Created pod: hello-pks-gvgh6
Normal SuccessfulCreate 7m39s replicaset-controller Created pod: hello-pks-r7qx6
Normal SuccessfulCreate 3m41s replicaset-controller Created pod: hello-pks-tml22
Events:にReplicaSetが作成したPodの情報が記載されています。
作成したReplicaSetは削除してください。
kubectl delete -f hello-pks-rs.yml
出力結果
replicaset.apps "hello-pks" deleted
Deploymentのデプロイ
DeploymentはReplicaSetを管理し、ローリングアップデートできるようにします。
hello-pks.ymlを作成して、次の内容を記述してください。(hello-pks-rs.ymlとの違いはkindがReplicaSetからDeploymentになっただけです。)
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-pks
spec:
replicas: 2
selector:
matchLabels:
app: hello-pks
template:
metadata:
labels:
app: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.1
name: hello-pks
ports:
- containerPort: 8080
kubectl applyでデプロイします。
kubectl apply -f hello-pks.yml
出力結果
deployment.apps/hello-pks created
kubectl get pod,rs,deployでPodとReplicaSetおよびDeployment一覧を確認できます。
kubectl get pod,rs,deploy
出力結果
NAME READY STATUS RESTARTS AGE
pod/hello-pks-8658768855-526jn 1/1 Running 0 10s
pod/hello-pks-8658768855-6h7sp 1/1 Running 0 10s
NAME DESIRED CURRENT READY AGE
replicaset.extensions/hello-pks-8658768855 2 2 2 11s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.extensions/hello-pks 2/2 2 2 11s
名前がDeployment名-一意な文字列であるReplicaSetができていることがわかります。そしてこのReplicaSetによって2つのPodができていることがわかります。
kubectl describe <Deployment名>でDeploymentの詳細情報を確認できます。
kubectl describe deploy hello-pks
出力結果
Name: hello-pks
Namespace: default
CreationTimestamp: Mon, 02 Sep 2019 02:09:59 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"hello-pks","namespace":"default"},"spec":{"replicas":2,"s...
Selector: app=hello-pks
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=hello-pks
Containers:
hello-pks:
Image: making/hello-pks:0.0.1
Port: 8080/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-pks-8658768855 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 35s deployment-controller Scaled up replica set hello-pks-8658768855 to 2
Serviceのデプロイ
ここまでPodへのアクセスはPort Forwardingを利用して行いましたが、ReplicaSetによって複製されたPodへロードバランスすることはできていません。
PodをKubernetesクラスタ内外に公開し、ロードバランシングの機能も提供するのがServiceです。
ServiceのTypeはいくつか用意されており、次の3つが代表的です。
ClusterIP: クラスタ内にのみ公開される。デフォルトのService Type。NodePort: Nodeのポートを経由して公開される。クラスタ外からアクセス可能。LoadBalancer: クラウドプロバイダ等が提供する外部ロードバランサを経由して公開される。ロードバランサは動的に作成される。
ClusterIPやNodePortは全てのクラスタで利用可能ですが、全てのk8s環境でLoadBalancerが対応されているわけではありません。
本資料が想定としている環境のLoadBalancer対応状況は次の表の通りです。
| 環境 | NSX-Tなし | NSX-Tあり |
|---|---|---|
| PKS on vSphere | ❌ | ✅ |
| PKS on GCP | ✅ | - |
| PKS on AWS | ✅ | - |
| PKS on Azure | ✅ | - |
ここではNodePortのServiceを作成する例を説明します。
Type=NodePort
LoadBalancerに対応していない環境ではNodePortのServiceを作成します。
hello-pks.ymlを次の内容を変更してください。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-pks
spec:
replicas: 2
selector:
matchLabels:
app: hello-pks
template:
metadata:
labels:
app: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.1
name: hello-pks
ports:
- containerPort: 8080
# ここから追記
---
kind: Service
apiVersion: v1
metadata:
name: hello-pks
spec:
type: NodePort
selector:
app: hello-pks
ports:
- protocol: TCP
port: 8080
spec.selectorにはPodに設定したラベルを、spec.ports[].portには公開対象のPodのポートを指定します。
kubectl applyでデプロイしてください。
kubectl apply -f hello-pks.yml
出力結果
deployment.apps/hello-pks unchanged
service/hello-pks created
kubectl get serviceでService一覧を確認できます。
kubectl get pod,rs,deploy,service
出力結果
NAME READY STATUS RESTARTS AGE
pod/hello-pks-8658768855-526jn 1/1 Running 0 4m27s
pod/hello-pks-8658768855-6h7sp 1/1 Running 0 4m27s
NAME DESIRED CURRENT READY AGE
replicaset.extensions/hello-pks-8658768855 2 2 2 4m28s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.extensions/hello-pks 2/2 2 2 4m28s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-pks NodePort 10.100.200.190 <none> 8080:32569/TCP 15s
service/kubernetes ClusterIP 10.100.200.1 <none> 443/TCP 230d
svc/hello-pks-serviceのPORT(S)列の8080:32569に注目してください。左がPodのIPで右がNode VMでlistenしているポートです。
この場合は、Node VMのIPの32569番ポートにアクセスするとhello-pksのPodにルーティングされます。ポートはデフォルトでは30000から32767で空いているポートがランダムで選択されます。
Node上のポートを固定したい場合は、次のように指定可能です。
spec:
type: NodePort
selector:
app: hello-pks
ports:
- protocol: TCP
port: 8080
nodePort: 32569
Node VMのIPはkubectl get node -o wideの結果のEXTERNAL-IP列から取得できます。
Node VMが複数ある場合は、どのNode VMにアクセスしても指定のPodへルーティングされます。
PKS on GCPやGKEでNode VMにインターネットからアクセスする場合は、Firewallの設定を変更してポートをポートを開放する必要があります。
gcloud compute instances list --format=jsonでNode VMに設定されているNetwork Tagを取得し、gcloud compute firewall-rules create k8s-allow-node-port --allow tcp:30000-32767 --target-tags <Node VMのNetwork Tag> --network <Node VMのNetwork Name>
Node VMの32569ポートにアクセスします。Nodeが複数ある場合はどれか一つのIPアドレスを選んでください。
curl http://<Worker NodeのIP>:32569/actuator/health
出力結果
{
"status" : "UP"
}
Type=LoadBalancer
LoadBalancerに対応している環境ではLoadBalancerのServiceを作成します。
hello-pks.ymlを次の内容を変更してください。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-pks
spec:
replicas: 2
selector:
matchLabels:
app: hello-pks
template:
metadata:
labels:
app: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.1
name: hello-pks
ports:
- containerPort: 8080
# ここから追記
---
kind: Service
apiVersion: v1
metadata:
name: hello-pks
spec:
type: LoadBalancer
selector:
app: hello-pks
ports:
- protocol: TCP
port: 8080
spec.selectorにはPodに設定したラベルを、spec.ports[].portには公開対象のPodのポートを指定します。
kubectl applyでデプロイしてください。
kubectl apply -f hello-pks.yml
出力結果
deployment.apps/hello-pks unchanged
service/hello-pks configured
kubectl get serviceでService一覧を確認できます。
kubectl get pod,rs,deploy,service
出力結果
NAME READY STATUS RESTARTS AGE
pod/hello-pks-8658768855-526jn 1/1 Running 0 8m43s
pod/hello-pks-8658768855-6h7sp 1/1 Running 0 8m43s
NAME DESIRED CURRENT READY AGE
replicaset.extensions/hello-pks-8658768855 2 2 2 8m44s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.extensions/hello-pks 2/2 2 2 8m44s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-pks LoadBalancer 10.100.200.190 aeb43003accdb11e99cb7066f53a5a1a-2093361350.ap-northeast-1.elb.amazonaws.com 8080:32569/TCP 4m31s
service/kubernetes ClusterIP 10.100.200.1 <none>
service/hello-pksのEXTERNAL-IP列にアクセス可能なLoad BalancerのIPアドレスまたはホスト名が表示されます。
このIPアドレスがアタッチされた外部のLoadBalancerを経由してServiceにアクセス可能になりました。<pending>になっている場合はLoad Balancer作成中またはエラーが起きてLoad Balancerの作成に失敗しています。kubectl describe service hello-pkdで状態を確認してください。
curlでhttp://<EXTERNAL-IP>:8080/actuator/healthにアクセスしてください。
curl http://aeb43003accdb11e99cb7066f53a5a1a-2093361350.ap-northeast-1.elb.amazonaws.com:8080/actuator/health
出力結果
{
"status" : "UP"
}
Node/Pod情報の表示
このままではロードバランスがされていることがわからないため、アクセスしているNodeとPodの情報をレスポンスボディに含めるようにします。making/hello-pksアプリは環境変数がNODEから始まるものとPODから始まるものがレスポンスボディに含まれるように作られています。
Podの環境変数にNodeとPodの情報を埋め込みます。NodeやPodの情報はDownload APIを使って取得できます。
hello-pks.ymlを次のように修正してください。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-pks
spec:
replicas: 2
selector:
matchLabels:
app: hello-pks
template:
metadata:
labels:
app: hello-pks
spec:
containers:
- image: making/hello-pks:0.0.1
name: hello-pks
ports:
- containerPort: 8080
# ここから追加
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: NODE_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
# ここまで
---
kind: Service
apiVersion: v1
metadata:
name: hello-pks
spec:
type: LoadBalancer
selector:
app: hello-pks
ports:
- protocol: TCP
port: 8080
kubectl applyで変更内容を適用します。
kubectl apply -f hello-pks.yml
出力結果
deployment.apps/hello-pks configured
service/hello-pks unchanged
kubectl get podでPodのSTATUSがRunningになっていることを確認したら、curlで、
- NodePortの場合
http://<Node IP>:<hello-pksのNode Port> - LoadBalancerの場合
http://<EXTERNAL IP>:8080
にアクセスしてください。
curl http://aeb43003accdb11e99cb7066f53a5a1a-2093361350.ap-northeast-1.elb.amazonaws.com:8080
出力結果
{
"node" : {
"NODE_IP" : "10.0.8.6",
"NODE_NAME" : "ip-10-0-8-6.ap-northeast-1.compute.internal"
},
"pod" : {
"POD_IP" : "10.200.74.57",
"POD_NAME" : "hello-pks-795466b574-lfr2z",
"POD_NAMESPACE" : "default"
},
"container" : { }
}
NodeとPodの情報が返ります。
何回かアクセスして、異なるPodの情報が表示されることを確認してください。
{
"node" : {
"NODE_IP" : "10.0.8.6",
"NODE_NAME" : "ip-10-0-8-6.ap-northeast-1.compute.internal"
},
"pod" : {
"POD_IP" : "10.200.74.56",
"POD_NAME" : "hello-pks-795466b574-75dcz",
"POD_NAMESPACE" : "default"
},
"container" : { }
}
WebブラウザでアクセスするとHTMLで表示されます。

"SHUTDOWN"ボタンを押すとアプリケーションが終了します。ボタンを押したあとはReplicaSetによってPodが再作成されますが、
それまでは1 Podだけでリクエストを捌きます。"SHUTDOWN"ボタンを押した後、別のPodの情報が表示されることを確認してください。
kubectl deleteでdeplymentとserviceを削除してください。
kubectl delete -f hello-pks.yml
出力結果
deployment.apps "hello-pks" deleted
service "hello-pks" deleted