deployment
我們已經知道k8s是通過各種controller來管理pod的生命周期。為了滿足不同業務場景,k8s開發了Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等多種 Controller。我們首先學習最常用的 Deployment。
運行一個deployment
[root@ken ~]# kubectl run httpd-ken1--generator=run-pod/v1 --image=httpd --replicas=2
下面詳細分析 Kubernetes 都做了些什么工作。
[root@ken ~]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE httpd-ken 2/2 2 2 35m
kubectl get deplouyment命令可以查看 httpd-ken 的狀態,輸出顯示兩個副本正常運行。
接下來我們用 kubectl describe deployment 了解更詳細的信息。
[root@ken ~]# kubectl describe deployment httpd-ken Name: httpd-ken Namespace: default CreationTimestamp: Tue, 29 Jan 2019 15:27:40 +0800 Labels: run=httpd-ken Annotations: deployment.kubernetes.io/revision: 1 Selector: run=httpd-ken 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: run=httpd-ken Containers: httpd-ken: Image: httpd Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: httpd-ken-5c949b96f (2/2 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 18m deployment-controller Scaled up replica set httpd-ken-5c949b96f to 2
大部分內容都是自解釋的,我們重點看最下面部分。這里告訴我們創建了一個 ReplicaSet httpd-ken-5c949b96,Events 是 Deployment 的日志,記錄了 ReplicaSet 的啟動過程。
通過上面的分析,也驗證了 Deployment 通過 ReplicaSet 來管理 Pod 的事實。接着我們將注意力切換到 httpd-ken-5c949b96,執行 kubectl describe replicaset:
[root@ken ~]# kubectl get replicaset NAME DESIRED CURRENT READY AGE httpd-ken-5c949b96f 2 2 2 20m
兩個副本已經就緒,用 kubectl describe replicaset 查看詳細信息:
[root@ken ~]# kubectl describe replicaset Name: httpd-ken-5c949b96f Namespace: default Selector: pod-template-hash=5c949b96f,run=httpd-ken Labels: pod-template-hash=5c949b96f run=httpd-ken Annotations: deployment.kubernetes.io/desired-replicas: 2 deployment.kubernetes.io/max-replicas: 3 deployment.kubernetes.io/revision: 1 Controlled By: Deployment/httpd-ken Replicas: 2 current / 2 desired Pods Status: 2 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: Labels: pod-template-hash=5c949b96f run=httpd-ken Containers: httpd-ken: Image: httpd Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 20m replicaset-controller Created pod: httpd-ken-5c949b96f-twdsd Normal SuccessfulCreate 20m replicaset-controller Created pod: httpd-ken-5c949b96f-9cd52
Controlled By 指明此 ReplicaSet 是由 Deployment httpd-ken 創建。Events 記錄了兩個副本 Pod 的創建。接着我們來看 Pod,執行 kubectl get pod:
[root@ken ~]# kubectl get pod NAME READY STATUS RESTARTS AGE httpd-ken-5c949b96f-9cd52 1/1 Running 0 22m httpd-ken-5c949b96f-twdsd 1/1 Running 0 22m
兩個副本 Pod 都處於 Running 狀態,用 kubectl describe pod 查看更詳細的信息:
root@ken ~]# kubectl describe pod Name: httpd-ken-5c949b96f-9cd52 Namespace: default Priority: 0 PriorityClassName: <none> Node: host1/172.20.10.7 Start Time: Tue, 29 Jan 2019 15:46:45 +0800 Labels: pod-template-hash=5c949b96f run=httpd-ken Annotations: <none> Status: Running IP: 10.244.1.3 Controlled By: ReplicaSet/httpd-ken-5c949b96f Containers: httpd-ken: Container ID: docker://e59bda9941a16f20027c89a0d8fa8e17797b517f6f5461e905c0d29b57369dde Image: httpd Image ID: docker-pullable://httpd@sha256:44daa8e932a32ab6e50636d769ca9a60ad412124653707e5ed59c0209c72f9b3 Port: <none> Host Port: <none> State: Running Started: Tue, 29 Jan 2019 15:47:10 +0800 Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-vb7lm (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-vb7lm: Type: Secret (a volume populated by a Secret) SecretName: default-token-vb7lm 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 23m default-scheduler Successfully assigned default/httpd-ken-5c949b96f-9cd52 to host1 Normal Pulling 23m kubelet, host1 pulling image "httpd" Normal Pulled 22m kubelet, host1 Successfully pulled image "httpd" Normal Created 22m kubelet, host1 Created container Normal Started 22m kubelet, host1 Started container
Controlled By 指明此 Pod 是由 ReplicaSet httpd-ken-5c949b96f創建。Events 記錄了 Pod 的啟動過程。如果操作失敗(比如 image 不存在),也能在這里查看到原因。
總結一下這個過程:
用戶通過 kubectl 創建 Deployment。
Deployment 創建 ReplicaSet。
ReplicaSet 創建 Pod
也可以看出,對象的命名方式是:子對象的名字 = 父對象名字 + 隨機字符串或數字。
命令vs配置文件
k8s支持兩種創建資源的方式:
1.用 kubectl 命令直接創建,比如:
kubectl run nginx-deployment –image=nginx:1.7.9 –replicas=2
在命令行中通過參數指定資源的屬性。
2. 通過配置文件和 kubectl apply 創建,要完成前面同樣的工作,可執行命令:
kubectl apply -f nginx.yml
nginx.yml 的內容為:
資源的屬性寫在配置文件中,文件格式為 YAML。
下面對這兩種方式進行比較。
基於命令的方式:
簡單直觀快捷,上手快。
適合臨時測試或實驗。
基於配置文件的方式:
配置文件描述了 What,即應用最終要達到的狀態。
配置文件提供了創建資源的模板,能夠重復部署。
可以像管理代碼一樣管理部署。
適合正式的、跨環境的、規模化部署。
這種方式要求熟悉配置文件的語法,有一定難度。
后面我們都將采用配置文件的方式,大家需要盡快熟悉和掌握。
kubectl apply 不但能夠創建 Kubernetes 資源,也能對資源進行更新,非常方便。不過 Kubernets 還提供了幾個類似的命令,例如 kubectl create、kubectl replace、kubectl edit 和 kubectl patch。
為避免造成不必要的困擾,我們會盡量只使用 kubectl apply,
此命令已經能夠應對超過 90% 的場景,事半功倍。
deployment yaml
既然要用 YAML 配置文件部署應用,現在就很有必要了解一下 Deployment 的配置格式,其他 Controller(比如 DaemonSet)非常類似。
① apiVersion 是當前配置格式的版本。
先執行kubectl api-resources找到所有的資源
在執行命令 kubectl explain deploy即可獲取到版本和類型信息
② kind 是要創建的資源類型,這里是 Deployment。
③ metadata 是該資源的元數據,name 是必需的元數據項。
④ spec 部分是該 Deployment 的規格說明。
⑤ replicas 指明副本數量,默認為 1。
⑥ template 定義 Pod 的模板,這是配置文件的重要部分。
⑦ metadata 定義 Pod 的元數據,至少要定義一個 label。label 的 key 和 value 可以任意指定。
⑧ spec 描述 Pod 的規格,此部分定義 Pod 中每一個容器的屬性,name 和 image 是必需的。
注意:最后name前面加個橫線是因為container后面是一個列表
此 nginx.yml 是一個最簡單的 Deployment 配置文件,后面我們學習 Kubernetes 各項功能時會逐步豐富這個文件。
執行 kubectl apply -f nginx.yml:
[root@ken ~]# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment created
查看nginx-deployment各種資源
[root@ken ~]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE httpd-ken 2/2 2 2 73m nginx-deployment 2/2 2 2 107s [root@ken ~]# kubectl get replicaset NAME DESIRED CURRENT READY AGE httpd-ken-5c949b96f 2 2 2 54m nginx-deployment-65998d8886 2 2 2 111s [root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpd-ken-5c949b96f-9cd52 1/1 Running 0 54m 10.244.1.3 host1 <none> <none> httpd-ken-5c949b96f-twdsd 1/1 Running 0 54m 10.244.2.3 host2 <none> <none> nginx-deployment-65998d8886-9qrrv 1/1 Running 0 2m4s 10.244.2.4 host2 <none> <none> nginx-deployment-65998d8886-vnbgt 1/1 Running 0 2m4s 10.244.1.4 host1 <none> <none>
Deployment、ReplicaSet、Pod 都已經就緒。如果要刪除這些資源,執行 kubectl delete deployment nginx-deployment 或者 kubectl delete -f nginx.yml (編寫的nginx.yml文件不會被刪除)。
[root@ken ~]# kubectl delete -f nginx.yml deployment.extensions "nginx-deployment" deleted
Scale Up/Down
伸縮(Scale Up/Down)是指在線增加或減少 Pod 的副本數。
Deployment nginx-deployment 初始是兩個副本。
[root@ken ~]# kubectl apply -f nginx.yml [root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-5b5rc 1/1 Running 0 84s 10.244.1.5 host1 <none> <none> nginx-deployment-65998d8886-tnpcx 1/1 Running 0 84s 10.244.2.5 host2 <none> <none>
k8s-node1 和 k8s-node2 上各跑了一個副本。現在修改 nginx.yml,將副本改成 5 個。
再次執行kubectl apply
[root@ken ~]# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment configured
查看pod
[root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-4hfgp 1/1 Running 0 3m 10.244.1.7 host1 <none> <none> nginx-deployment-65998d8886-5b5rc 1/1 Running 0 5m48s 10.244.1.5 host1 <none> <none> nginx-deployment-65998d8886-btrsq 1/1 Running 0 3m 10.244.2.6 host2 <none> <none> nginx-deployment-65998d8886-tnpcx 1/1 Running 0 5m48s 10.244.2.5 host2 <none> <none> nginx-deployment-65998d8886-x4pbd 1/1 Running 0 3m 10.244.1.6 host1 <none> <none>
三個新副本被創建並調度到 k8s-node1 和 k8s-node2 上。
接下來修改配置文件,將副本數減少為 3 個,重新執行 kubectl apply:
[root@ken ~]# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment configured [root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-5b5rc 1/1 Running 0 7m6s 10.244.1.5 host1 <none> <none> nginx-deployment-65998d8886-btrsq 1/1 Running 0 4m18s 10.244.2.6 host2 <none> <none> nginx-deployment-65998d8886-tnpcx 1/1 Running 0 7m6s 10.244.2.5 host2 <none> <none>
可以看到兩個副本被刪除,最終保留了 3 個副本。
模擬故障
上面我們有 3 個 nginx 副本分別運行在 k8s-node1 和 k8s-node2 上。現在模擬 k8s-node2 故障,關閉該節點(poweroff)。
首先查看節點
[root@ken ~]# kubectl get node NAME STATUS ROLES AGE VERSION host1 Ready <none> 5h25m v1.13.2 host2 NotReady <none> 5h43m v1.13.2 ken Ready master 6h18m v1.13.2
發現host2狀態為NotReady
等待一段時間,Kubernetes 會檢查到 k8s-node2 不可用,將 k8s-node2 上的 Pod 標記為 Terminating狀態,並在 k8s-node1 上新創建兩個 Pod,維持總副本數為 3。
[root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-5b5rc 1/1 Running 0 16m 10.244.1.5 host1 <none> <none> nginx-deployment-65998d8886-8647d 1/1 Running 0 79s 10.244.1.8 host1 <none> <none> nginx-deployment-65998d8886-btrsq 1/1 Terminating 0 13m 10.244.2.6 host2 <none> <none> nginx-deployment-65998d8886-qp6jj 1/1 Running 0 79s 10.244.1.9 host1 <none> <none> nginx-deployment-65998d8886-tnpcx 1/1 Terminating 0 16m 10.244.2.5 host2 <none> <none>
當 k8s-node2 恢復后, Terminating的 Pod 會被刪除,不過已經運行的 Pod 不會重新調度回 k8s-node2。
[root@ken ~]# kubectl get node NAME STATUS ROLES AGE VERSION host1 Ready <none> 5h33m v1.13.2 host2 Ready <none> 5h51m v1.13.2 ken Ready master 6h26m v1.13.2 [root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-65998d8886-5b5rc 1/1 Running 0 19m 10.244.1.5 host1 <none> <none> nginx-deployment-65998d8886-8647d 1/1 Running 0 4m33s 10.244.1.8 host1 <none> <none> nginx-deployment-65998d8886-qp6jj 1/1 Running 0 4m33s 10.244.1.9 host1 <none> <none>
刪除 nginx-deployment:
[root@ken ~]# kubectl delete -f nginx.yml deployment.extensions "nginx-deployment" deleted
label 控制 Pod 的位置
默認配置下,Scheduler 會將 Pod 調度到所有可用的 Node。不過有些情況我們希望將 Pod 部署到指定的 Node,比如將有大量磁盤 I/O 的 Pod 部署到配置了 SSD 的 Node;或者 Pod 需要 GPU,需要運行在配置了 GPU 的節點上。
Kubernetes 是通過 label 來實現這個功能的。
label 是 key-value 對,各種資源都可以設置 label,靈活添加各種自定義屬性。比如執行如下命令標注 k8s-node1 是配置了 SSD 的節點。
第一步:定義標簽
disk為自定義字符串
[root@ken ~]# kubectl label node host1 disk=ssd
第二步:查看標簽
[root@ken ~]# kubectl get node --show-labels NAME STATUS ROLES AGE VERSION LABELS host1 Ready <none> 8h v1.13.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disk=ssd,kubernetes.io/hostname=host1 host2 Ready <none> 8h v1.13.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=host2 ken Ready master 8h v1.13.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=ken,node-role.kubernetes.io/master=
disk=ssd 已經成功添加到 host1,除了 disk,Node 還有幾個 Kubernetes 自己維護的 label。
第三步:配置nginx.yml
有了 disk 這個自定義 label,接下來就可以指定將 Pod 部署到 host1。編輯 nginx.yml:
在 Pod 模板的 spec 里通過 nodeSelector 指定將此 Pod 部署到具有 label disktype=ssd 的 Node 上。
注意:1. nodeSelector需要與containers位置保持一致
2. S必須大寫
第四步:部署
部署 Deployment
[root@ken ~]# kubectl apply -f nginx.yml deployment.extensions/nginx-deployment created
第五步:查看 Pod 的運行節點
[root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-5d8db4598d-2gdmz 0/1 ContainerCreating 0 102s <none> host1 <none> <none> nginx-deployment-5d8db4598d-cq55q 0/1 ContainerCreating 0 102s <none> host1 <none> <none> nginx-deployment-5d8db4598d-qjh4x 0/1 ContainerCreating 0 102s <none> host1 <none> <none>
全部 3個副本都運行在 host1 上,符合我們的預期。
要刪除 label disktype,執行如下命令:
kubectl label node k8s-node1 disktype-
– 即刪除。
[root@ken ~]# kubectl label node host1 disk- node/host1 labeled [root@ken ~]# kubectl get node --show-labels NAME STATUS ROLES AGE VERSION LABELS host1 NotReady <none> 8h v1.13.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=host1 host2 Ready <none> 8h v1.13.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=host2 ken Ready master 9h v1.13.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=ken,node-role.kubernetes.io/master=
不過此時 Pod 並不會重新部署,依然在 host1 上運行。
[root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-5d8db4598d-2dbw9 1/1 Running 0 39s 10.244.1.12 host1 <none> <none> nginx-deployment-5d8db4598d-4brh5 1/1 Running 0 39s 10.244.1.11 host1 <none> <none> nginx-deployment-5d8db4598d-p87mj 1/1 Running 0 39s 10.244.1.13 host1 <none> <none>
除非在 nginx.yml 中刪除 nodeSelector 設置,然后通過 kubectl apply 重新部署。
不需要刪除之前的deployment,直接部署即可
Kubernetes 自己會刪除之前的 Pod 並調度和運行新的 Pod。
[root@ken ~]# kubectl apply -f nginx.yml [root@ken ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-5d8db4598d-p87mj 0/1 Terminating 0 2m 10.244.1.13 host1 <none> <none> nginx-deployment-65998d8886-t5nmv 1/1 Running 0 7s 10.244.2.9 host2 <none> <none> nginx-deployment-65998d8886-wz7c2 1/1 Running 0 4s 10.244.2.10 host2 <none> <none> nginx-deployment-65998d8886-xdlz4 1/1 Running 0 6s 10.244.1.14 host1 <none> <none>
Continue Reading