工作负载是在Kubernetes上运行的应用程序,主要功能是对pod进行管理。包括以下几类:
- 无状态工作负载
无状态工作负载管理的pod是相互等价的,需要的时候可以互相替换。包括Deployment
、ReplicaSet
、ReplicationController
。
- 有状态工作负载
有状态的工作负载为每个pod维护了一个唯一的ID,能够保证pod的顺序和唯一性,每个pod是不可替代的。可使用持久存储来保存服务产生的状态,如StatefulSet
。
- 守护进程工作负载
守护进程工作负载如DaemonSet
,管理节点上运行的守护进程。
- 批处理工作负载
批处理工作负载如Job
,CronJob
,用于处理一次性或周期性任务。
本文将按顺序对这几种工作负载进行介绍。
Deployments
Deployment控制器根据Deployment中的目标状态来创建和修改目标,使其达到期望状态。
创建Deployment
下面是一个Deployment示例,其中创建了一个ReplicaSet,负载启动三个运行nginx的pod:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
在该例中,创建了名为nginx-deployment
的无状态工作负载Deployment,该Deployment会创建3个pod,每个pod中运行了一个nginx容器。
selector
字段定义了Deployment如何查找要管理的pods,这里通过标签进行匹配。
通过以下命令来创建Deployment:
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
运行kubectl get deployments
检查Deployment是否已创建好。要查看Deployment创建的ReplicaSet,可以使用命令kubectl get rs
。
注意ReplicaSet的名称始终被格式化为
[Deployment名称]-[随机字符串]
要查看每个pod自动生成的标签,可以运行以下命令:
kubectl get pods --show-labels
你必须在Deployment中指定适当的选择符和pod模板标签(如
app:nginx
)。标签或选择符不要与其他控制器(包括Deployment和StatefulSet)相同。虽然Kubernetes本身不限制这样做,但如果多个控制器具有相同的选择符,可能在执行某些操作时发生冲突。
更新Deployment
当Deployment的pod模板(即.spec.template
)发生改变时,例如模板的标签或容器镜像被更新,才会触发Deployment上线,其他更新不会出触发上线,如Deployment执行扩缩容的操作。
下面来更新容器镜像,可以使用如下命令:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
或者
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
当然,也可以直接用edit命令来编辑yaml文件:
kubectl edit deployment/nginx-deployment
注意,负载类型后面使用斜杠和空格都是可以的。
查看上线状态:kubectl rollout status deployment nginx-deployment
会显示出deployment的上线状态:deployment "nginx-deployment" successfully rolled out
通过kubectl get rs
查看ReplicaSet,结果类似于:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 6s
nginx-deployment-2035384211 0 0 0 36s
可以看出Deployment创建了新的ReplicaSet并将其扩容到3个副本,同时旧的ReplicaSet缩容到0个副本。通过此方式完成了pod的更新操作。
查看Deployment的信息:
kubectl describe deployment nginx-deployment
在描述信息的events中可以看到以下信息:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3
Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1
Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2
Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3
Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
可以看出,当deployment首次创建时,它创建了一个ReplicaSet并扩容到3个pod。更新deployment时,它创建了一个新的ReplicaSet并将其扩容到1个pod,等待其就绪;然后将旧ReplicaSet缩容到2,同时将新的ReplicaSet扩容到2。然后使用相同的滚动更新策略继续对ReplicaSet进行扩缩容。最终新的ReplicaSet扩容到3,旧的ReplicaSet缩容到0。
在整个过程中,可用的pod数量始终保持在3-4之间。这是因为默认的滚动更新策略导致的。在上面describe deployment得到的结果中可以看到这样一行:
RollingUpdateStrategy: 25% max unavailable, 25% max surge
表示在pod滚动更新过程中,最大不可用的pod数量不能超过25%,最大增加的pod数量不可超过25%。如果没有显式指定滚动更新策略,25%就是默认的值。这种更新策略可以使得服务在上线升级的时候平滑发布。
注意,对新的ReplicaSet进行扩容和对旧的ReplicaSet进行缩容并不一定有先后顺序,可以同时进行。只需要保证可用的pod数量不低于指定值(默认为:期望值x75%),总的pod数量不高于指定值(默认为:期望值x125%)。
翻转
上面介绍的deployment的更新是在原有的pod都启动完成之后的更新,如果当deployment正在上线时被更新呢?在这种情况下,deployment会针对更新创建一个新的ReplicaSet并开始对其扩容,之前正在被扩容的ReplicaSet会被添加到旧的ReplicaSets列表并开始缩容。
更改标签选择符
通常不建议修改标签选择符,如果确实要更新,则必须要了解这个过程可能发生的所有事情。
在API版本
apps/v1
中,deployment的标签选择符在创建后是不可变的。
更新选择符需要同步更新deployment规约中的pod模板标签,这会导致deployment重新上线,并创建新的ReplicaSet,而原来创建的ReplicaSet和Pod将不会被筛选到,也就是说,旧ReplicaSet会被孤立。
回滚Deployment
默认情况下,Deployment的所有上线记录都保留在系统中以便随时回滚。
Deployment被触发上线时,系统会创建Deployment的新的修订版本。这意味着仅当deployment的pod模板发生变更时,才会创建新修订版本,其他更新(如扩缩容)不会创建修订版本。这是为了方便同时执行手动缩放或自动缩放。换句话说,当你回滚到较早的修订版本时,只有deployment的pod模板部分会被回滚。
假如你在某次更新deployment时出现问题需要回滚,首先检查deployment的更新记录:
kubectl rollout history deployment nginx-deployment
输出结果类似于:
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
3 <none>
4 <none>
注意,修订历史保存数量可以用
spec.revisionHistoryLimit
指定,默认为10。
这里的版本是3和4,更新原因是空的。通过describe命令查看deployment有如下信息:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "4"
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx-deployment","namespace":"default"},"spec":{"replicas":3,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx","ports":[{"containerPort":80}]}]}}}}
...
在metadata
注解下保存了修订版本号和上次更新的配置。如果在更新deployment时在metadata
注解中添加kubernetes.io/change-cause
,则更新记录中除了版本号外,还会显示添加的变更原因。
要查看修订历史的详细信息,只要指定修订版本号即可:
kubectl rollout history deployment nginx-deployment --revision=3
假设现在想回滚到上一个版本,即revision=3,执行以下命令:
kubectl rollout undo deployment nginx-deployment --to-revision=3
输出类似于:
deployment.apps/nginx-deployment
如果不指定版本号,则默认回退到上一个版本
缩放Deployment
你可以使用如下指令缩放deployment:
kubectl scale deployment nginx-deployment --repllicas=10
假设集群开启了pod的水平自动缩放,则可以通过如下命令基于CPU利用率来设置自动缩放:
kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
暂停、恢复deployment的上线
如果你要更新deployment的多个配置,建议使用edit命令一次更新完,然后上线deployment。
但是如果分多次进行deployment的更新,又不想触发不必要的deployment的上线操作,则可以在更新之前暂停deployment上线,确定全部更新完成后再恢复上线。
暂停上线命令如下:
kubectl rollout pause deployment nginx-deployment
接着更新deployment镜像:
kubectl set image deployment nginx-deployment nginx=nginx:1.16.1
执行describe deployment命令,可以看到如下信息:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing Unknown DeploymentPaused
OldReplicaSets: nginx-deployment-6595874d85 (3/3 replicas created)
NewReplicaSet: nginx-deployment-66b957f9d (0/0 replicas created)
状况栏显示上线暂停,而且有新的ReplicaSet,但没有扩容。继续执行其他更新操作,当所有更新都完成后,只要恢复deployment的上线就可以应用所有这些更新:
kubectl rollout resume deployment nginx-deployment
此时再次查看deployment,发现新ReplicaSet扩容到期望值,旧ReplicaSet缩容到0。
注意,处于暂停状态的Deployment不能回滚,除非先恢复其执行状态。
Deployment状态
Deployment的生命周期中会有许多状态,如Processing、Complete或Failed。
当deployment执行以下任务时,其状态是Processing的:
- 创建新的ReplicaSet
- 为新的ReplicaSet扩容
- 为旧的ReplicaSet缩容
- 新的pods已经就绪或者可用(持续运行
minReadySeconds
时间)
.sepc.minReadySeconds
表示新创建的pod被视为可用时需要持续就绪的时间,默认为0。
此时,deployment的控制器会向其conditions
中添加如下信息:
Progressing True NewReplicaSetCreated |FoundNewReplicaSet | ReplicaSetUpdated
当deployment的ReplicaSet副本均已更新到指定的最新版本时,其状态是Complete的。
此时起conditions
为:
Processing True NewReplicaSetAvailable
如果Deployment在尝试部署其最新的ReplicaSet时受挫,且超过指定的超时时间,则其状态就是Failed
的。部署超时时间是通过参数spec.procgressDeadlineSeconds
指定的,单位是秒,默认为600s。
执行以下命令,将超时时间更改为60s:
kubectl patch deployment nginx-deployment -p '{"spec": {"progressDeadlineSeconds":60}}'
然后更新deployment的镜像,选择一个不存在的镜像,如1.22.9:
kubectl set image deployment nginx-deployment nginx=nginx:1.22.9
等待60s后,describe deployment的到如下信息:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
OldReplicaSets: nginx-deployment-66b957f9d (3/3 replicas created)
NewReplicaSet: nginx-deployment-6cd7c48f65 (1/1 replicas created)
除了报告
Reason=ProgressDeadlineExceeded
外,kubernetes对已停止的deployment不执行任何操作。可以手动将deployment回滚到以前的版本。