Kubernetesのチュートリアルをたどる
kubernetesKubernetesとは
Kubernetes(発音はkoo-ber-nay’-tace。 ギリシャ語で操舵手。)はGoogleによって開発が始められた、アプリケーションコンテナにおける自動デプロイ、スケーリング、操作を 自動化するOSS。K8sと略される。
Minikube
K8sをローカルで試すために、MinikubeというVMの中で単一ノードのK8sクラスターを動かすツールを入れる。
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.6.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
$ minikube start
Starting local Kubernetes cluster...
...
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"2", GitVersion:"v1.2.4", GitCommit:"3eed1e3be6848b877ff80a93da3785d9034d0a4f", GitTreeState:"clean"}
Server Version: version.Info{Major:"1", Minor:"3", GitVersion:"v1.3.0", GitCommit:"283137936a498aed572ee22af6774b6fb6e9fd94", GitTreeState:"clean"}
Pods
K8sではコンテナのグループをpodと呼ぶ。pod中のコンテナは共にデプロイされ、起動し、停止する。 また、グループとして複製される。
Podの定義は次のようにyamlで書かれる。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Podの定義に望ましい状態を記述すると、Kubernatesはそれを見て現在の状態が一致しているかどうか確認する。 例えば、Podが作られたときに、コンテナがその中で動いている状態が望ましい状態だとすると、 コンテナが動かなくなったときに、Kubernatesは新しいものを再作成することで望ましい状態にする。
podの作成とリストの取得のコマンドは次の通り。
$ kubectl create -f nginx.yaml
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 4s
kubectl exec
でpsコマンドを実行し、
podが動いていることを確認しようとしたがコマンドがなかった。
$ kubectl exec -it nginx ps
rpc error: code = 2 desc = "oci runtime error: exec failed: exec: \"ps\": executable file not found in $PATH"error: error executing remote command: error executing command in container: Error executing in Docker Container: 126
そこでリクエストを投げるためにkubectl run
で単一コンテナのDeploymentを作成する。
Deploymentについては後で説明がある。
--restart=Never
でpodが存在しなくなったときに再起動しないようにし、--env
で環境変数としてnginxのpodのIPを渡している。
$ kubectl run busybox --image=busybox --restart=Never --tty -i --env "POD_IP=$(kubectl get pod nginx -o go-template={{.status.podIP}})"
busybox$ wget -qO- http://$POD_IP
busybox$ exit # Exit the busybox container
$ kubectl get deployments
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 54m
--restart=Never
なしで実行するとこうなる。
$ kubectl run busybox --image=busybox --tty -i --env "POD_IP=$(kubectl get pod nginx -o go-template={{.status.podIP}})"
busybox$ exit
Session ended, resume using 'kubectl attach busybox-985443498-9elny -c busybox -i -t' command when the pod is running
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
busybox 1 1 1 1 3m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
busybox-985443498-9elny 1/1 Running 1 3m
nginx 1/1 Running 0 59m
$ kubectl delete pods busybox-985443498-9elny
pod "busybox-985443498-9elny" deleted
$ kubectl get pods # Podsだけ削除しても新しいものが立ち上がってくる
NAME READY STATUS RESTARTS AGE
busybox-985443498-4iyvx 0/1 ContainerCreating 0 1s
busybox-985443498-9elny 1/1 Terminating 1 13m
nginx 1/1 Running 0 1h
$ kubectl delete deployment busybox
$ kubectl get pods # Deploymentを削除するとPodsも消える
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 1h
Volumes
コンテナのファイルシステムはコンテナが生存しているときに限り有効なので、 永続化したいデータはコンテナの外に保存する必要がある。
次の例のようにvolumes
でvolumeを定義し、volumeMounts
でどこにマウントするか指定することができる。
volumes
には、そのPodがノードで実行されている間存在するディレクトリを作成して使うEmptyDir
か、
ノードのファイルシステムに既に存在するディレクトリを使うHostPath
を指定する。
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
volumeMounts:
- name: redis-persistent-storage
mountPath: /data/redis
volumes:
- name: redis-persistent-storage
emptyDir: {}
Labels
metadataとしてkey-valueのラベルを付けることができる。
metadata:
name: nginx
labels:
app: nginx
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2m
Deployments
実行しているPodの維持と更新を管理するのが上でも出てきたDeployment。 Deploymentの定義にはPodを作るためのテンプレートと維持するPod数を記述する。 pod名はDeployment名から生成されるのでtemplateには含めない。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
$ kubectl create -f deployment.yaml
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 2 2 2 2 3m
$ kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-deployment-1159050644-ar3i7 1/1 Running 0 3m
nginx-deployment-1159050644-kdjly 1/1 Running 0 3m
kubectl apply
でDeploymentの変更を実行中のPodに適用する。
次の例ではnginxのバージョンを上げている。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.8
ports:
- containerPort: 80
$ kubectl apply -f deployment-update.yaml
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-1159050644-kdjly 1/1 Running 0 30m
nginx-deployment-1771418926-pi3vy 0/1 ContainerCreating 0 7s
nginx-deployment-1771418926-ygoxl 0/1 ContainerCreating 0 7s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-1771418926-pi3vy 0/1 ContainerCreating 0 12s
nginx-deployment-1771418926-ygoxl 1/1 Running 0 12s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-1771418926-pi3vy 1/1 Running 0 15s
nginx-deployment-1771418926-ygoxl 1/1 Running 0 15s
Services
アプリケーションのレイヤー間(例えばフロントエンドとバックエンド)の接続で使われるのがService。
次のServiceは、8080番ポートで待ち、app: nginx
のラベルが付いているPodの80番ポートに向けるロードバランサーとして働く。
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- port: 8000
targetPort: 80
protocol: TCP
selector:
app: nginx
$ kubectl create -f service.yaml
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.0.0.1 <none> 443/TCP 19h
nginx-service 10.0.0.90 <none> 8000/TCP 36s
$ export SERVICE_IP=$(kubectl get service nginx-service -o go-template='{{.spec.clusterIP}}')
$ export SERVICE_PORT=$(kubectl get service nginx-service -o go-template='{{(index .spec.ports 0).port}}')
$ echo "$SERVICE_IP:$SERVICE_PORT"
10.0.0.90:8000
$ kubectl run busybox --image=busybox --restart=Never --tty -i --env "SERVICE_IP=$SERVICE_IP,SERVICE_PORT=$SERVICE_PORT"
busybox$ wget -qO- http://$SERVICE_IP:$SERVICE_PORT
Health Checking
livenessProbe
にヘルスチェックの設定を含めることができる。
次の例では、初期化のために30秒待った後、/_status/healthz
へのHTTP GETリクエストに対して
200~399以外のステータスコードが返るか、1秒以上かかった場合、コンテナを再起動する。
apiVersion: v1
kind: Pod
metadata:
name: pod-with-healthcheck
spec:
containers:
- name: nginx
image: nginx
livenessProbe:
httpGet:
path: /_status/healthz
port: 80
initialDelaySeconds: 30
timeoutSeconds: 1
ports:
- containerPort: 80