お題
表題の関係について記載。
環境
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="17.10 (Artful Aardvark)"
〜省略〜
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.7", GitCommit:"0c38c362511b20a098d7cd855f1314dad92c2780", GitTreeState:"clean", BuildDate:"2018-08-20T10:09:03Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"9+", GitVersion:"v1.9.7-gke.6", GitCommit:"9b635efce81582e1da13b35a7aa539c0ccb32987", GitTreeState:"clean", BuildDate:"2018-08-16T21:33:47Z", GoVersion:"go1.9.3b4", Compiler:"gc", Platform:"linux/amd64"}
定義とYAMLサンプルのリンク
Pod
ポッドテンプレートは、レプリケーションコントローラ、ジョブ、およびデーモンセットなどの他のオブジェクトに含まれるポッド仕様
https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/#pod-templates
ReplicaSet
ReplicaSetは、指定された数のポッドレプリカがいつでも実行されていることを保証する仕様
https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#example
Deployments
Deployment Controllerは、PodおよびReplicaSetsの宣言的な更新を提供する仕様
https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment
実践
Pod
ミニマムに以下のようなYAMLを作成
★Podを作るだけなら「labels」は不要だけど、後に expose する時にラベルが必要だと怒られたので付加。
apiVersion: v1
kind: Pod
metadata:
name: kind-pod
labels:
app: go
spec:
containers:
- name: go-webapi-for-gke-study
image: sky0621dhub/go-webapi-for-gke-study:v0.1
反映
$ kubectl apply -f kind-pod.yaml
pod "kind-pod" created
$
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-pod 1/1 Running 0 53s 10.60.12.10 gke-my-cluster-1-min-default-pool-ea807978-8d2t
サービス公開
$ kubectl expose pod kind-pod --type "LoadBalancer" --port 80
service "kind-pod" exposed
$
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kind-pod LoadBalancer 10.63.252.240 xx.xxx.xx.xxx 80:30598/TCP 5m
EXTERNAL-IP記載のアドレスにWebブラウザでアクセス
「kind: Pod」だけでサービス公開までは楽々いける。
じゃあ、これを複数の「Node」に適用すれば、他の「kind」を使うことはないのかと言うと、当然、そうではない。
「kind: Pod」の場合、その Pod で何かしらの障害が起きて停止ないし機能しない状態になった際に、単純にその Pod が死ぬ。
例えば、以下のように。(しばらく待っても、立ち上がってきたりはしない。)
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-pod 1/1 Running 0 26s 10.60.14.4 gke-my-cluster-1-min-default-pool-ea807978-8d2t
$
$ kubectl delete pods kind-pod
pod "kind-pod" deleted
$
$ kubectl get pods -o wide
No resources found.
3つ作っていても、2つになる。そして何もしなければ以後、元の3つに戻ることはない。
もちろん、Pod が死んでいるのに気づけば手動で再度、Pod を適用すればいいけど、そんなことしてられない。
では、どうするかと言うと、「ReplicaSet」を使う。
ReplicaSet
PodのYAMLを内包したような作りでYAMLを作成
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: kind-rs
labels:
app: go
spec:
replicas: 3
selector:
matchLabels:
app: rsgo
template:
metadata:
labels:
app: rsgo
spec:
containers:
- name: go-webapi-for-gke-study
image: sky0621dhub/go-webapi-for-gke-study:v0.1
ports:
- containerPort: 80
「spec/template」配下に先ほどの Pod のYAMLに書いた内容(つまり Pod の仕様)が入る。
また、常時3つの Pod が起動していることを保証するために「replicas: 3」を指定。
あと重要なのが2箇所にある「app: rsgo」の記述。
「spec/template」にラベル付けするための「spec/template/metadata/labels/app」と、
そうしてラベル付けされた Pod を管理するための指定である「spec/selector/matchLabels/app」。
https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/#pod-selector
そう、
何気にバージョンは(Podの時と違って)「apps/v1」を指定。
反映
$ kubectl apply -f kind-replicaset.yaml
replicaset.apps "kind-rs" created
$
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-rs-57nxb 1/1 Running 0 44s 10.60.16.8 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-rs-rt2r2 1/1 Running 0 44s 10.60.15.5 gke-my-cluster-1-min-default-pool-ea807978-ss7p
kind-rs-s5knz 1/1 Running 0 44s 10.60.14.5 gke-my-cluster-1-min-default-pool-ea807978-8d2t
$
$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
kind-rs 3 3 3 58s go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.1 app=rsgo
3つ Pod が作られてる。そして均等に Node に振り分けられている。
さて、おもむろに Pod を1つ削除してみる。
$ kubectl delete pods kind-rs-57nxb
pod "kind-rs-57nxb" deleted
でも、
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-rs-rt2r2 1/1 Running 0 4m 10.60.15.5 gke-my-cluster-1-min-default-pool-ea807978-ss7p
kind-rs-s5knz 1/1 Running 0 4m 10.60.14.5 gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-rs-zsbfq 1/1 Running 0 6s 10.60.16.9 gke-my-cluster-1-min-default-pool-ea807978-hpqc
すぐに別の Pod(この場合は「kind-rs-zsbfq」)が立ち上がる。
これが、「kind: ReplicaSet」で Pod を作ったときの挙動。指定したレプリカ数を維持してくれる。
サービス公開
$ kubectl expose rs kind-rs --type "LoadBalancer" --port 80
service "kind-rs" exposed
$
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kind-rs LoadBalancer 10.63.248.75 xx.xxx.xx.xxx 80:30290/TCP 1m
EXTERNAL-IP記載のアドレスにWebブラウザでアクセス
Pod は3つあるのだけど、どれにアクセスされたのか?
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kind-rs-rt2r2 1/1 Running 0 17m
kind-rs-s5knz 1/1 Running 0 17m
kind-rs-zsbfq 1/1 Running 0 13m
まず1つ目。 ↓違った。(Webサーバ起動時のログしか出てないので)
$ kubectl logs kind-rs-rt2r2
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.6
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:80
次は2つ目。 ↓これだった。
$ kubectl logs kind-rs-s5knz
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.6
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:80
{"level":"info","ts":1537972593.5397136,"caller":"go-webapi-for-gke-study/main.go:34","msg":"INFO LEVEL with severity","severity":"INFO"}
{"level":"warn","ts":1537972593.539827,"caller":"go-webapi-for-gke-study/main.go:35","msg":"WARN LEVEL with severity","severity":"WARN"}
{"level":"error","ts":1537972593.539841,"caller":"go-webapi-for-gke-study/main.go:36","msg":"ERROR LEVEL with severity","severity":"ERROR","stacktrace":"main.main.func1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/main.go:36\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo.(*Echo).Add.func1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/echo.go:480\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware.RequestIDWithConfig.func1.1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware/request_id.go:57\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware.RecoverWithConfig.func1.1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware/recover.go:78\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo.(*Echo).ServeHTTP\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/echo.go:583\nnet/http.serverHandler.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2619\nnet/http.(*conn).serve\n\t/usr/local/go/src/net/http/server.go:1801"}
{"level":"info","ts":1537972670.3378396,"caller":"go-webapi-for-gke-study/main.go:34","msg":"INFO LEVEL with severity","severity":"INFO"}
{"level":"warn","ts":1537972670.3378987,"caller":"go-webapi-for-gke-study/main.go:35","msg":"WARN LEVEL with severity","severity":"WARN"}
{"level":"error","ts":1537972670.3379054,"caller":"go-webapi-for-gke-study/main.go:36","msg":"ERROR LEVEL with severity","severity":"ERROR","stacktrace":"main.main.func1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/main.go:36\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo.(*Echo).Add.func1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/echo.go:480\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware.RequestIDWithConfig.func1.1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware/request_id.go:57\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware.RecoverWithConfig.func1.1\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/middleware/recover.go:78\ngithub.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo.(*Echo).ServeHTTP\n\t/go/src/github.com/sky0621/go-webapi-for-gke-study/vendor/github.com/labstack/echo/echo.go:583\nnet/http.serverHandler.ServeHTTP\n\t/usr/local/go/src/net/http/server.go:2619\nnet/http.(*conn).serve\n\t/usr/local/go/src/net/http/server.go:1801"}
最後に3つ目。 ↓当然、違う。
$ kubectl logs kind-rs-zsbfq
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.6
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:80
一応、何度かWebアクセスしてみると、他の Pod にもアクセスログが出力されていた。分散されている。
ただ、アクセスには、けっこうな偏りがあったので、ラウンドロビンというわけではなさそう。
決めた分だけ Pod の起動を維持してくれるし、これで事足りる。
じゃあ、ReplicaSetで十分だから「Deployments」は使うことないのかというと、これは新しいバージョンのアプリをデプロイする時に役に立つ。
”ローリングアップデート”というのができる。
もともと3つのPodで動いていた現行Verのアプリに対し、同じく3つのPodで動く新Verのアプリで入れ替えようとした時に、
新Verアプリ用のPodを増やしつつ、現行Verアプリ用のPodを減らしていき、最終的に入れ替える。
そして、これがk8sで推奨されているパターンらしい。
Deployment
ReplicaSetのYAMLとまったく同じ形でYAMLを作成
apiVersion: apps/v1
kind: Deployment
metadata:
name: kind-deployment
labels:
app: go
spec:
replicas: 3
selector:
matchLabels:
app: rsgo
template:
metadata:
labels:
app: rsgo
spec:
containers:
- name: go-webapi-for-gke-study
image: sky0621dhub/go-webapi-for-gke-study:v0.1
ports:
- containerPort: 80
反映
$ kubectl apply -f kind-deployment.yaml
deployment.apps "kind-deployment" created
$
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-deployment-6658cdbcd-db7lg 1/1 Running 0 28s 10.60.16.10 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-6658cdbcd-lkdfw 1/1 Running 0 28s 10.60.14.6 gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-deployment-6658cdbcd-z4prb 1/1 Running 0 28s 10.60.15.6 gke-my-cluster-1-min-default-pool-ea807978-ss7p
$
$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
kind-deployment-6658cdbcd 3 3 3 46s go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.1 app=rsgo,pod-template-hash=221478678
$
$ kubectl get deployments -o wide
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
kind-deployment 3 3 3 3 8m go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.1 app=rsgo
Podを1つ削除
$ kubectl delete pods kind-deployment-6658cdbcd-db7lg
pod "kind-deployment-6658cdbcd-db7lg" deleted
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-deployment-6658cdbcd-db7lg 0/1 Terminating 0 2m 10.60.16.10 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-6658cdbcd-lkdfw 1/1 Running 0 2m 10.60.14.6 gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-deployment-6658cdbcd-mjzvb 1/1 Running 0 3s 10.60.16.11 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-6658cdbcd-z4prb 1/1 Running 0 2m 10.60.15.6 gke-my-cluster-1-min-default-pool-ea807978-ss7p
素早く1つ新しいPod(kind-deployment-6658cdbcd-mjzvb)を立ち上げ、
削除対象のPod(kind-deployment-6658cdbcd-db7lg)は削除中(Terminating)のステータスになった。
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-deployment-6658cdbcd-lkdfw 1/1 Running 0 4m 10.60.14.6 gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-deployment-6658cdbcd-mjzvb 1/1 Running 0 2m 10.60.16.11 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-6658cdbcd-z4prb 1/1 Running 0 4m 10.60.15.6 gke-my-cluster-1-min-default-pool-ea807978-ss7p
入れ替え完了。
Ver違いのイメージをPod数4でデプロイするようYAMLを書き換え
apiVersion: apps/v1
kind: Deployment
metadata:
name: kind-deployment
labels:
app: go
spec:
replicas: 4
selector:
matchLabels:
app: rsgo
template:
metadata:
labels:
app: rsgo
spec:
containers:
- name: go-webapi-for-gke-study
image: sky0621dhub/go-webapi-for-gke-study:v0.2
ports:
- containerPort: 80
反映
◆反映前のPodの状態◆
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-deployment-6658cdbcd-lkdfw 1/1 Running 0 9m 10.60.14.6 gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-deployment-6658cdbcd-mjzvb 1/1 Running 0 7m 10.60.16.11 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-6658cdbcd-z4prb 1/1 Running 0 9m 10.60.15.6 gke-my-cluster-1-min-default-pool-ea807978-ss7p
$
$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
kind-deployment-6658cdbcd 3 3 3 9m go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.1 app=rsgo,pod-template-hash=221478678
$
$ kubectl get deployments -o wide
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
kind-deployment 3 3 3 3 9m go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.1 app=rsgo
◆では、反映◆
$ kubectl apply -f kind-deployment.yaml
deployment.apps "kind-deployment" configured
◆入れ替えが始まる◆
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-deployment-6658cdbcd-dd5lq 0/1 Terminating 0 4s <none> gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-deployment-6658cdbcd-lkdfw 1/1 Running 0 10m 10.60.14.6 gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-deployment-6658cdbcd-mjzvb 1/1 Running 0 8m 10.60.16.11 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-6658cdbcd-z4prb 1/1 Running 0 10m 10.60.15.6 gke-my-cluster-1-min-default-pool-ea807978-ss7p
kind-deployment-8646897b59-fzlng 0/1 ContainerCreating 0 4s <none> gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-8646897b59-q9qd4 0/1 ContainerCreating 0 4s <none> gke-my-cluster-1-min-default-pool-ea807978-ss7p
$
$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
kind-deployment-6658cdbcd 1 1 1 10m go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.1 app=rsgo,pod-template-hash=221478678
kind-deployment-8646897b59 4 4 2 9s go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.2 app=rsgo,pod-template-hash=4202453615
$
$ kubectl get deployments -o wide
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
kind-deployment 4 4 4 4 10m go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.2 app=rsgo
◆入れ替えが終わる◆
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kind-deployment-8646897b59-8whlg 1/1 Running 0 26s 10.60.15.8 gke-my-cluster-1-min-default-pool-ea807978-ss7p
kind-deployment-8646897b59-dt6hz 1/1 Running 0 28s 10.60.14.7 gke-my-cluster-1-min-default-pool-ea807978-8d2t
kind-deployment-8646897b59-fzlng 1/1 Running 0 34s 10.60.16.12 gke-my-cluster-1-min-default-pool-ea807978-hpqc
kind-deployment-8646897b59-q9qd4 1/1 Running 0 34s 10.60.15.7 gke-my-cluster-1-min-default-pool-ea807978-ss7p
$
$ kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
kind-deployment-6658cdbcd 0 0 0 10m go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.1 app=rsgo,pod-template-hash=221478678
kind-deployment-8646897b59 4 4 4 47s go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.2 app=rsgo,pod-template-hash=4202453615
$
$ kubectl get deployments -o wide
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
kind-deployment 4 4 4 4 17m go-webapi-for-gke-study sky0621dhub/go-webapi-for-gke-study:v0.2 app=rsgo
入れ替えが終わった後、既存のReplicaSetの定義自体は消えないみたい。ただし、Pod数は0