目錄
Replication Controller 和 ReplicaSet
標簽與標簽選擇器
無狀態應用管理Deployment
有狀態應用管理StatefulSet
守護進程集DaemonSet
Replication Controller 和 ReplicaSet
RC用來確保Pod副本數達到期望值,這樣可以確保一個或多七個同類Pod總是可用的
如果存在的Pod數量大于設定的值,Replication Controller將終止額外的Pod,如果太少,
Replication Controller將會啟動更多的Pod用于保證達到期望值,與手動創建Pod不同的是,用Replication Controller維護的Pod在失敗、刪除或終止時會自動替換。因此,即使應用程序只需要一個Pod,也應該使用Replication Controller或其他方式管管理。Replication Controller類似于進程管理程序,但是Replication Controller不是監視單個節點上的各個進程,而是監視多個節點上的多個Pod。
創建名為replication.yaml
的文件,內容如下:
apiVersion: v1
kind: ReplicationController
metadata:name: nginx
spec:replicas: 3selector:app: nginxtemplate:metadata:name: nginxlabels:app: nginxspec:containers:- name: nginximage: nginxports:- containerPort: 80
?
- 創建 Replication Controller:執行命令
kubectl apply -f replication.yaml
,創建名為nginx
的 Replication Controller。 - 查看狀態:使用命令
kubectl describe replicationcontrollers nginx
查看其狀態,初始可能顯示pods status: 0 running / 3 waiting / 0 succeeded / 0 failed
,稍后會變為pods status: 3 running / 0 waiting / 0 succeeded / 0 failed
。 - 列出相關 Pod:通過命令
pods=$(kubectl get pods --selector=app=nginx --output=jsonpath={.items[*].metadata.name}) && echo $pods
,可列出該 Replication Controller 管理的 Pod 名稱。 -
ReplicaSet 實驗案例1
- 案例目的:創建一個 ReplicaSet,同樣用于管理 Nginx 應用的 Pod 副本,維持 3 個副本,并展示其標簽選擇器的靈活性。
- 操作步驟:
- 創建配置文件:創建
replicaset.yaml
文件,內容如下: -
apiVersion: apps/v1 kind: ReplicaSet metadata:name: nginx - replicaset spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxports:- containerPort: 80
- 創建 ReplicaSet:執行命令
kubectl apply -f replicaset.yaml
,創建名為nginx - replicaset
的 ReplicaSet。 - 查看狀態:使用
kubectl describe replicaset nginx - replicaset
查看狀態,確認其是否成功創建并維持 3 個 Pod 副本。 - 測試標簽選擇器:可以嘗試修改
matchLabels
中的標簽,或者添加更多標簽選擇條件,如matchExpressions
,然后重新應用配置文件,觀察 Pod 的創建和管理情況。例如,若添加一個tier in (front - end)
的標簽選擇條件,只有符合該條件的 Pod 才會被該 ReplicaSet 管理。
- 創建配置文件:創建
標簽與標簽選擇器
標簽
標簽是用來標識K8S對象的一組附加在其上的鍵值對,通過標簽我我們可以方便地篩選或排除一組對象借鑒資料中的話來講,集群中的應用部署或是批處理的程序部署通常都是多維度的,為了實現對這些對象的管理,往往需要對某一特定維度的對象進行操作,而標簽可可以通過用戶的意愿組織集群中的對象之間的結構,而不需要對集群進行修改在同一個對象之下標簽的Key值必須唯一的。名稱方面,標簽名不得多于63個字符且必須由字母或數字開頭或結尾,可以包含字母、數字、-、、、等字符;標簽前繳是可選的,必須以DNS子域名的方式指定,例如:kubernetes.io,后用/將其與標簽名分隔。通常情請況下,若不使用標簽前綴,那么該標簽的Key將被視為專屬于用戶的,在K8S的系統組件向對象添加標:簽時,必須指定前綴。在標簽值方面,若標簽值不為空,則其長度不得多于63個字符且必須由字母或數字開頭或結尾,可以包含字母、數字、-、等字符。
標簽選擇器
標簽選擇器可以用來選擇一組對象(標簽并不能唯一標識一個對象),APIServer支持兩種標簽選擇器:基于等式的標簽選擇器與基于集合的標簽選器:
基于等式的標簽選擇方式:在這種選擇方式下可以使用=、==、!=三種操作符來進行選擇,前兩個的含義是一樣的,都代表相等,第三種代表不等。選擇條件可以通過,疊加,例如date=day1,name!=build代表選擇date值為day1且name值不為build的對象。
基于集合的標簽選擇方式:這種選擇器可以同時選擇一組對象只。支持的操作符有:in、notin、exists具體的使用方法為:選擇date包含有值為day1、day2、day3的標簽:date in(dayy1,day2,day3選擇name值不為build、pipline的標簽:name notin(build, pipline)
選擇所有包含test的標簽:test基于集合的標簽選擇器也支持使用","分隔以同時疊加選擇,相同意義上的選擇條件在這兩種選擇方式之間是等價的。
標簽等式的標簽選擇器
matchlabels是{key,value}對的映射。matchlabels 映射中中的單個{key,value}等價于
matchexpressions的元素,其鍵字段為"key",運算符為"in",值數組僅包含"value"
matchexpressions是pod選擇器需求的列表。有效的運算符包括in、notin、exists 和doesnotexist.對于in和notin,設置的值必須為非空。matchlabels和mattchexpressions中的所有要求都被放在一起,必須滿足所有這些要求才能匹配。
ReplicaSet
Replicaset(復制集,RS)是支持基于集合的標簽選擇器的下一代Replication Controller,它
主要用于Deployment協調創建、刪除和更新Pod,和Repliication Controller唯一的區別是,ReplicaSet支持標簽選擇器。在實際應用中,雖然Replicasset可以單獨使用,但是一般建議使用Deployment來自動管理Replicaset,除非自定義的Pod不需要更新或有其他編排等
?Pod 標簽示例
apiVersion: v1
kind: Pod
metadata:name: nginx-weblabels:# 應用標識app: nginx # 應用版本version: v1 # 服務層級tier: frontend # 環境類型environment: prod
spec:# 容器配置...
?Service 標簽示例
apiVersion: v1
kind: Service
metadata:name: nginx-servicelabels:# 關聯應用app: nginx # 服務類型service: web
spec:# 服務配置...
創建帶標簽的 Pod
# pod-with-labels.yaml
apiVersion: v1
kind: Pod
metadata:name: frontend-podlabels:app: myapptier: frontendenv: test
spec:containers:- name: nginximage: nginx
無狀態應用管理Deployment
無狀態服務(stateless service)對單次請求的處理,不依賴其他請求,也就是說,處理一次請求所需的全部信息,要么都包含在這個請求里,要么可以從外部獲取到(比如說數據庫),服務器本身不存儲任何信息。這種服務叫做無狀態服務。
無狀態服務:就是沒有特殊狀態的服務,各個請求對于服務器來說統無差別處理,請求自身攜帶了所有服務端所需要的所有參數(服務端自身不存儲跟請求相關的任何數據,不包括數據庫存儲信息)
無狀態服務的優點
數據方面:無狀態服務不會在本地存儲持久化數據.多個實例可以共享享相同的持久化數據
結果方面:多個服務實例對于同一個用戶請求的響應結果是完全一致的
關系方面:這種多服務實例之間是沒有依賴關系
影響方面:在k8s控制器中動態啟停無狀態服務的pod并不會對其它的pod產生影響
示例方面:nginx實例,tomcat實例,web應用
資源方面:相關的k8s資源有:ReplicaSet、ReplicationCointroller、Deployment
創建方式:Deployment被設計用來管理無狀態服務的pod
每個pod完全一致,原因如下:
無狀態服務內的多個Pod創建的順序是沒有順序的
無狀態服務內的多個Pod的名稱是隨機的
pod被重新啟動調度后,它的名稱與IP都會發生變化
無狀態服務內的多個Pod背后是共享存儲的
(8)擴縮容方式:隨機縮容
由于是無狀態服務,所以這些控制器創建的pod序號都是阿隨機值。并且在縮容也是隨機,并不會明縮容某一個pod。因為所有實例得到的返回值都是一樣,所以縮容任何一個pod都可以。無狀態服務不會在本地存儲持久化數據。多個服務實例對于同同一個用戶請求的響應結果是完全一致的。這種多服務實例之間是沒有依賴關系,比如web應用,在k8s控制器中動態啟停無狀態服務的pod并不會對其它的pod產生影響。
Deployment被設計用來管理無狀態服務的pod,每個pod完全一致
無狀態服務內的多個Pod創建的順序是沒有順序的。
無狀態服務內的多個Pod的名稱是隨機的.pod被重新啟動調度后,它的名稱與IP都會發生變化無狀態服務內的多個Pod背后是共享存儲的。
編寫一個名為nginx - deployment.yaml
的文件,內容如下:
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx - deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80
此 YAML 文件定義了一個名為nginx - deployment
的 Deployment,它將創建 3 個 Pod 副本,每個 Pod 運行nginx:1.14.2
鏡像,并暴露 80 端口。
部署 Nginx Deployment
使用以下命令在 Kubernetes 集群中創建 Deployment:
kubectl apply -f nginx - deployment.yaml
3. 查看 Deployment 狀態
使用以下命令查看 Deployment 的詳細信息:
kubectl describe deployment nginx - deployment
也可使用以下命令查看 Deployment 創建的 Pod:
kubectl get pods - l app = nginx
4. 更新 Nginx Deployment
假設要將 Nginx 鏡像更新到新版本nginx:1.20.0
,編輯nginx - deployment.yaml
文件,將image
字段的值修改為nginx:1.20.0
,然后再次應用配置:
kubectl apply -f nginx - deployment.yaml
Kubernetes 會自動執行滾動更新,逐步用新版本的 Pod 替換舊版本的 Pod。
5. 回滾 Deployment
如果更新后出現問題,可使用以下命令回滾到上一個版本:
kubectl rollout undo deployment nginx - deployment
若要回滾到指定版本,先查看 Deployment 的歷史版本:
kubectl rollout history deployment nginx - deployment
然后根據版本號回滾,例如回滾到版本 3:
kubectl rollout undo deployment nginx - deployment --to - revision = 3
6. 擴展和縮減 Deployment
可根據負載情況調整 Pod 的副本數量。例如,將副本數量擴展到 5:
kubectl scale deployment nginx - deployment --replicas = 5
查看 Deployment 狀態,確認副本數已更新:
kubectl get deployment nginx - deployment
若要縮減副本數,如減至 2 個,執行:
kubectl scale deployment nginx - deployment --replicas = 2
7. 刪除 Deployment
當不再需要該 Deployment 時,可使用以下命令將其刪除:
kubectl delete deployment nginx - deployment
這會刪除 Deployment 及其管理的所有 Pod。
有狀態應用管理StatefulSet
StatefulSet(有狀態集,縮寫為sts)常用于部署有狀態的且需要有序啟動的應用程序。比如在生產環境中,可以部署Elasticsearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集
群、Kafka集群和Zookeeper集群等。
一個StatefulSet管理著基于相同容器規范的Pod。與Deployment不同的是,Statefulset為每個Pod維護了一個標識。這些Pod是根據相同規范創建的,但是不可互換,每個Pod都有一個持久的標識符,在重新調度時也會被保留。
有狀態服務的特征
數據方面:有狀態服務需要在本地存儲持久化數據,典型的應用是分布式數據庫
結果方面:實例之間,請求結果可能存在不一致
關系方面:分布式節點實例之間有依賴的拓撲關系,比如主從關關系。
影響方面:如果K8S停止分布式集群中任一實例pod,就可能會導致數據丟失或者集群的crash(崩
示例方面:mysql數據庫、kafka、zookeeper、Redis主從架構
資源方面:statefulSet
創建方式:statefulSet管理Stateful管理有狀態的應用,Pod有如下特征:
唯一性:每個Pod會被分配一個唯一序號.
順序性:Pod啟動,更新,銷毀是按順序進行.
穩定的網絡標識:Pod主機名,DNS地址不會隨著Pod被重新調度而發生變化
穩定的持久化存儲:Pod被重新調度后,仍然能掛載原有的PV,從而保證了數據的完整性和一致性
有狀態服務的應用場景
數據方面:有狀態服務需要在本地存儲持久化數據,典型的應用是分布式數據庫
結果方面:實例之間,請求結果可能存在不一致
關系方面:分布式節點實例之間有依賴的拓撲關系,比如主生從關系
影響方面:如果K8S停止分布式集群中任一實例pod,就可能會導致數據丟失或者集群的crash(崩潰
示例方面:mysql數據庫、kafka、zookeeper、Redis主從架構
資源方面:statefulSet
創建方式:statefulSet管理
Stateful管理有狀態的應用,Pod有如下特征:
唯一性:每個Pod會被分配一個唯一序號.
順序性:Pod啟動,更新,銷毀是按順序進行.
穩定的網絡標識:Pod主機名,DNS地址不會隨著Pod被重新調度而發生變化
穩定的持久化存儲:Pod被重新調度后,仍然能掛載原有的PV,從而保證了數據的完整性和一致性
有狀態服務的應用場景
有狀態的pod是用來運行有狀態應用的,所以其在數據卷上不存儲的數據非常重要,在Statefulset縮容時刪除這個聲明將是災難性的,特別是對于Statefulset來說,縮容就像減少其replicas數值一樣簡單。基于這個原因,當需要釋放特定的持久卷時,需要手動刪除對應的持久卷聲明。有狀態服務需要在本地存儲持久化數據,典型的是分布式數據庫的應用,分布式節點實例之間有依賴
的拓撲關系.比如,主從關系。如果K8S停止分布式集群中任一實例pod,就可能會導致數據丟失或者集群的crash(崩潰)有狀態服務可以說是需要數據存儲功能的服務、或者指多線程類型的服務,隊列等。(mysql數據
庫、kafka、zookeeper等)有狀態服務常常用于實現事務(并不是唯一辦法,下文有另外的方案)。舉一個常見的例子,在商城里購買一件商品。需要經過放入購物車、確認訂單、付款等多個步驟。由于HTTP協議本身是無狀態的,所以為了實現有狀態服務,就需要通過一些額外的方案。比如最常見的session,將用戶挑選的商品(購物車),保存到session中,當付款的時候,再從購物車里取收出商品信息
無狀態服務和有狀態服務的比較無狀態服務
服務不依賴自身的狀態,實例的狀態數據可以維護在內存中。
任何一個請求都可以被任意一個實例處理。
不存儲狀態數據,實例可以水平拓展,通過負載均衡將請求分發到各個節點。
在一個封閉的系統中,只存在一個數據閉環。
通常存在于單體架構的集群中。
有狀態服務
服務本身依賴或者存在局部的狀態數據,這些數據需要自身持久化或者可以通過其他節點恢復。一個請求只能被某個節點(或者同等狀態下的節點)處理。
存儲狀態數據,實例的拓展需要整個系統參與狀態的遷移。
在一個封閉的系統中,存在多個數據閉環,需要考慮這些閉環的數據一致性問題
通常存在于分布式架構中。
首先需要創建一個 StorageClass,為 StatefulSet 提供動態存儲:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: mysql - storage
provisioner: kubernetes.io/aws - ebs # 根據你的集群環境選擇合適的存儲插件
parameters:type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:- debug
將上述內容保存為mysql - storageclass.yaml
,然后執行:
kubectl apply -f mysql - storageclass.yaml
2. 創建 Headless Service
為 StatefulSet 創建一個 Headless Service,為 Pod 提供穩定的網絡標識:
apiVersion: v1
kind: Service
metadata:name: mysql - servicelabels:app: mysql
spec:ports:- port: 3306name: mysqlclusterIP: None # 指定為Headless Serviceselector:app: mysql
保存為mysql - service.yaml
并執行:
kubectl apply -f mysql - service.yaml
3. 創建 StatefulSet
創建一個 StatefulSet 來管理 MySQL 實例:
apiVersion: apps/v1
kind: StatefulSet
metadata:name: mysql - statefulset
spec:serviceName: "mysql - service"replicas: 3selector:matchLabels:app: mysqltemplate:metadata:labels:app: mysqlspec:containers:- name: mysqlimage: mysql:8.0ports:- containerPort: 3306name: mysqlenv:- name: MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name: mysql - secretkey: root - passwordvolumeMounts:- name: mysql - datamountPath: /var/lib/mysqlvolumeClaimTemplates:- metadata:name: mysql - dataspec:accessModes: [ "ReadWriteOnce" ]storageClassName: "mysql - storage"resources:requests:storage: 10Gi
注意,這里引用了一個名為mysql - secret
的 Secret,需要提前創建:
kubectl create secret generic mysql - secret --from - literal = root - password = your - password
將 StatefulSet 配置保存為mysql - statefulset.yaml
并執行:
kubectl apply -f mysql - statefulset.yaml
4. 驗證 StatefulSet
查看 StatefulSet 狀態:
kubectl get statefulset mysql - statefulset
查看創建的 Pod:
kubectl get pods - l app = mysql
你會看到類似以下格式的 Pod 名稱:mysql - statefulset - 0
、mysql - statefulset - 1
、mysql - statefulset - 2
。
查看 PVC 和 PV:
kubectl get pvc
kubectl get pv
5. 連接到 MySQL 實例
可以通過 Pod 名稱連接到特定的 MySQL 實例。例如,連接到mysql - statefulset - 0
:
kubectl exec - it mysql - statefulset - 0 -- mysql - uroot - p
輸入之前設置的密碼your - password
即可登錄。
6. 擴展和縮減 StatefulSet
擴展 MySQL 實例到 5 個:
kubectl scale statefulset mysql - statefulset --replicas = 5
縮減回 3 個:
kubectl scale statefulset mysql - statefulset --replicas = 3
注意,StatefulSet 的縮容是有序的,會從最大索引的 Pod 開始刪除。
7. 更新 StatefulSet
如果需要更新 MySQL 版本,編輯mysql - statefulset.yaml
文件,修改image
字段,然后應用更改:
kubectl apply -f mysql - statefulset.yaml
默認情況下,StatefulSet 使用OnDelete
更新策略,需要手動刪除 Pod 才能觸發更新。也可以將更新策略改為RollingUpdate
:
updateStrategy:type: RollingUpdate
8. 刪除 StatefulSet
刪除 StatefulSet 時,PVC 不會自動刪除,以保護數據:
kubectl delete statefulset mysql - statefulset
如果需要刪除 PVC 和 PV,可執行:
kubectl delete pvc - l app = mysql
守護進程集DaemonSet
什么是Daemonset
有時候我們需要在每個Kubernetes節點或符合條件的節點點上都部署某個應用,那么就可以使用Kubernetes的DaemonSet調度 Pod。DaemonSet確保全部(或符合條件)的節點上運行一個Pod副本。
當有新的節點加入集群時,也會為他們新增一個Pod,當節點從集群中移除時,這些Pod會被回收,刪除DaemonSet將會刪除它創建的所有的Pod。
創建 DaemonSet YAML 文件
編寫一個名為fluentd - daemonset.yaml
的文件,內容如下
apiVersion: apps/v1
kind: DaemonSet
metadata:name: fluentd - loggingnamespace: kube - systemlabels:k8s - app: fluentd - log - collector
spec:selector:matchLabels:name: fluentd - loggingtemplate:metadata:labels:name: fluentd - loggingspec:tolerations:- key: node - role.kubernetes.io/control - planeeffect: NoSchedule- key: node - role.kubernetes.io/mastereffect: NoSchedulecontainers:- name: fluentdimage: fluent/fluentd:v1.14 - debianslimresources:limits:memory: 200Mirequests:cpu: 100mmemory: 200MivolumeMounts:- name: varlogmountPath: /var/log- name: varlibdockercontainersmountPath: /var/lib/docker/containersreadOnly: trueterminationGracePeriodSeconds: 30volumes:- name: varloghostPath:path: /var/log- name: varlibdockercontainershostPath:path: /var/lib/docker/containers
此 YAML 文件定義了一個名為fluentd - logging
的 DaemonSet,它會在每個節點上運行一個 Fluentd 容器,用于收集容器日志
部署 DaemonSet
使用以下命令在 Kubernetes 集群中創建 DaemonSet:
kubectl apply -f fluentd - daemonset.yaml
3. 查看 DaemonSet 狀態
使用以下命令查看 DaemonSet 的詳細信息:
kubectl describe daemonset fluentd - logging - n kube - system
查看已調度的 Pod 數量:
kubectl get daemonset fluentd - logging - n kube - system
輸出類似于:
NAME DESIRED CURRENT READY UP - TO - DATE AVAILABLE NODE SELECTOR AGE
fluentd - logging 3 3 3 3 3 <none> 10m
這里的DESIRED
表示集群中的節點數,CURRENT
和READY
表示實際運行的 Pod 數。
4. 查看運行的 Pod
使用以下命令查看 DaemonSet 創建的 Pod:
kubectl get pods - n kube - system - l name = fluentd - logging
每個 Pod 會在不同的節點上運行,名稱類似于:fluentd - logging - xyz12
。
5. 節點選擇器和容忍度
如果需要將 DaemonSet 限制在特定節點上運行,可以添加nodeSelector
字段。例如,只在標記為storage - node = true
的節點上運行:
spec:template:spec:nodeSelector:storage - node: "true"
DaemonSet 默認會調度到所有節點,包括 master 節點。如果不想在 master 節點上運行,可以添加容忍度(tolerations),如示例中所示。
6. 更新 DaemonSet
如果需要更新 Fluentd 版本,編輯fluentd - daemonset.yaml
文件,修改image
字段,然后再次應用配置:
kubectl apply -f fluentd - daemonset.yaml
Kubernetes 會自動執行滾動更新,逐個替換舊版本的 Pod。
7. 回滾 DaemonSet
如果更新后出現問題,可使用以下命令回滾到上一個版本:
kubectl rollout undo daemonset fluentd - logging - n kube - system
8. 刪除 DaemonSet
當不再需要該 DaemonSet 時,可使用以下命令將其刪除:
kubectl delete daemonset fluentd - logging - n kube - system
這會刪除 DaemonSet 及其管理的所有 Pod。