管理Pod(rc,rs,deployment)
1.概述
可以把容器想像成豆莢里的豆子,把一個或多個關系緊密的豆子包在一起就是豆莢(一個Pod)。在k8s中我們不會直接操作容器,而是把容器包裝成Pod再進行管理.
2.管理Pod
|
1
2
3
|
a. 使用Replication Controller 來部署、升級Pod
b. Replica
Set
– 下一代Replication Controller
c. Deployment – 更加方便的管理Pod和Replica
Set
|
例子1: 提出疑惑
|
1
2
3
4
5
6
7
8
9
10
|
先舉個例子,假設我們有一個Pod在提供線上服務,現在有如下幾個場景,大家想想如何應對:
1.
節日活動,網站訪問量突增
2.
遭到攻擊,網站訪問量突增
3.
運行Pod的節點發生故障
第
1
種情況,活動前預先多啟動幾個Pod,活動結束后再結束掉多余的,雖然要啟動和結束的Pod有點多,但也能有條不紊按計划進行
第
2
種情況,正在睡覺突然手機響了說網站反應特慢卡得要死,趕緊爬起來邊擴容邊查找攻擊模式、封IP等等……
第
3
種情況,正在休假突然手機又響了說網站上不去,趕緊打開電腦查看原因,啟動新的Pod
|
解決辦法:引入rc
|
1
2
3
|
Pod需要手動管理,好累……能否在Pod發生問題時自動恢復呢,我們先來看下Replication Controller(以下簡稱RC)
先說RC是什么。RC保證在同一時間能夠運行指定數量的Pod副本,保證Pod總是可用。如果實際Pod數量比指定的多就結束掉多余的,如果實際數量比指定的少就啟動缺少的。<br>當Pod失敗、被刪除或被終結時RC會自動創建新的Pod來保證副本數量。所以即使只有一個Pod也應該使用RC來進行管理。
|

|
1
2
3
4
5
6
7
|
這個文件定義了RC的屬性,我們先關注如下字段:
spec.replicas:副本數量
3
spec.selector:RC通過spec.selector來篩選要控制的Pod
spec.template:這里寫Pod的定義(但不需要apiVersion和kind)
spec.template.metadata.labels:Pod的label,可以看到這個label與spec.selector相同
這個文件的意思是定義了一個RC對象,它的名字是hello
-
rc(metadata.name:hello
-
rc),保證有
3
個Pod運行(spec.replicas:
3
),<br>Pod的鏡像是index.tenxcloud.com
/
tailnode
/
hello:v1.
0
(spec.template.spec.containers.image: index.tenxcloud.com
/
tailnode
/
hello:v1.
0
)<br>關鍵在於spec.selector與spec.template.metadata.labels,這兩個字段必須相同,否則下一步創建RC會失敗。<br>(也可以不寫spec.selector,這樣默認與spec.template.metadata.labels相同)
|
現在通過kubectl來創建RC:

解決辦法:引入rs,官方推薦使用RS代替RC
|
1
2
3
|
1.RC
只支持基於等式的selector(env
=
dev或environment!
=
qa)但Replica
Set
還支持新的基於集合的selector(version
in
(v1.
0
, v2.
0
)或env notin (dev, qa)),<br>這對復雜的運維管理帶來很大方便
2.
使用Deployment升級Pod只需要定義Pod的最終狀態,k8s會為你執行必要的操作,雖然能夠使用命令kubectl rolling
-
update完成升級,<br>但它是在客戶端與服務端多次交互控制RC完成的,所以REST API中並沒有rolling
-
update的接口,這為定制自己的管理系統帶來了一些麻煩。
3.Deployment
擁有更加靈活強大的升級、回滾功能
|
Replica Set目前與RC的區別只是支持的selector不同,后續肯定會加入更多功能。Deployment使用了Replica Set,是更高一層的概念。除非需要自定義升級功能或根本不需要升級Pod,所以推薦使用Deployment而不直接使用Replica Set。
3.Pod創建流程

