1. 程式人生 > >06 . Kubernetes之Pod控制器詳細介紹及應用

06 . Kubernetes之Pod控制器詳細介紹及應用

#### Pod API屬性詳解 > Pod是k8s叢集中的最小編排單位。將這個設計落實到API物件上,容器就成了Pod屬性裡一個普通的欄位。那麼到底哪些屬性屬於Pod物件,哪些屬性屬於容器的呢?先看下面的一段描述: > > > > 假如把Pod看成傳統環境裡的"機器"、那麼容器就是執行在這個"機器"裡的"使用者程式",這樣很多關於Pod物件的設計就非常容易理解了。凡是排程、網路、儲存,以及安全相關的屬性,基本上是Pod級別的。他們的共同特徵是:描述的是"機器"這個整體,而不是裡面執行的"程式"。比如: ```python # 配置這個"機器"的網絡卡——Pod 的網路定義 # 配置這個"機器"的磁碟——Pod 的儲存定義 # 配置這個"機器"的防火牆——Pod 的安全定義 # 這臺"機器"執行在哪個伺服器之上——Pod 的排程 ``` ##### 關於標籤 > 所有的資源都可以設定標籤,目的就是為了給資源貼識別符號,使用時用選擇器呼叫標籤,用到標籤的地方: > > > > 後端有以副本形式存在的Pod,這麼多副本最好做負載均衡,此時就在前面建立一個service,一般情況下是先建立rc,然後建立service,建立完成後需要將service和後端的rc關聯到一起,關聯到一起就是用標籤選擇器關聯的,即使不需要標籤也最好設定一個能用的標籤,標籤可以由多個字典元素組成. 標籤的格式: name:value,一個鍵值對錶示一個標籤,呼叫時一起呼叫,例如: 做nginx,這裡是眾多nginx的第一個,故可以設定這個標籤由兩個字典元素組成,標籤可以有多行,但標籤的值不能是純數字. #### Pod級別的相關屬性 > 凡是跟Namespace都是Pod級別的,比如,容器的Linux Namespace、容器共享宿主機的 Namespace > 原因:Pod 的設計就是要讓它裡面的容器儘可能多地共享Linux Namespace,僅保留必要的隔離和限制能力。如此Pod模擬出的效果才能跟虛擬機器里程序間的關係非常類似. ##### **apiVersion** `除了deployment是v1的升級版,其他的基本都是v1。 # kubectl api-versions` ##### **kind** `指定這個API物件的資源型別: Pod、Deployment、Job、Ingress、Service等,資源型別的首字母需大寫.` **metadata** `描述建立資源的屬性,比如Pod的名稱,namspace、標籤等資訊.` **spec** > specification of the resource content: 指定該資源的內容,包括一些container,storage,volume以及其他k8s需要的引數,以及諸如是否在容器失敗時重新啟動容器的屬性,可在特定Kubernetes API找到完整的Kubernetes Pod屬性. **Spec常用欄位** ```yaml # Pod資源: spec.containers <[]object > spec: containers: - name image # 倉庫路徑,專案名稱,使用者,映象名稱,映象標籤 ports: - name: http containerPort: 80 - name: https containerPort: 443 imagePullPolicy: IfNotPresent # 映象獲取策略 # 修改映象中的預設應用: command,args # 標籤<最多六十三個字元> key=value key: 字元,數字,_-,.,# 只能以字母數字開頭及結尾 value: 可以為空,    # 只能字母或者數字開頭及結尾,中間可使用: # Always,Never,IfNotPresent # Always: 本地不管有沒有映象都是要到倉庫去下載,本地無論有還是沒有到要去倉庫下載,就算本地有映象他也不用: # 雖然會導致容器啟動變慢,但是可以防止被人惡意修改映象不被中招: # Never: 永遠不下載,需要使用者手動去拖映象,映象一旦建立,不允許被更改,一旦編輯就報錯,除非刪除再建立: # IfNotPresent: 本地不存在就去下載: # 如果是latest標籤就是Always,否則就是IfNotPresent ``` ##### Example1(給Pod打標籤示例) ```yaml cat demo1-pod.yaml apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: - "/bin/sh" - "-c" - "sleep 3600" ``` ##### 檢視Pod標籤 ```python [root@master YAML]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx-test2 1/1 Running 0 37m run=nginx-test2 pod-demo 2/2 Running 0 2m30s app=myapp,tier=frontend [root@master YAML]# kubectl get pods -L app # 顯示指定資源類別物件下所有標籤的值. NAME READY STATUS RESTARTS AGE APP nginx-test2 1/1 Running 0 36m pod-demo 2/2 Running 0 71s myapp [root@master YAML]# kubectl get pods -l app # -l才是過濾 NAME READY STATUS RESTARTS AGE pod-demo 2/2 Running 0 84s ``` ##### **修改標籤** ```yaml # 如果期望將金絲雀改變為穩定版,覺得版本釋出沒問題,可以改過去 kubectl label pods pod-demo release=canar # 標籤不能重名,如果需要重名加上--overwrite覆蓋即可. kubectl label pod pod-demo release=stable --overwrite # 修改節點標籤 kubectl label nodes node1 disktype=ssd ``` ##### **標籤選擇器** `等值關係: =,==,!=都表示等值關係` ```python kubectl get pods -l release=stable,app --show-labels NAME READY STATUS RESTARTS AGE LABELS pod-demo 2/2 Running 0 11m app=myapp,release=stable,tier=frontend # 集合關係: # KEY in (VALUE1,VALUE2...) # KEY notin (VALUE1,VALUE2...) ``` **nodeSelector 能影響Pod排程演算法** > 如果我們需要對一些節點擁有ssd硬碟的機器做監控就需要將相應節點打上ssd標籤.然後通過標籤選擇器將Pod執行在指定節點上. > > > > 我們在之前那個demo-pod配置檔案加上一個欄位即可. `我們先給節點打標籤 ` ```python kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS master Ready master 43h v1.17.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/master= node1 Ready 43h v1.17.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux node2 Ready 43h v1.17.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2,kubernetes.io/os=linux kubectl label nodes node1 disktype=ssd node/node1 labeled kubectl get nodes --show-labels |grep disktype=ssd node1 Ready 43h v1.17.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux ``` `我們重新修改下demo1-pod.yaml` ```yaml cat demo1-pod.yaml apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: - "/bin/sh" - "-c" - "sleep 3600" nodeSelector: disktype: ssd kubectl create -f demo1-pod.yaml kubectl get pods -o wide kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-test2 1/1 Running 0 49m 10.244.0.18 master pod-demo 2/2 Running 0 53s 10.244.1.15 node1 ``` **annotations:** > 與label不同地方在於,他不能用於挑選資源物件,沒有字元限制,僅用於物件提供“元資料”和`註解`. ```yaml cat demo1-pod.yaml --- apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend annotations: youmen.com/create-by: "youmen" spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: - "/bin/sh" - "-c" - "sleep 3600" nodeSelector: disktype: ssd kubectl create -f pod-demo.yaml kubectl describe pods pod-demo |grep Annotations Annotations: youmen.com/create-by: youmen ``` ##### Pod生命週期 **Pod生命週期** `狀態` ```python Pending: # 排程尚未完成 Running: # 正在執行 Failed: # 失敗 Succeded: # 成功 Unknown: # 未知狀態. ``` **建立Pod過程** > 當用戶建立Pod時,這個請求提交給API Server,他先將狀態儲存在etcd中,APIServer,接下來會請求Scheduler進行排程,如果排程成功後會將結果儲存在etcd資源,更新到etcd狀態資源中,隨後目標節點調到node1上,根據那個清單建立所需要的Pod. ##### Probe機制 ```python # Pod生命週期的重要行為: # 初始化容器: # 容器探測: # 1. lieness probe: <是否存活> # 如果檢查失敗,殺死容器,根據Pod的restartPolicy來操作 # 2. readiness probe: <是否就緒> # 如果檢查失敗,Kubernetes會把Pod從service endpoints中刪除. # 兩種都支援三種探測行為: # 1. exec: 執行自定義命令,看返回狀態碼是否為0 # 2. tcpSocket: 向指定TCP套接字發請求,埠發請求,發起 # 3. httpGet: 向指定http服務發請求,應用層get,url響應碼. # 存活性探測: 主要用於判定主容器是否處於執行狀態 # 就緒性探測: 適用於判定容器中主程序是否處於就緒並可以對外進行服務. ``` **readiness probe:** > 我們為動態有生命週期Pod提供一個固定的端點,service用標籤選擇器關聯到各個Pod資源: > > > > 此處有一個問題,如果有一個新的Pod,這個新Pod剛好符合service條件加入到後端,而有新請求進來就會被排程到新的Pod,但這個時候新Pod裡面服務很有可能還沒有就緒,裡面檔案還沒有展開,而這個時候去訪問就有可能出現訪問失敗,如果不做就緒性探測,Pod一建立就關聯到service後出現大量訪問失敗: ```yaml restartPolicy: <重啟策略> Always,UnFailure,Never,Default to Always. Always: # 一旦Pod中容器掛了就地將他重啟. UnFailure: # 狀態為錯誤才重啟,正常終止不重啟: # 延時重啟 Never: # 掛了就掛了,從來不重啟. ``` **Example** ```python cat pod-probe.yaml apiVersion: v1 kind: Pod metadata: name: nginx-pod labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 livenessProbe: httpGet: path: /index.html port: 80 kubectl logs nginx-pod 10.244.3.1 - - [22/Dec/2019:11:03:04 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "kube-probe/1.17" "-" 10.244.3.1 - - [22/Dec/2019:11:03:14 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "kube-probe/1.17" "-" 10.244.3.1 - - [22/Dec/2019:11:03:24 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "kube-probe/1.17" "-" 10.244.3.1 - - [22/Dec/2019:11:03:34 +0000] "GET /index.html HTTP/1.1" 200 612 "-" "kube-probe/1.17" "-" # 我們可以看到每十秒都會進行一次測試 # 接下來我們把那個頁面刪除,看會怎麼樣 kubectl exec -it nginx-pod /bin/bash rm -rf usr/share/nginx/html/index.html # 然後我們去事件裡面看看他做了什麼處理. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m35s default-scheduler Successfully assigned default/nginx-pod to node1 Normal Pulling 43s (x2 over 3m34s) kubelet, node1 Pulling image "nginx" Warning Unhealthy 43s (x3 over 63s) kubelet, node1 Liveness probe failed: HTTP probe failed with statuscode: 404 Normal Killing 43s kubelet, node1 Container nginx failed liveness probe, will be restarted Normal Pulled 21s (x2 over 3m14s) kubelet, node1 Successfully pulled image "nginx" Normal Created 21s (x2 over 3m14s) kubelet, node1 Created container nginx Normal Started 21s (x2 over 3m14s) kubelet, node1 Started container nginx # 我們可以看到當檢測不到報錯的話,他會自己重新建立一個新映象.此處只是個頁面檢測, # 如果是其他型別服務也可以使用TCP套接字做檢測. ``` ##### **Pod的排錯** ```python kubectl describe TYPE NAME_PREFIX kubectl logs nginx-xx kubectl exec -it nginx-xx bash or /bin/bash ``` ##### **許多資源支援內嵌欄位** > matchLabels: 直接給定鍵值 > matchExpresslons: 基於給定的表示式來定義使用標籤選擇器,{key:"KEY",operator: "OPERATOR" ,values: [VAL1,VAL2...]} ```python # 操作符 # In,NotIn: values欄位的值必須為空列表. # Exists,NotExists: values欄位的值為空列表. ``` ​ #### Pod控制器 > Pod控制器用於實現代我們管理Pod中間層,幫我們確保Pod是我們所期望的目標狀態,如果出現故障,他會嘗試重啟,如果重啟失敗,他會嘗試重新編排重新構建一個,如果Pod副本數量低於使用者定義目標數量,他會自動補全,反之終止多餘目標資源 > > > > 但此處Pod控制器只是一個泛稱,包含以下控制器 ##### ReplicaSet控制器(ReplicationController) > 核心作用在於代使用者建立指定數量的副本,並確保副本數量一直符合使用者所定義狀態,還支援擴縮容機制 > **kubernetes不建議我們直接使用ReplicaSet,而是用Deployment,因為它還支援滾動更新,回滾,宣告式配置更新** > **簡寫為rs** ```yaml cat rs-demo1.yaml apiVersion: apps/v1 kind: ReplicaSet metadata: name: myapp namespace: default spec: replicas: 2 selector: matchLabels: app: myapp release: canary template: metadata: name: myapp-pod labels: app: myapp release: canary environment: qa spec: containers: - name: myapp-container image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 # 我們此處的標籤儘量條件匹配複雜一點,避免以後建立Pod標籤衝突,多退少補 # 如果需要新增副本數量直接edit配置檔案即可,最好使用打補丁方式修改. # 如果需要更新版本,只有重建Pod才能更新成功. # 還能控制更新節奏,加一個刪一個,加一個刪兩個,加兩個刪兩個.d # 灰度釋出: 刪一個建立一個 # 金絲雀釋出: 刪一個,等過段時間看使用者反應,沒什麼不好的影響全部給升級 # 藍綠髮布: 在建立個RS,改下service匹配條件,讓請求都匹配到RS2上. # Deployment就建構在RS之上.一個Deployment可以管理多個RS, ``` ![](https://img2020.cnblogs.com/blog/1871335/202007/1871335-20200702162538062-210053903.png) ##### Deployment控制器 **kubernetes不建議我們直接使用ReplicaSet,而是用Deployment,因為它還支援滾動更新,回滾,宣告式配置更新,管理無狀態非常好** ```python cat pod-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy namespace: default spec: replicas: 2 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deploy-7d574d56c7-44mqw 1/1 Running 0 52s myapp-deploy-7d574d56c7-5msnk 1/1 Running 0 52s # 此處的5msnk是模板的雜湊值.我們可以通過apply增加副本數量,但是後面雜湊值不變 kubectl describe deploy myapp-deploy ``` **我們可以實時更新一下** ``` python kubectl get pods -l app=myapp -w NAME READY STATUS RESTARTS AGE myapp-deploy-7d574d56c7-44mqw 1/1 Running 0 2m56s myapp-deploy-7d574d56c7-5msnk 1/1 Running 0 2m56s # 我們再另開一個終端修改配置檔案或者打補丁,然後實時檢視此處的雜湊變化. kubectl edit deploy myapp-deploy replicas: 4 - image: ikubernetes/myapp:v2 kubectl get pods -l app=myapp -w NAME READY STATUS RESTARTS AGE myapp-deploy-7d574d56c7-44mqw 1/1 Running 0 8m15s myapp-deploy-7d574d56c7-5msnk 1/1 Running 0 8m15s myapp-deploy-7d574d56c7-gvl9q 0/1 Pending 0 0s myapp-deploy-798dc9b584-z7jhh 0/1 Pending 0 0s myapp-deploy-7d574d56c7-gvl9q 0/1 Pending 0 0s myapp-deploy-7d574d56c7-nkwt6 0/1 Pending 0 0s myapp-deploy-798dc9b584-z7jhh 0/1 Pending 0 1s myapp-deploy-7d574d56c7-nkwt6 0/1 Pending 0 1s myapp-deploy-7d574d56c7-gvl9q 0/1 ContainerCreating 0 1s myapp-deploy-7d574d56c7-nkwt6 0/1 ContainerCreating 0 1s myapp-deploy-798dc9b584-q8fxd 0/1 Pending 0 0s myapp-deploy-798dc9b584-q8fxd 0/1 Pending 0 0s myapp-deploy-798dc9b584-z7jhh 0/1 ContainerCreating 0 1s myapp-deploy-7d574d56c7-gvl9q 0/1 Terminating 0 1s myapp-deploy-798dc9b584-q8fxd 0/1 ContainerCreating 0 0s myapp-deploy-7d574d56c7-gvl9q 0/1 Terminating 0 1s myapp-deploy-7d574d56c7-nkwt6 1/1 Running 0 3s myapp-deploy-798dc9b584-z7jhh 1/1 Running 0 7s myapp-deploy-7d574d56c7-nkwt6 1/1 Terminating 0 7s myapp-deploy-798dc9b584-sjj65 0/1 Pending 0 0s myapp-deploy-798dc9b584-sjj65 0/1 Pending 0 0s myapp-deploy-798dc9b584-sjj65 0/1 ContainerCreating 0 0s myapp-deploy-7d574d56c7-gvl9q 0/1 Terminating 0 8s myapp-deploy-7d574d56c7-gvl9q 0/1 Terminating 0 8s myapp-deploy-7d574d56c7-nkwt6 0/1 Terminating 0 8s myapp-deploy-7d574d56c7-nkwt6 0/1 Terminating 0 9s myapp-deploy-7d574d56c7-nkwt6 0/1 Terminating 0 9s myapp-deploy-798dc9b584-sjj65 1/1 Running 0 2s myapp-deploy-7d574d56c7-44mqw 1/1 Terminating 0 9m13s myapp-deploy-798dc9b584-rdtmd 0/1 Pending 0 0s myapp-deploy-798dc9b584-rdtmd 0/1 Pending 0 0s myapp-deploy-798dc9b584-rdtmd 0/1 ContainerCreating 0 0s myapp-deploy-7d574d56c7-44mqw 0/1 Terminating 0 9m14s myapp-deploy-798dc9b584-q8fxd 1/1 Running 0 10s myapp-deploy-798dc9b584-rdtmd 1/1 Running 0 2s myapp-deploy-7d574d56c7-5msnk 1/1 Terminating 0 9m15s myapp-deploy-7d574d56c7-5msnk 0/1 Terminating 0 9m16s myapp-deploy-7d574d56c7-5msnk 0/1 Terminating 0 9m17s myapp-deploy-7d574d56c7-5msnk 0/1 Terminating 0 9m17s myapp-deploy-7d574d56c7-44mqw 0/1 Terminating 0 9m22s myapp-deploy-7d574d56c7-44mqw 0/1 Terminating 0 9m22s ``` **我們可以檢視一下rs,此處有兩個版本了,一個v1一個v2** ```python kubectl get rs -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-deploy-798dc9b584 4 4 4 4m15s myapp ikubernetes/myapp:v2 app=myapp,pod-template-hash=798dc9b584,release=canary myapp-deploy-7d574d56c7 0 0 0 13m myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=7d574d56c7,release=canary # 但是myapp:v1為歷史版本,會保留著隨時等待被回滾. # 可以使用下面命令進行版本回滾 kubectl rollout history deployment myapp-deploy deployment.apps/myapp-deploy REVISION CHANGE-CAUSE 1 2 ``` **我們可以使用patch打補丁方式修改實時更新策略** ```python kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}' # 此時副本數量就為5個了 kubectl describe deployment myapp-deploy # 修改deployment最大不可用和最小保留 kubectl describe deployment myapp-deploy |grep RollingUpdateStrategy RollingUpdateStrategy: 0 max unavailable, 1 max surge # 接下來我們修改下映象版本,然後更新看一看(金絲雀釋出) kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 && kubectl rollout pause deployment myapp-deploy deployment.apps/myapp-deploy image updated deployment.apps/myapp-deploy paused # 另一個終端使用以下命令實時檢視 kubectl get pods -l app=myapp -w NAME READY STATUS RESTARTS AGE myapp-deploy-798dc9b584-bcdxf 1/1 Running 0 14m myapp-deploy-798dc9b584-q8fxd 1/1 Running 0 57m myapp-deploy-798dc9b584-rdtmd 1/1 Running 0 57m myapp-deploy-798dc9b584-sjj65 1/1 Running 0 57m myapp-deploy-798dc9b584-z7jhh 1/1 Running 0 57m myapp-deploy-5dc9c974d7-qlpmq 0/1 Pending 0 0s myapp-deploy-5dc9c974d7-qlpmq 0/1 Pending 0 0s myapp-deploy-5dc9c974d7-qlpmq 0/1 ContainerCreating 0 0s myapp-deploy-5dc9c974d7-qlpmq 1/1 Running 0 9s kubectl rollout status deployment myapp-deploy Waiting for deployment "myapp-deploy" rollout to finish: 1 out of 5 new replicas have been updated... # 此時我們發現他會一直卡在這一個Pod更新,接下來我們讓他全部更新 kubectl rollout resume deployment myapp-deploy # 我們發現此時有了第三個版本 kubectl get rs -o wide NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-deploy-5dc9c974d7 5 5 5 5m4s myapp ikubernetes/myapp:v3 app=myapp,pod-template-hash=5dc9c974d7,release=canary myapp-deploy-798dc9b584 0 0 0 64m myapp ikubernetes/myapp:v2 app=myapp,pod-template-hash=798dc9b584,release=canary myapp-deploy-7d574d56c7 0 0 0 73m myapp ikubernetes/myapp:v1 app=myapp,pod-template-hash=7d574d56c7,release=canary # 接下來我們可以用回滾 kubectl rollout undo deployment myapp-deploy --to-revision=1 # 回滾到第一個版本 kubectl rollout history deployment myapp-deploy deployment.apps/myapp-deploy REVISION CHANGE-CAUSE 2 3 4 # 此時我們看到已經有第四個版本了,而此時工作的是v1版 curl 10.244.2.20 Hello MyApp | Version: v1 | Pod Name ``` ##### DaemonSet控制器 > **在叢集中每個節點只執行一個Pod副本** > **也可以根據自己需求,在部分節點執行一個Pod副本** > **DaemonSet有以下特點** ```python # 1. 一般是無狀態的 # 2. 這種服務必須是守護程序,持續執行在後臺 ``` **Example1** ```yaml cat pod-ds.yaml apiVersion: apps/v1 kind: Deployment metadata: name: redis namespace: default spec: replicas: 1 selector: matchLabels: app: redis role: logstor template: metadata: labels: app: redis role: logstor spec: containers: - name: redis image: redis:4.0-alpine ports: - name: redis containerPort: 6379 --- apiVersion: apps/v1 kind: DaemonSet metadata: name: myapp-ds namespace: default spec: selector: matchLabels: app: filebeat release: stable template: metadata: labels: app: filebeat release: stable spec: containers: - name: filebeat image: ikubernetes/filebeat:5.6.5-alpine env: - name: REDIS_HOST value: redis.default.svc.cluster.local - name: REDIS_LOG_LEVEL value: info kubectl exec -it redis-646cf89449-b5qkr /bin/bash Address 1: 10.96.249.167 redis.default.svc.cluster.local ``` **DaemonSet也支援滾動更新** ```python kubectl get ds -o wide NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR myapp-ds 2 2 2 2 2 23m filebeat ikubernetes/filebeat:5.6.5-alpine app=filebeat,release=stable [root@master ~]# kubectl set image daemonsets myapp-ds filebeat=ikubernetes/filebeat:5.6.6-alpine ``` **Example2 (Pod中容器和宿主機共享網路、程序通訊和程序PID Namespace)** ``` yaml cat ns1.yaml apiVersion: v1 kind: Pod metadata: name: web-nginx2 spec: hostNetwork: true hostIPC: true hostPID: true containers: - name: web-nginx2 image: daocloud.io/library/nginx - name: shell image: busybox stdin: true tty: true kubectl apply -f ns1.yaml kubectl attach -it web-nginx2 -c shell / # ps ax |grep network 3522 root 15:32 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --\ kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml \ --cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.1 23958 root 0:00 grep network # Pod中的所有容器直接使用宿主機的網路、直接與宿主機進行IPC通訊,且能夠看到宿主機正在執行的所有程序 ``` ##### Job **此類控制器主要為了完成指定任務、作業,只要沒完成作業就會不斷重建直至完成** **幫我們確保Pod任務是正常完成的,沒有出現什麼異常** **但是隻是一次性任務** **也可以使週期性任務,但他們不需要持續在後臺執行,CronJob** `以上控制器只能針對無狀態應用,` ##### StatefulSet **針對每一種服務每一種報錯都要定義相應的恢復操作** **比如說你Mysql主從節點的從節點宕機了,你要定義很多操作建立一個從節點然後讓他們銜接,稍有不慎,整個叢集就崩潰了** **我們可以通過Operator將一些運維技能給灌進去,但是支援的應用有限** **直到後來出現了helm,類似於yum,類似於模板** ##### Example1(Pod中容器共用一個Pid Namespace) ```python cat ns.yaml apiVersion: v1 kind: Pod metadata: name: web-nginx spec: shareProcessNamespace: true containers: - name: web-nginx image: daocloud.io/library/nginx - name: shell image: busybox stdin: true tty: trdue # 1、shareProcessNamespace: true表示此Pod中的容器共享PID,即每個容器都能看到其他容器內的程序 # 2. 定義兩個容器:一個nginx;一個等同於使用-it選項的容器 此Pod被建立後,就可以使用shell容器的tty跟這個容器進行互動。 kubectl apply -f ns.yaml kubectl attach -it web-nginx -c shell If you don't see a command prompt, try pressing enter. / # ps ax PID USER TIME COMMAND 1 root 0:00 /pause 6 root 0:00 nginx: master process nginx -g daemon off; 11 101 0:00 nginx: worker process 21 root 0:00 sh 26 root 0:00 ps ax # 在容器裡能同時看到nginx和busybox以及Infra容器的/pause的程序,整個Pod裡的每個容器程序對於所有容器來說都是可見的, # 因為它們共享同一個 PID Namespace。 ``` #### **node的相關屬性** > nodeName: 這個欄位一般由排程器負責設定,使用者也可以設定他來'騙過'排程器,一旦Pod的這個欄位被賦值,k8s就會被認為此Pod已經排程過,排程的結果就是賦值的節點名字,這個做法一般是測試或者除錯的時候才會用到,簡單來說就是不讓排程器去選擇此Pod執行在哪個node上,而是使用者自行指定該Pod執行的node. > > > > nodeSelector: 和nodeName的作用一樣,是一個供使用者將Pod與Node進行繫結的欄位,例如: 設定Pod永遠只能執行在攜帶了: "Kubernetes.io/hostname: k8s-node1"標籤的節點上: 否則,他將排程失敗. ##### Example1(使用nodeSelector指定pod執行的節點) **檢視k8s-node1上的標籤都有哪些** ```python kubectl describe pod web-nginx |grep ^Labels -C3 Priority: 0 Node: node2/172.19.0.54 Start Time: Thu, 19 Dec 2019 17:45:43 +0800 Labels: Annotations: Status: Running IP: 10.244.1.5 ``` **建立一個Pod指定執行在node1上** ```yaml cat nginx1.yaml --- apiVersion: v1 kind: Pod metadata: name: test-nginx labels: web: nginx2 nginx: nginx3 spec: # nodeName: 192.168.122.5 #也可以使用下面的nodeSelector。 containers: - name: web-test image: daocloud.io/library/nginx ports: - containerPort: 80 nodeSelector: kubernetes.io/hostname: node1 kubectl apply -f nginx1.yaml ``` ##### 容器中的hosts檔案解析 **HostAliases: 定義Pod容器中的/etc/hosts檔案,解析主機名,且在k8s中,一定要通過此方法設定hosts檔案中的內容,如果直接修改hosts檔案,在Pod被刪除重建之後,kubelet會自動覆蓋被修改的內容** ```yaml cat nginx2.yaml --- apiVersion: v1 kind: Pod metadata: name: web-nginx3 labels: web: nginx4 nginx: nginx5 spec: hostAliases: - ip: "1.1.1.1" hostnames: - "cluster1.com" - "cluster2.com" - "cluster3.com" containers: - name: web2 image: daocloud.io/library/nginx ports: - containerPort: 80 kubectl apply -f nginx2.yaml kubectl exec -it web-nginx3 /bin/bash root@web-nginx3:/# ls bin dev home lib64 mnt proc run srv tmp var boot etc lib media opt root sbin sys usr root@web-nginx3:/# cat /etc/hosts # Kubernetes-managed hosts file. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 10.244.1.6 web-nginx3 # Entries added by HostAliases. 1.1.1.1 cluster1.com cluster2.com cluster3.com 多個ip對應不同域名的寫法 spec: hostAliases: - ip: "1.1.1.1" hostnames: - "cluster1.com" - ip: "2.2.2.2" hostnames: - "cluster2.com" ``` **容器的屬性** > 容器是Pod中最重要的欄位,有"Containers" 和"Init Containers" 兩種寫法,內容完全相同. > > > > Init Containers: 其生命週期會先於所有的容器(即優先啟動),並且嚴格按照定義的順序執行. > > > > containers: 指定多個名稱表示多個容器,每一個容器都是列表中的一個元素,每一列元素中還會有字典,字典不同的元素表示容器的不同屬性,容器可以設定複雜的屬性,包括容器啟動執行的命令,使用的引數、工作目錄以及每次例項化是否拉取新的副本,還可以指定更深入的資訊,例如容器的退出日誌的位置等. 包括: name、image、command、args、workingDir、ports、env、resource、volumeMounts、livenessProbe、readinessProbe、livecycle、terminationMessagePath、imagePullPolicy、securityContext、stdin、stdinOnce、tty ```python name:容器的名字,起個有意義的名字 image:容器映象 command:容器啟動執行的命令 args:容器使用的引數 workingDir:容器的工作目錄 ports:容器監聽的埠 env:定義容器的環境變數,主要是給mysql這種應用使用的spec:containers:env env: - name: a # 變數名稱 value: "hello" # 變數值,必須加引號 volumeMounts:# 共享卷 imagePullPolicy:# 映象拉取策略,此屬性有bug。 # 預設值Always表示每次建立Pod都重新拉取一次映象,實際上是映象在本地無需拉取; Never:# 不拉取映象,本地有直接使用,本地不存在就報異常錯誤 IfNotPresent: # 表示宿主機上不存在這個映象時才拉取,建議使用。 ``` ##### 官方提供的鉤子示例 > 容器成功啟動之後,在/usr/share/message中寫入了一句“歡迎資訊”(PostStart定義),在這個容器被刪除之前,則先呼叫nginx的退出命令(preStop定義),從而實現容器中的應用從而關閉. ```yaml cat message.yaml apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: daocloud.io/library/nginx lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: exec: command: ["/usr/sbin/nginx","-s","quit"] kubectl apply -f message.yaml ``` **註釋** > postStart: 開始之後執行的動作,雖然理論上是在Docker容器ENTRYPOINT執行之後,但它並不嚴格保證順序。即:在postStart啟動時,ENTRYPOINT有可能還沒有結束。如果postStart執行超時或者錯誤,k8s會在該Pod的Events中報出該容器啟動失敗的錯誤資訊,導致Pod也處於失敗的狀態。 > > > > preStop:停止之前指定的動作。操作的執行是同步的,所以它會阻塞當前的容器殺死流程,直到這個 Hook定義操作完成之後,才允許容器被殺死。 **Pod | docker 容器的生命週期** > Pod宣告週期的變化,主要體現在Pod API物件的Status部分,這是除了Metadata和Spec之外的第三個重要欄位,其中Pod.status.phase就是Pod的當前狀態,有如下幾種可能的情況: > > > > Pending: 此狀態表示Pod的YAML檔案已經提交給了kubernetes,API物件已經被建立並儲存在Etcd中.但是這個Pod裡有些容器因為某種原因不能被順利建立,比如: 排程不成功. (準備狀態: 準備好了就running,準備不好就是failed) ```python # Running: 此狀態表示Pod已經排程成功,跟一個具體的節點繫結,它包含的容器都已經建立成功,並且至少有一個正在執行中. # Succeeded: 此狀態表示Pod裡的所有容器都正常執行完畢,並且已經退出了,這種情況在執行一次性任務最為常見. # Failed: 此狀態表示Pod裡至少有一個容器以不正常的狀態退出,這個狀態出現以為這個你得Debug這個容器的應用,比如檢視Pod的Events和日誌. # Unknown: 這是一個異常狀態,表示Pod的狀態不能持續的kubelet彙報給kube-apiserver,這很有可能是主從節點(Master和Kubelet)之間的通訊出現了問題. ``` `細分Pod物件的Status欄位` > Pod物件的Status欄位還可以細分一組Conditions,包括: PodScheduled、Ready、Initialized、以及Unschedulable,他們主要用於描述當前Status的具體原因,比如: Pod當前的Status是Pending,對應的Condition是Unschedulable,這表示他的排程出現了問題. > > 投射資料卷Projected Volume > > > > 是Kubernetes v1.11之後的新特性,在K8s中,有幾種特殊的Volume,他們既不是存放容器裡的資料,也不是用來和宿主機之間的資料交換,而是為容器提供預先定義好的為新建容器提供字串的,字串有長有短,就可以使用不同型別的投射資料卷,當然這個工作普通的volumn也可以實現,但是普通的volumn很容易暴露密碼,token或者祕鑰等敏感資料,而使用投射資料卷方式可以把敏感資料的資源直接存放在k8s叢集的資料庫中,可以更方便的控制這些資料,並減少暴露的風險,從容器的角度來看,這些Volume裡的資訊彷彿是被k8s"投射"(Project)進入容器當中的. **k8s支援的Projected Volume** ```python # Secret: 設定密碼可以使用 # ConfigMap: 準備配置檔案使用 # Downward API: 設定環境變數 # ServiceAccountToken: 屬於一種特殊的Secret,做認證使用. # 使用時分兩步: # 做出相應的投射資料卷存放到資料庫 # 建立容器時使用. ``` #### Pod的重啟策略 ##### **三種重啟策略** ```python Always: # 當容器停止,總是重建容器,預設策略 OnFailure: # 當容器異常退出(退出狀態碼非0)時,才重啟容器 Never: # 當容器終止退出,從不重啟容器. ``` ##### **Example** ```yaml apiVersion: v1 kind: Pod metadata: name: nginx-pod labels: app: nginx spec: containers: - name: nginx image: nginx restartPolicy: OnFail