【Kubernetes系列】第2篇 基礎概念介紹(上)
- 2019 年 10 月 6 日
- 筆記

1 Pod – 實例
Pod是一組緊密關聯的容器集合,支援多個容器在一個Pod中共享網路和文件系統,可以通過進程間通訊和文件共享這種簡單高效的方式完成服務,是Kubernetes調度的基本單位。Pod的設計理念是 每個Pod都有一個唯一的IP Pod具有如下特徵:
- 包含多個共享IPC、Network和UTC namespace的容器,可直接通過localhost通訊
- 所有Pod內容器都可以訪問共享的Volume,可以訪問共享數據
- 優雅終止:Pod刪除的時候先給其內的進程發送SIGTERM,等待一段時間(grace period)後才強制停止依然還在運行的進程
- 特權容器(通過SecurityContext配置)具有改變系統配置的許可權(在網路插件中大量應用)
- 支援三種重啟策略(restartPolicy),分別是:Always、OnFailure、Never
- 支援三種鏡像拉取策略(imagePullPolicy),分別是:Always、Never、IfNotPresent
- 資源限制,Kubernetes通過CGroup限制容器的CPU以及記憶體等資源,可以設置request以及limit值
- 健康檢查,提供兩種健康檢查探針,分別是livenessProbe和redinessProbe,前者用於探測容器是否存活,如果探測失敗,則根據重啟策略進行重啟操作,後者用於檢查容器狀態是否正常,如果檢查容器狀態不正常,則請求不會到達該Pod
- Init container在所有容器運行之前執行,常用來初始化配置
- 容器生命周期鉤子函數,用於監聽容器生命周期的特定事件,並在事件發生時執行已註冊的回調函數,支援兩種鉤子函數:postStart和preStop,前者是在容器啟動後執行,後者是在容器停止前執行
2 Namespace – 命名空間
Namespace(命名空間)是對一組資源和對象的抽象集合,比如可以用來將系統內部的對象劃分為不同的項目組或者用戶組。常見的pod、service、replicaSet和deployment等都是屬於某一個namespace的(默認是default),而node, persistentVolumes等則不屬於任何namespace。 常用namespace操作:
# 查詢所有namespaces kubectl get namespace # 創建namespace kubectl create namespace ns-name # 刪除namespace kubectl delete namespace ns-name
刪除命名空間時,需注意以下幾點:
- 刪除一個namespace會自動刪除所有屬於該namespace的資源。
- default 和 kube-system 命名空間不可刪除。
- PersistentVolumes是不屬於任何namespace的,但PersistentVolumeClaim是屬於某個特定namespace的。
Events是否屬於namespace取決於產生events的對象。
3 Node 節點
Node是Pod真正運行的主機,可以是物理機也可以是虛擬機。Node本質上不是Kubernetes來創建的, Kubernetes只是管理Node上的資源。為了管理Pod,每個Node節點上至少需要運行container runtime(Docker)、kubelet和kube-proxy服務。 常用node操作:
# 查詢所有node kubectl get nodes # 將node標誌為不可調度 kubectl cordon $nodename # 將node標誌為可調度 kubectl uncordon $nodename
taint(污點) 使用kubectl taint命令可以給某個Node節點設置污點,Node被設置上污點之後就和Pod之間存在了一種相斥的關係,可以讓Node拒絕Pod的調度執行,甚至將Node已經存在的Pod驅逐出去。每個污點的組成:`key=value:effect`,當前taint effect支援如下三個選項:
- NoSchedule:表示k8s將不會將Pod調度到具有該污點的Node上
- PreferNoSchedule:表示k8s將盡量避免將Pod調度到具有該污點的Node上
- NoExecute:表示k8s將不會將Pod調度到具有該污點的Node上,同時會將Node上已經存在的Pod驅逐出去
常用命令如下:
# 為節點node0設置不可調度污點 kubectl taint node node0 key1=value1:NoShedule # 將node0上key值為key1的污點移除 kubectl taint node node0 key- # 為kube-master節點設置不可調度污點 kubectl taint node node1 node-role.kubernetes.io/master=:NoSchedule # 為kube-master節點設置盡量不可調度污點 kubectl taint node node1 node-role.kubernetes.io/master=PreferNoSchedule
容忍(Tolerations) 設置了污點的Node將根據taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之間產生互斥的關係,Pod將在一定程度上不會被調度到Node上。 但我們可以在Pod上設置容忍(Toleration),意思是設置了容忍的Pod將可以容忍污點的存在,可以被調度到存在污點的Node上。
4 Service 服務
Service是對一組提供相同功能的Pods的抽象,並為他們提供一個統一的入口,藉助 Service 應用可以方便的實現服務發現與負載均衡,並實現應用的零宕機升級。 Service通過標籤(label)來選取後端Pod,一般配合ReplicaSet或者Deployment來保證後端容器的正常運行。 service 有如下四種類型,默認是ClusterIP:
- ClusterIP: 默認類型,自動分配一個僅集群內部可以訪問的虛擬IP
- NodePort: 在ClusterIP基礎上為Service在每台機器上綁定一個埠,這樣就可以通過 `NodeIP:NodePort` 來訪問該服務
- LoadBalancer: 在NodePort的基礎上,藉助cloud provider創建一個外部的負載均衡器,並將請求轉發到 NodeIP:NodePort
- ExternalName: 將服務通過DNS CNAME記錄方式轉發到指定的域名
另外,也可以將已有的服務以Service的形式加入到Kubernetes集群中來,只需要在創建 Service 的時候不指定Label selector,而是在Service創建好後手動為其添加endpoint。
5 Volume 存儲卷
默認情況下容器的數據是非持久化的,容器消亡以後數據也會跟著丟失,所以Docker提供了Volume機制以便將數據持久化存儲。Kubernetes提供了更強大的Volume機制和插件,解決了容器數據持久化以及容器間共享數據的問題。 Kubernetes存儲卷的生命周期與Pod綁定
- 容器掛掉後Kubelet再次重啟容器時,Volume的數據依然還在
- Pod刪除時,Volume才會清理。數據是否丟失取決於具體的Volume類型,比如emptyDir的數據會丟失,而PV的數據則不會丟
目前Kubernetes主要支援以下Volume類型:
- emptyDir:Pod存在,emptyDir就會存在,容器掛掉不會引起emptyDir目錄下的數據丟失,但是pod被刪除或者遷移,emptyDir也會被刪除
- hostPath:hostPath允許掛載Node上的文件系統到Pod裡面去
- NFS(Network File System):網路文件系統,Kubernetes中通過簡單地配置就可以掛載NFS到Pod中,而NFS中的數據是可以永久保存的,同時NFS支援同時寫操作。
- glusterfs:同NFS一樣是一種網路文件系統,Kubernetes可以將glusterfs掛載到Pod中,並進行永久保存
- cephfs:一種分散式網路文件系統,可以掛載到Pod中,並進行永久保存
- subpath:Pod的多個容器使用同一個Volume時,會經常用到
- secret:密鑰管理,可以將敏感資訊進行加密之後保存並掛載到Pod中
- persistentVolumeClaim:用於將持久化存儲(PersistentVolume)掛載到Pod中
- …
6 PersistentVolume(PV) 持久化存儲卷
PersistentVolume(PV)是集群之中的一塊網路存儲。跟 Node 一樣,也是集群的資源。PersistentVolume (PV)和PersistentVolumeClaim (PVC)提供了方便的持久化卷: PV提供網路存儲資源,而PVC請求存儲資源並將其掛載到Pod中。 PV的訪問模式(accessModes)有三種:
- ReadWriteOnce(RWO):是最基本的方式,可讀可寫,但只支援被單個Pod掛載。
- ReadOnlyMany(ROX):可以以只讀的方式被多個Pod掛載。
- ReadWriteMany(RWX):這種存儲可以以讀寫的方式被多個Pod共享。
不是每一種存儲都支援這三種方式,像共享方式,目前支援的還比較少,比較常用的是 NFS。在PVC綁定PV時通常根據兩個條件來綁定,一個是存儲的大小,另一個就是 訪問模式。 PV的回收策略(persistentVolumeReclaimPolicy)也有三種
- Retain,不清理保留Volume(需要手動清理)
- Recycle,刪除數據,即 rm -rf /thevolume/* (只有NFS和HostPath支援)
- Delete,刪除存儲資源
7 Deployment 無狀態應用
一般情況下我們不需要手動創建Pod實例,而是採用更高一層的抽象或定義來管理Pod,針對無狀態類型的應用,Kubernetes使用Deloyment的Controller對象與之對應。其典型的應用場景包括:
- 定義Deployment來創建Pod和ReplicaSet
- 滾動升級和回滾應用
- 擴容和縮容
- 暫停和繼續Deployment
常用的操作命令如下:
# 生成一個Deployment對象 kubectl run www --image=10.0.0.183:5000/hanker/www:0.0.1 --port=8080 # 查找Deployment kubectl get deployment --all-namespaces # 查看某個Deployment kubectl describe deployment www # 編輯Deployment定義 kubectl edit deployment www # 刪除某Deployment kubectl delete deployment www # 擴縮容操作,即修改Deployment下的Pod實例個數 kubectl scale deployment/www --replicas=2 # 更新鏡像 kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1 # 回滾操作 kubectl rollout undo deployment/nginx-deployment # 查看回滾進度 kubectl rollout status deployment/nginx-deployment # 啟用水平伸縮(HPA - horizontal pod autoscaling),設置最小、最大實例數量以及目標cpu使用率 kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80 # 暫停更新Deployment kubectl rollout pause deployment/nginx-deployment # 恢復更新Deployment kubectl rollout resume deploy nginx
更新策略 `.spec.strategy` 指新的Pod替換舊的Pod的策略,有以下兩種類型
- `RollingUpdate` 滾動升級,可以保證應用在升級期間,對外正常提供服務。
- `Recreate` 重建策略,在創建出新的Pod之前會先殺掉所有已存在的Pod。
Deployment和ReplicaSet兩者之間的關係
- 使用Deployment來創建ReplicaSet。ReplicaSet在後台創建pod,檢查啟動狀態,看它是成功還是失敗。
- 當執行更新操作時,會創建一個新的ReplicaSet,Deployment會按照控制的速率將pod從舊的ReplicaSet移 動到新的ReplicaSet中。
8 StatefulSet 有狀態應用
Deployments和ReplicaSets是為無狀態服務設計的,那麼StatefulSet則是為了有狀態服務而設計,其應用場景包括:
- 穩定的持久化存儲,即Pod重新調度後還是能訪問到相同的持久化數據,基於PVC來實現
- 穩定的網路標誌,即Pod重新調度後其PodName和HostName不變,基於Headless Service(即沒有Cluster IP的Service)來實現
- 有序部署,有序擴展,即Pod是有順序的,在部署或者擴展的時候要依據定義的順序依次進行操作(即從0到N-1,在下一個Pod運行之前所有之前的Pod必須都是Running和Ready狀態),基於init containers來實現
- 有序收縮,有序刪除(即從N-1到0)
支援兩種更新策略:
- OnDelete:當`.spec.template`更新時,並不立即刪除舊的Pod,而是等待用戶手動刪除這些舊Pod後自動創建新Pod。這是默認的更新策略,兼容v1.6版本的行為
- RollingUpdate:當 `.spec.template` 更新時,自動刪除舊的Pod並創建新Pod替換。在更新時這些Pod是按逆序的方式進行,依次刪除、創建並等待Pod變成Ready狀態才進行下一個Pod的更新。