全部的 K8S学习笔记总目录 ,请点击查看。
以下主要介绍 k8s 中的 deployment ,deployment 是 k8s 中最常用的资源类型之一,用于管理 pod 的生命周期。
改造之前的 pod 之前我们使用 pod 来管理应用,但是 pod 有如下缺点:
pod 无法实现滚动升级
pod 无法实现回滚
pod 无法实现自动伸缩
pod 无法实现自动恢复
pod 无法实现自动发布
pod 无法实现自动扩容
pod 无法实现自动缩容
pod 无法实现自动重启
为了解决这些问题,我们需要使用 deployment 来管理应用。
创建 deployment 文件 首先创建数据的文件,将其改造为 deployment 方式 deploy-mysql.yaml
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 apiVersion: apps/v1 kind: Deployment metadata: name: mysql namespace: test spec: replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: hostNetwork: true volumes: - name: mysql-data hostPath: path: /opt/mysql/data nodeSelector: component: mysql containers: - name: mysql image: mariadb:11.1 args: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci ports: - containerPort: 3306 env: - name: MYSQL_USER valueFrom: secretKeyRef: name: myblog-secret key: MYSQL_USER - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: myblog-secret key: MYSQL_PASSWD - name: MYSQL_DATABASE valueFrom: configMapKeyRef: name: myblog key: MYSQL_DATABASE volumeMounts: - name: mysql-data mountPath: /var/lib/mysql
之后创建业务应用的 deployment 文件 deploy-myblog.yaml
,为了更好的实验,我把 blog 的应用换成 wordpress 了.
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 apiVersion: apps/v1 kind: Deployment metadata: name: myblog namespace: test spec: replicas: 1 selector: matchLabels: app: myblog template: metadata: labels: app: myblog spec: containers: - name: myblog image: wordpress:php8.2-alpine imagePullPolicy: IfNotPresent env: - name: WORDPRESS_DB_HOST valueFrom: configMapKeyRef: name: myblog key: MYSQL_HOST - name: WORDPRESS_DB_USER valueFrom: secretKeyRef: name: myblog-secret key: MYSQL_USER - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: myblog-secret key: MYSQL_PASSWD - name: WORDPRESS_DB_NAME valueFrom: configMapKeyRef: name: myblog key: MYSQL_DATABASE ports: - containerPort: 80
创建 deployment 1 2 $ kubectl apply -f deploy-mysql.yaml $ kubectl apply -f deploy-myblog.yaml
查看 deployment 此时可以通过 kubectl get deploy -n test
查看 deployment 的状态: 1 2 3 4 $ kubectl get deploy -n test NAME READY UP-TO-DATE AVAILABLE AGE mysql 1/1 1 1 2m myblog 1/1 1 1 2m
NAME
列出了集群中 Deployments 的名称。
READY
显示当前正在运行的副本数/期望的副本数。
UP-TO-DATE
显示已更新以实现期望状态的副本数。
AVAILABLE
显示应用程序可供用户使用的副本数。
AGE
显示应用程序运行的时间量。
查看 pod 1 2 3 4 $ kubectl get po -n test NAME READY STATUS RESTARTS AGE mysql-7b4f8f8d5f-4j4q4 1/1 Running 0 2m myblog-7c96c9f76b-qbbg7 1/1 Running 0 2m
查看 replicaSet 1 2 3 4 $ kubectl get rs -n test NAME DESIRED CURRENT READY AGE mysql-7b4f8f8d5f 1 1 1 2m myblog-7c96c9f76b 1 1 1 2m
查看 deployment 详细信息 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 28 29 30 31 32 33 34 35 36 37 38 39 40 $ kubectl describe deploy mysql -n test Name: mysql Namespace: test CreationTimestamp: Fri, 03 Sep 2021 23:59:15 +0800 Labels: <none> Annotations: deployment.kubernetes.io/revision: 1 Selector: app=mysql Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=mysql Containers: mysql: Image: mariadb:11.1 Port: 3306/TCP Host Port: 0/TCP Args: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci Environment: MYSQL_USER: <set to the key 'MYSQL_USER' in secret 'myblog-secret' > Optional: false MYSQL_ROOT_PASSWORD: <set to the key 'MYSQL_PASSWD' in secret 'myblog-secret' > Optional: false MYSQL_DATABASE: <set to the key 'MYSQL_DATABASE' of config map 'myblog' > Optional: false Mounts: /var/lib/mysql from mysql-data (rw) Volumes: mysql-data: Type: HostPath (bare host directory volume) Path: /opt/mysql/data HostPathType: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: mysql-7f97cb6cc9 (1/1 replicas created) Events: <none>
副本保障机制 controller实时检测pod状态,并保障副本数一直处于期望的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ kubectl -n test delete pod myblog-7c96c9f76b-qbbg7 $ kubectl get pods -o wide -n test $ kubectl -n test scale deploy myblog --replicas=2 deployment.extensions/myblog scaled $ kubectl get pods -o wide -n test NAME READY STATUS RESTARTS AGE mysql-7b4f8f8d5f-4j4q4 1/1 Running 0 3m18s myblog-7c96c9f76b-qbbg7 1/1 Running 0 11m myblog-7c96c9f76b-s6brm 1/1 Running 0 3m18s
Pod驱逐策略 K8S 有个特色功能叫 pod eviction,它在某些场景下如节点 NotReady,或者资源不足时,把 pod 驱逐至其它节点,这也是出于业务保护的角度去考虑的。
Kube-controller-manager: 周期性检查所有节点状态,当节点处于 NotReady 状态超过一段时间后,驱逐该节点上所有 pod。
pod-eviction-timeout
:NotReady 状态节点超过该时间后,执行驱逐,默认 5 min,适用于k8s 1.13版本之前
1.13版本后,集群开启 TaintBasedEvictions 与TaintNodesByCondition
功能,即taint-based-evictions ,即节点若失联或者出现各种异常情况,k8s会自动为node打上污点,同时为pod默认添加如下容忍设置:
1 2 3 4 5 6 7 8 9 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300
即各pod可以独立设置驱逐容忍时间。
Kubelet: 周期性检查本节点资源,当资源不足时,按照优先级驱逐部分 pod
memory.available
:节点可用内存
nodefs.available
:节点根盘可用存储空间
nodefs.inodesFree
:节点inodes可用数量
imagefs.available
:镜像存储盘的可用空间
imagefs.inodesFree
:镜像存储盘的inodes可用数量
服务更新方法 修改服务,重新打tag模拟服务更新至下一个版本。
更新方式:
修改yaml文件,使用kubectl -n test apply -f deploy-myblog.yaml
来应用更新
kubectl -n test edit deploy myblog
在线更新
kubectl -n test set image deploy myblog myblog=wordpress:php8.2 --record
更新策略 1 2 3 4 5 6 7 8 9 10 11 12 13 ... spec: replicas: 2 selector: matchLabels: app: myblog strategy: rollingUpdate: maxSurge: 25 % maxUnavailable: 25 % type: RollingUpdate ...
策略控制:
maxSurge:最大激增数, 指更新过程中, 最多可以比replicas预先设定值多出的pod数量, 可以为固定值或百分比,默认为desired Pods数的25%。计算时向上取整(比如3.4,取4),更新过程中最多会有replicas + maxSurge个pod
maxUnavailable: 指更新过程中, 最多有几个pod处于无法服务状态 , 可以为固定值或百分比,默认为desired Pods数的25%。计算时向下取整(比如3.6,取3)
在Deployment rollout时,需要保证Available(Ready) Pods数不低于 desired pods number - maxUnavailable; 保证所有的非异常状态Pods数不多于 desired pods number + maxSurge 。
以myblog为例,使用默认的策略,更新过程:
maxSurge 25%,2个实例,向上取整,则maxSurge为1,意味着最多可以有2+1=3个Pod,那么此时会新创建1个ReplicaSet,RS-new,把副本数置为1,此时呢,副本控制器就去创建这个新的Pod
同时,maxUnavailable是25%,副本数2*25%,向下取整,则为0,意味着,滚动更新的过程中,不能有少于2个可用的Pod,因此,旧的Replica(RS-old)会先保持不动,等RS-new管理的Pod状态Ready后,此时已经有3个Ready状态的Pod了,那么由于只要保证有2个可用的Pod即可,因此,RS-old的副本数会有2个变成1个,此时,会删掉一个旧的Pod
删掉旧的Pod的时候,由于总的Pod数量又变成2个了,因此,距离最大的3个还有1个Pod可以创建,所以,RS-new把管理的副本数由1改成2,此时又会创建1个新的Pod,等RS-new管理了2个Pod都ready后,那么就可以把RS-old的副本数由1置为0了,这样就完成了滚动更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ kubectl -n test describe deploy myblog ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 11s deployment-controller Scaled up replica set myblog-6cf56fc848 to 1 Normal ScalingReplicaSet 11s deployment-controller Scaled down replica set myblog-6fdcf98f9 to 1 Normal ScalingReplicaSet 11s deployment-controller Scaled up replica set myblog-6cf56fc848 to 2 Normal ScalingReplicaSet 6s deployment-controller Scaled down replica set myblog-6fdcf98f9 to 0 $ kubectl get rs NAME DESIRED CURRENT READY AGE myblog-6cf56fc848 2 2 2 16h myblog-6fdcf98f9 0 0 0 16h
除了滚动更新以外,还有一种策略是Recreate,直接在当前的pod基础上先删后建:
1 2 3 4 ... strategy: type : Recreate ...
我们的mysql服务应该使用Recreate来管理:
1 2 3 4 5 6 7 8 9 10 11 12 13 $ kubectl -n test edit deploy mysql ... selector: matchLabels: app: mysql strategy: type : Recreate template: metadata: creationTimestamp: null labels: app: mysql ...
服务回滚 通过滚动升级的策略可以平滑的升级Deployment,若升级出现问题,需要最快且最好的方式回退到上一次能够提供正常工作的版本。为此K8S提供了回滚机制。
revision :更新应用时,K8S都会记录当前的版本号,即为revision,当升级出现问题时,可通过回滚到某个特定的revision,默认配置下,K8S只会保留最近的几个revision,可以通过Deployment配置文件中的spec.revisionHistoryLimit属性增加revision数量,默认是10。
查看当前:
1 2 $ kubectl -n test rollout history deploy myblog $ kubectl delete -f deploy-myblog.yaml
记录回滚:
1 2 $ kubectl apply -f deploy-myblog.yaml --record $ kubectl -n test set image deploy myblog myblog=wordpress:php8.2 --record=true
查看deployment更新历史:
1 2 3 4 5 $ kubectl -n test rollout history deploy myblog deployment.extensions/myblog REVISION CHANGE-CAUSE 1 kubectl create --filename=deploy-myblog.yaml --record=true 2 kubectl set image deploy myblog myblog=wordpress:php8.2-apache --record=true
回滚到具体的REVISION:
1 2 3 4 5 $ kubectl -n test rollout undo deploy myblog --to-revision=1 deployment.extensions/myblog rolled back curl 10.244.1.150:8002/