一、污點(Taint)和容忍(Tolerations)
1.1 污點(Taint)
1.1.1 概念
1.節點親和性,是Pod的一種屬性(偏好或硬性要求),它使Pod被吸引到一類特定的節點。Taint則相反,它使節點能夠排斥一類特定的Pod
2.Taint和Toleration相互配合,可以用來避免Pod被分配到不合適的節點上。每個節點上都可以應用一個或多個taint ,這表示對於那些不能容忍這些taint的Pod,是不會被該節點接受的。如果將toleration應用於Pod上,則表示這些 Pod 可以(但不一定)被調度到具有匹配taint的節點上
3.使用kubectl taint命令可以給某個Node節點設置污點,Node被設置上污點之后就和 Pod 之間存在了一種相斥的關系,可以讓Node拒絕 Pod 的調度執行,甚至將Node已經存在的Pod驅逐出去
1.1.2 污點的組成格式
key=value:effect
每個污點有一個key和value作為污點的標簽,其中value可以為空,effect描述污點的作用
1.1.3 effect支持如下三個選項
●NoSchedule:表示 k8s 將不會將 Pod 調度到具有該污點的 Node 上
●PreferNoSchedule:表示 k8s 將盡量避免將 Pod 調度到具有該污點的 Node 上
●NoExecute:表示 k8s 將不會將 Pod 調度到具有該污點的 Node 上,同時會將 Node 上已經存在的 Pod 驅逐出去
1.1.4 master上的NoSchedule污點
master 就是因為有 NoSchedule 污點,k8s 才不會將 Pod 調度到 master 節點上
kubectl describe node master01
1.1.5 node上設置污點
#設置污點
kubectl taint nodes node01 key1=value1:NoSchedule
#節點說明中,查找 Taints 字段
kubectl describe node node01
1.1.6 去除污點
#去除污點
kubectl taint nodes node01 key1:NoSchedule-
#節點說明中,查找 Taints 字段
kubectl describe node node01
1.1.7 污點實例測試
1.先創建兩個pod資源分別在兩個node節點上
kubectl get pods -o wide
2.在node02上創建污點
kubectl taint nodes node02 check=mycheck:NoExecute
3.kubectl get pods -o wide
查看 Pod 狀態,會發現 node02 上的 Pod 已經被全部驅逐(注:如果是 Deployment 或者 StatefulSet 資源類型,為了維持副本數量則會在別的 Node 上再創建新的 Pod
1.2、容忍(Tolerations)
1.2.1 概念
設置了污點的 Node 將根據 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之間產生互斥的關系,Pod 將在一定程度上不會被調度到 Node 上。但我們可以在 Pod 上設置容忍(Tolerations),意思是設置了容忍的 Pod 將可以容忍污點的存在,可以被調度到存在污點的Node上
1.2.2 測試污點
1.在node02設置污點的基礎上,再在node01上設置污點
kubectl taint nodes node01 check=mycheck:NoExecute
2.vim demo1.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: myapp03
labels:
app: myapp03
spec:
containers:
- name: myapp01
image: nginx
==========================================================
3.kubectl apply -f demo1.yaml
4.kubectl get pods -o wide
1.2.3 在設置污點的基礎上設置容忍
vim demo2.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: myapp04
labels:
app: myapp04
spec:
containers:
- name: myapp01
image: nginx
tolerations:
- key: "check"
operator: "Equal"
value: "mycheck"
effect: "NoExecute"
tolerationSeconds: 15
==========================================================
#其中的 key、vaule、effect 都要與 Node 上設置的 taint 保持一致
#operator 的值為 Exists 將會忽略 value 值,即存在即可
#tolerationSeconds 用於描述當 Pod 需要被驅逐時可以在 Pod 上繼續保留運行的時間
==========================================================
kubectl apply -f demo2.yaml
kubectl get pods -o wide -w
1.2.4 容忍的其他注意事項
1.當不指定 key 值時,表示容忍所有的污點 key
tolerations:
- operator: "Exists"
2.當不指定 effect 值時,表示容忍所有的污點作用
tolerations:
- key: "key"
operator: "Exists"
3.有多個 Master 存在時,防止資源浪費,可以如下設置
kubectl taint nodes Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
1.2.5 node升級時,設置污點的流程
//如果某個 Node 更新升級系統組件,為了防止業務長時間中斷,可以先在該 Node 設置 NoExecute 污點,把該 Node 上的 Pod 都驅逐出去
kubectl taint nodes node01 check=mycheck:NoExecute
//此時如果別的 Node 資源不夠用,可臨時給 Master 設置 PreferNoSchedule 污點,讓 Pod 可在 Master 上臨時創建
kubectl taint nodes master node-role.kubernetes.io/master=:PreferNoSchedule
//待所有 Node 的更新操作都完成后,再去除污點
kubectl taint nodes node01 check=mycheck:NoExecute-
二、Pod啟動階段(相位 phase)
2.1 pod啟動過程
1.調度到某台 node 上。kubernetes 根據一定的優先級算法選擇一台 node 節點將其作為 Pod 運行的 node
2.拉取鏡像
3.掛載存儲配置等
4.運行起來。如果有健康檢查,會根據檢查的結果來設置其狀態
2.2 phase的狀態
●Pending:表示APIServer創建了Pod資源對象並已經存入了etcd中,但是它並未被調度完成(比如還沒有調度到某台node上),或者仍然處於從倉庫下載鏡像的過程中。
●Running:Pod已經被調度到某節點之上,並且Pod中所有容器都已經被kubelet創建。至少有一個容器正在運行,或者正處於啟動或者重啟狀態(也就是說Running狀態下的Pod不一定能被正常訪問)。
●Succeeded:有些pod不是長久運行的,比如job、cronjob,一段時間后Pod中的所有容器都被成功終止,並且不會再重啟。需要反饋任務執行的結果。
●Failed:Pod中的所有容器都已終止了,並且至少有一個容器是因為失敗終止。也就是說,容器以非0狀態退出或者被系統終止,比如 command 寫的有問題。
●Unknown:因為某些原因無法取得 Pod 的狀態,通常是因為與 Pod 所在主機通信失敗
2.3 故障排除步驟
//查看Pod事件
kubectl describe TYPE NAME_PREFIX
//查看Pod日志(Failed狀態下)
kubectl logs <POD_NAME> [-c Container_NAME]
//進入Pod(狀態為running,但是服務沒有提供)
kubectl exec –it <POD_NAME> bash
//查看集群信息
kubectl get nodes
//發現集群狀態正常
kubectl cluster-info
//查看kubelet日志發現
journalctl -xefu kubelet
2.4 對節點執行維護操作:刪除節點上的pod數據
2.4.1 將Node標記為不可調度的狀態
kubectl get nodes
//將 Node 標記為不可調度的狀態,這樣就不會讓新創建的 Pod 在此 Node 上運行
kubectl cordon <NODE_NAME> #該node將會變為SchedulingDisabled狀態
kubectl cordon node01
kubectl get nodes
2.4.2 用drain刪除pod數據
//kubectl drain 可以讓 Node 節點開始釋放所有 pod,並且不接收新的 pod 進程。drain 本意排水,意思是將出問題的 Node 下的 Pod 轉移到其它 Node 下運行
==========================================================
kubectl drain node01 --ignore-daemonsets --delete-local-data --force
==========================================================
--ignore-daemonsets:無視 DaemonSet 管理下的 Pod。
--delete-local-data:如果有 mount local volume 的 pod,會強制殺掉該 pod。
--force:強制釋放不是控制器管理的 Pod,例如 kube-proxy。
注:執行 drain 命令,會自動做了兩件事情:
(1)設定此 node 為不可調度狀態(cordon)
(2)evict(驅逐)了 Pod
2.4.3 將Node標記為可調度的狀態
//kubectl uncordon 將 Node 標記為可調度的狀態
kubectl uncordon <NODE_NAME>
kubectl uncordon node01
kubectl get nodes
三、存儲卷
3.1 emptyDir存儲卷
當pod被分配給節點時,首先創建emptyDir卷,並且只要該Pod在該節點上運行,該卷就會存在。正如卷的名字所述,它最初是空的。Pod中的容器可以讀取和寫入emptyDir卷中的相同文件,盡管該卷可以掛載到每個容器中的相同或不同路徑上。當出於任何原因從節點中刪除 pod時,emptyDir中的數據將被永久刪除
vim demo3.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx1
image: nginx
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
- name: nginx2
image: nginx
volumeMounts:
- name: html
mountPath: /data/
command: ['/bin/bash','-c','while true;do echo $(date) >> /data/index.html;sleep 10;done']
volumes:
- name: html
emptyDir: {}
==========================================================
kubectl apply -f demo3.yaml
kubectl get pods -o wide
kubectl exec -it nginx -c nginx2 sh #進去nginx2容器
cat /data/index.html
kubectl exec -it nginx -c nginx1 sh #進去nginx1容器
cat /usr/share/nginx/html/index.html
3.2 hostPath存儲卷
hostpath卷將 node節點的文件系統中的文件或目錄掛載到集群中。hostPath可以實現持久存儲,但是在node節點故障時,也會導致數據的丟失
1.vim demo4.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: nginx222
labels:
app: nginx222
spec:
containers:
- name: nginx1
image: nginx
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html ##使用的存儲卷名稱,如果跟下面volume字段name值相同,則表示使用volume的這個存儲卷
mountPath: /usr/share/nginx/html/ ##掛載至容器中哪個目錄
readOnly: false #讀寫掛載方式,默認為讀寫模式false
volumes:
- name: html #存儲卷名稱
hostPath:
path: /data/pod/volume #在宿主機上目錄的路徑
type: DirectoryOrCreate #定義類型,這表示如果宿主機沒有此目錄則會自動創建
==========================================================
2.kubectl apply -f demo4.yaml
3.查看pod在哪個node節點創建,可以用ip訪問測試
kubectl get pods -o wide
4.在node節點上自動創建的目錄中寫入內容
echo 'woshiwuyifan' > /data/pod/volume/index.html
5.訪問測試
curl http://10.244.2.70
6.主節點寫入內容測試共享
kubectl exec -it nginx222 -c nginx1 sh #進入容器
echo 'woshigutianle' >> /usr/share/nginx/html/index.html
再退出容器測試node02節點:curl http://10.244.2.70
3.3 nfs共享存儲卷
3.3.1 另起服務器nfs01節點
1.設置主機名
hostnamectl set-hostname nfs01
su
2.關閉防火牆和安全功能
systemctl stop firewalld
setenforce 0
3.創建共享目錄並給權限
mkdir -p /data/volume
chmod 777 /data/volume
4.安裝nfs,並配置nfs服務
yum install -y rpcbind nfs-utils
vim /etc/exports
/data/volume 192.168.80.0/24(rw,sync,no_root_squash)
5.啟動nfs服務並查看本機共享目錄
systemctl start rpcbind
systemctl start nfs
showmount -e
6.在共享目錄寫入網頁文件
echo 'woshizhangjiahui' > /data/volume/index.html
3.3.2 在master節點和node節點配置映射
echo '192.168.80.14 nfs01' >> /etc/hosts
3.3.3 主節點操作
vim demo5.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: nginx333
labels:
app: nginx222
spec:
containers:
- name: nginx1
image: nginx
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html ##使用的存儲卷名稱,如果跟下面volume字段name值相同,則表示使用volume的這個存儲卷
mountPath: /usr/share/nginx/html/ ##掛載至容器中哪個目錄
readOnly: false #讀寫掛載方式,默認為讀寫模式false
volumes:
- name: html #存儲卷名稱
nfs:
path: /data/volume #在宿主機上目錄的路徑
server: nfs01
==========================================================
kubectl apply -f demo5.yaml
kubectl get pods -o wide
curl http://10.244.2.71 #調度的node節點的ip
3.3.4 在nfs服務器額外寫網頁文件
nfs服務器:echo 'woshi111' >> /data/volume/index.html
主服務器:curl http://10.244.2.71
kubectl exec -it nginx333 -c nginx1 sh