|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
step.
1
kubectl 向 k8s api server 發起一個create pod 請求(即我們使用Kubectl敲一個create pod命令) 。
step.
2
k8s api server接收到pod創建請求后,不會去直接創建pod;而是生成一個包含創建信息的yaml。
step.
3
apiserver 將剛才的yaml信息寫入etcd數據庫。到此為止僅僅是在etcd中添加了一條記錄, 還沒有任何的實質性進展。
step.
4
scheduler 查看 k8s api ,類似於通知機制。
首先判斷:pod.spec.Node
=
=
null?
若為null,表示這個Pod請求是新來的,需要創建;因此先進行調度計算,找到最“閑”的node。
然后將信息在etcd數據庫中更新分配結果:pod.spec.Node
=
nodeA (設置一個具體的節點)
ps:同樣上述操作的各種信息也要寫到etcd數據庫中中。
step.
5
kubelet 通過監測etcd數據庫(即不停地看etcd中的記錄),發現 k8s api server 中有了個新的Node;
如果這條記錄中的Node與自己的編號相同(即這個Pod由scheduler分配給自己了);
則調用node中的docker api,創建container。
|
4.ReplicaSet創建流程
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
step.
1
kubectl 發起 create replicaSet 請求
step.
2
k8s api server 接受 replicaSet 創建請求,創建yaml。
step.
3
k8s api server將yaml的信息寫入etcd數據庫。
step.
4
Controller
-
Manager中的ReplicaSetController,在etcd數據庫中讀到了新的replicaSet 信息后,
向k8s api server發起請求,創建
3
個Pod(個數可以自己指定)。
step.
5
scheduler 在etcd中讀到相應信息
若
3pod
.spec.Node
=
=
null
則執行調度計算,找到最“閑”的若干個Node(如果有一個Node真的太閑,可能
3
個Pod都會被起在這個Node上面)
pod1.spec.Node
=
nodeA (更新記錄)
pod2.spec.Node
=
nodeB
pod3.spec.Node
=
nodeA (Node都是隨機分配的)
將這些信息寫回etcd數據庫中。
step.
6
nodeA 的 kubelet 讀etcd時讀到apiserver的信息,調用docker api;創建屬於自己的pod1
/
pod3的container
step.
7
nodeB kubelet 讀到 k8s api server的信息,調用docker api,創建pod2的container。
|
4.生命周期,重啟策略,鏡像拉取
pod聲明周期(狀態):pending , running, succeeded, failed, unknown
|
1
2
3
4
5
|
掛起(Pending):Pod 已被 Kubernetes 系統接受,但有一個或者多個容器鏡像尚未創建。等待時間包括調度 Pod 的時間和通過網絡下載鏡像的時間,這可能需要花點時間。
運行中(Running):該 Pod 已經綁定到了一個節點上,Pod 中所有的容器都已被創建。至少有一個容器正在運行,或者正處於啟動或重啟狀態。
成功(Succeeded):Pod 中的所有容器都被成功終止,並且不會再重啟。
失敗(Failed):Pod 中的所有容器都已終止了,並且至少有一個容器是因為失敗終止。也就是說,容器以非
0
狀態退出或者被系統終止。
未知(Unknown):因為某些原因無法取得 Pod 的狀態,通常是因為與 Pod 所在主機通信失敗。
|
pod重啟策略: 當某個容器異常退出或者健康檢查失敗, kubelet將根據RestartPolicy的設置來進行相應的操作, 重啟策略有Always , OnFailure, Never
|
1
2
3
|
Always: 當容器失效時, 由kubelet自動重啟該容器
OnFailure: 當容器終止運行且退出碼不為
0
時, 由kubelet自動重啟該容器
Never: 不論容器運行狀態如何, kubelet都不會重啟該容器
|
kubelet重啟失效容器的時間間隔以sync-frequency乘以2n來計算, 例如1丶2丶4丶8倍等, 最長延時5min, 並且在重啟后的10min后重置該時間
pod的重啟策略與控制方式息息相關
RC和DeamonSet必須設置為Always,需要保證該容器持續運行
Job: OnFailure或Never, 確保容器執行完成后不再重啟
鏡像拉取策略
|
1
2
3
|
Always: 表示每次都嘗試重新拉取鏡像
IfNotPresent: 表示如果本地有鏡像, 則使用本地的鏡像, 本地不存在時拉取鏡像
Never: 表示僅使用本地鏡像
|
示例
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default labels: app: nginx spec: selector: matchLabels: app: nginx replicas: 1 template: metadata: labels: app: nginx spec: restartPolicy: Always containers: - name: nginx image: nginx:1.12 imagePullPolicy: IfNotPresent ports: - containerPort: 80

