Kubernetes技术详解-从理论到实践-(5)-控制器-Deployment - 详解
1 Deployment控制器简介
Deployment是Kubernetes的无状态应用控制器,它通过声明式滚动的方式,完成一组完全相同的Pod的创建、升级、回滚、扩缩容,并始终保持期望的副本数量。
核心能力 | 说明 |
---|---|
副本维持 | 通过内部托管的ReplicaSet,确保始终有N个Pod在运行。 |
滚动升级 | 逐个替换旧版本Pod,业务零中断。 |
一键回滚 | 任意时刻回退到先前的版本。 |
水平扩缩 | kubectl scale或HPA实时调整副本数。 |
2 Deployment控制器基础
2.1 一个典型的Deployment资源清单文件
[root@master 5-deployment]# cat nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx-dm
spec:
selector:
matchLabels:
app: nginx-dm
replicas: 3
template:
metadata:
labels:
app: nginx-dm
spec:
containers:
- name: nginx
image: nginx:1.27.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
这个清单文件的含义是,在集群里持续保持3个nginx:1.27.3 Pod运行,并支持滚动升级/回滚。
各字段的具体含义如下:
字段 | 含义 |
---|---|
apiVersion: apps/v1 | 使用apps/v1 API版本。 |
kind: Deployment | 资源类型是Deployment。 |
metadata.name: nginx-deploy | Deployment本身的名字。 |
metadata.labels.app: nginx-dm | 给 Deployment打标签,方便被其它对象(如Service)选择。 |
spec.replicas: 3 | 期望副本数=3。 |
spec.selector.matchLabels.app: nginx-dm | 只管理带有app: nginx-dm标签的Pod。 |
template | 用来生成或替换Pod的模板。 |
template.metadata.labels.app: nginx-dm | 新Pod会被自动打上app:nginx-dm标签,与selector保持一致。 |
template.spec.containers[0].name: nginx | 容器名。 |
template.spec.containers[0].image: nginx:1.27.3 | 镜像版本。 |
imagePullPolicy: IfNotPresent | 本地已有镜像就不拉取。 |
ports.containerPort: 80 | 容器监听80端口,供后续Service或集群内访问。 |
2.2 Deployment控制器常见操作
2.2.1 创建名字为nginx-deploy的Deployment控制器
[root@master 5-deployment]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deploy created
2.2.2 查看Deployment控制器
[root@master 5-deployment]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 3/3 3 3 4s
[root@master 5-deployment]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deploy-7c7bbf4cc9 3 3 3 9s
[root@master 5-deployment]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-ch6l8 1/1 Running 0 14s
nginx-deploy-7c7bbf4cc9-hhb7z 1/1 Running 0 14s
nginx-deploy-7c7bbf4cc9-vv7ml 1/1 Running 0 14s
可以看到,nginx-deploy自动创建了一个ReplicaSet控制器和三个Pod,这个pod名有规律,前两个字段是Deployment控制器名,前三个字段是ReplicaSet控制器名。
2.2.3 Deployment控制器扩容
[root@master 5-deployment]# kubectl scale deploy nginx-deploy --replicas=5
deployment.apps/nginx-deploy scaled
[root@master 5-deployment]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 5/5 5 5 48s
[root@master 5-deployment]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-ch6l8 1/1 Running 0 51s
nginx-deploy-7c7bbf4cc9-gg6bh 1/1 Running 0 11s
nginx-deploy-7c7bbf4cc9-hhb7z 1/1 Running 0 51s
nginx-deploy-7c7bbf4cc9-vv7ml 1/1 Running 0 51s
nginx-deploy-7c7bbf4cc9-z2ltq 1/1 Running 0 11s
2.2.4 Deployment控制器缩容
[root@master 5-deployment]# kubectl scale deploy nginx-deploy --replicas=1
deployment.apps/nginx-deploy scaled
[root@master 5-deployment]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 1/1 1 1 67s
[root@master 5-deployment]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-vv7ml 1/1 Running 0 69s
2.2.5 查看Deployment控制器的详情
[root@master 5-deployment]# kubectl describe deploy nginx-deploy
Name: nginx-deploy
Namespace: default
CreationTimestamp: Sat, 19 Jul 2025 21:32:18 +0800
Labels: app=nginx-dm
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx-dm
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=nginx-dm
Containers:
nginx:
Image: nginx:1.27.3
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>Mounts: <none>Volumes: <none>Conditions:Type Status Reason---- ------ ------Progressing True NewReplicaSetAvailableAvailable True MinimumReplicasAvailableOldReplicaSets: <none>NewReplicaSet: nginx-deploy-7c7bbf4cc9 (1/1 replicas created)Events:Type Reason Age From Message---- ------ ---- ---- -------Normal ScalingReplicaSet 91s deployment-controller Scaled up replica set nginx-deploy-7c7bbf4cc9 to 3Normal ScalingReplicaSet 51s deployment-controller Scaled up replica set nginx-deploy-7c7bbf4cc9 to 5 from 3Normal ScalingReplicaSet 28s deployment-controller Scaled down replica set nginx-deploy-7c7bbf4cc9 to 1 from 5
2.2.6 Deployment控制器保持pod副本不增不减
这个是通过自动创建的ReplicaSet实现的。刚才我们把deploy的数量动态缩容为1,现在只有一个pod在运行,删除pod后,可以看到会自动生成一个新的pod。
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-vv7ml 1/1 Running 0 115s
[root@master 5-deployment]# kubectl delete pod nginx-deploy-7c7bbf4cc9-vv7ml
pod "nginx-deploy-7c7bbf4cc9-vv7ml" deleted
[root@master 5-deployment]#
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-g9rp6 1/1 Running 0 5s
2.2.7 Deployment控制器删除
[root@master 5-deployment]# kubectl delete deploy nginx-deploy
deployment.apps "nginx-deploy" deleted
[root@master 5-deployment]# kubectl get pods
No resources found in default namespace.
[root@master 5-deployment]#
3 Deployment升级
3.1 下载新的nginx镜像
下载一个新的nginx镜像,版本为1.27.5(本示例为了演示效果,仅将1.27.3镜像打一个新的tag,用于升级演示)
[root@master 5-deployment]# docker tag nginx:1.27.3 nginx:1.27.5
[root@master 5-deployment]# docker images | grep nginx
nginx 1.27.3 66f8bdd3810c 7 months ago 192MB
nginx 1.27.5 66f8bdd3810c 7 months ago 192MB
3.2 Deployment的三种升级策略
- RollingUpdate策略:默认策略,先创建新的pod,然后逐步将就得pod替换成新的pod。
- Recreate策略:直接删除所有旧的Pod并创建新的Pod来替代它们。该策略会导致一段时间内服务不可用。
- OnDelete策略:手动删除Deployment时,同时删除所有pod。
3.3 示例:RollingUpdate升级效果演示
(1) 准备升级文件
[root@master 5-deployment]# cat nginx-deploy-update-rollingupdate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx-dm
spec:
selector:
matchLabels:
app: nginx-dm
replicas: 3
strategy: # 升级策略
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: nginx-dm
spec:
containers:
- name: nginx
image: nginx:1.27.5 # 这里表示要升级到1.27.5版本
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
采用默认RollingUpdate策略,上述strategy字段中,最多1个pod不可用(maxUnavalible),每次最多新创建1个额外的pod(maxSurge),升级的新版本为1.27.5。
这个文件和nginx-deploy.yaml文件除了上面标的部分,其他完全相同,这样才能保证升级成功,如果deploy的name不一样,那就不是升级,而是新创建资源了。
(2) 升级
创建1.27.3版本的deploy
[root@master 5-deployment]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deploy created
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-bj5hh 1/1 Running 0 2s
nginx-deploy-7c7bbf4cc9-kn28k 1/1 Running 0 2s
nginx-deploy-7c7bbf4cc9-xkb9z 1/1 Running 0 2s
执行升级文件,升级文件是从nginx-deploy.yaml修改而来。
[root@master 5-deployment]# kubectl apply -f nginx-deploy-update-rollingupdate.yaml
deployment.apps/nginx-deploy configured
升级过程开始,每次最多1个pod不可用,最多新创建1个额外pod
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-767c5479df-flqn8 1/1 Running 0 1s
nginx-deploy-767c5479df-jfssd 1/1 Running 0 1s
nginx-deploy-767c5479df-m8zb2 0/1 Pending 0 0s
nginx-deploy-7c7bbf4cc9-kn28k 1/1 Terminating 0 9s
nginx-deploy-7c7bbf4cc9-xkb9z 1/1 Running 0 9s
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-767c5479df-flqn8 1/1 Running 0 2s
nginx-deploy-767c5479df-jfssd 1/1 Running 0 2s
nginx-deploy-767c5479df-m8zb2 0/1 ContainerCreating 0 1s
nginx-deploy-7c7bbf4cc9-kn28k 0/1 Terminating 0 10s
nginx-deploy-7c7bbf4cc9-xkb9z 0/1 Terminating 0 10s
至此,重新创建了三个pod
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-767c5479df-flqn8 1/1 Running 0 2s
nginx-deploy-767c5479df-jfssd 1/1 Running 0 2s
nginx-deploy-767c5479df-m8zb2 1/1 Running 0 1s
查看一下pod的具体详情,可以看到现在运行的已经是1.27.5版本的nginx,滚动升级完成。
[root@master 5-deployment]# kubectl describe pod nginx-deploy-767c5479df-flqn8
Name: nginx-deploy-767c5479df-flqn8
Namespace: default
Priority: 0
Service Account: default
Node: master/192.168.88.130
Start Time: Sat, 19 Jul 2025 21:40:22 +0800
Labels: app=nginx-dm
pod-template-hash=767c5479df
Annotations: <none>Status: RunningIP: 10.42.0.170IPs:IP: 10.42.0.170Controlled By: ReplicaSet/nginx-deploy-767c5479dfContainers:nginx:Container ID: docker://469206f8a5f36f00e50ea1b1ea3fe7d4fda5d3adf97f2a2a52b63abd40544ad7Image: nginx:1.27.5Image ID: docker://sha256:ce663b26176bac0729e88c8008b8dadfc5f164eea15bf7530bf4eed594564b2aPort: 80/TCPHost Port: 0/TCPState: RunningStarted: Sat, 19 Jul 2025 21:40:23 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-mdk47 (ro)Conditions:Type StatusPodReadyToStartContainers TrueInitialized TrueReady TrueContainersReady TruePodScheduled TrueVolumes:kube-api-access-mdk47:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: trueQoS Class: BestEffortNode-Selectors: <none>Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300sEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 4m43s default-scheduler Successfully assigned default/nginx-deploy-767c5479df-flqn8 to masterNormal Pulled 4m43s kubelet Container image "nginx:1.27.5" already present on machineNormal Created 4m43s kubelet Created container nginxNormal Started 4m43s kubelet Started container nginx
3.4 示例:Recreate升级效果演示
(1) 准备升级文件
[root@master 5-deployment]# cat nginx-deploy-update-recreate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx-dm
spec:
selector:
matchLabels:
app: nginx-dm
replicas: 3
strategy: # 升级策略
type: Recreate
template:
metadata:
labels:
app: nginx-dm
spec:
containers:
- name: nginx
image: nginx:1.27.5 # 版本
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
采用Recreate升级策略,上述strategy字段中,type为Recreate,升级之前将删除所有旧pod,升级的新版本为1.27.5。
(2) 升级
首先确保之前示例创建的资源都已经被删除
[root@master 5-deployment]# kubectl get pods
No resources found in default namespace.
创建1.27.3版本的deploy
[root@master 5-deployment]# kubectl apply -f nginx-deploy.yaml
deployment.apps/nginx-deploy created
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-gc2qs 1/1 Running 0 3s
nginx-deploy-7c7bbf4cc9-rrlh6 1/1 Running 0 3s
nginx-deploy-7c7bbf4cc9-tcqrk 1/1 Running 0 3s
通过查看pod详情可以看到目前的nginx版本为1.27.3
[root@master 5-deployment]# kubectl describe pod nginx-deploy-7c7bbf4cc9-gc2qs
Name: nginx-deploy-7c7bbf4cc9-gc2qs
Namespace: default
Priority: 0
Service Account: default
Node: master/192.168.88.130
Start Time: Sat, 19 Jul 2025 21:48:59 +0800
Labels: app=nginx-dm
pod-template-hash=7c7bbf4cc9
Annotations: <none>Status: RunningIP: 10.42.0.181IPs:IP: 10.42.0.181Controlled By: ReplicaSet/nginx-deploy-7c7bbf4cc9Containers:nginx:Container ID: docker://ae9678764f374d34949331f8d6bad70fcde699ee8257f92f68de1724b35f7f36Image: nginx:1.27.3Image ID: docker://sha256:66f8bdd3810c96dc5c28aec39583af731b34a2cd99471530f53c8794ed5b423ePort: 80/TCPHost Port: 0/TCPState: RunningStarted: Sat, 19 Jul 2025 21:49:00 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-nl4gh (ro)Conditions:Type StatusPodReadyToStartContainers TrueInitialized TrueReady TrueContainersReady TruePodScheduled TrueVolumes:kube-api-access-nl4gh:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: trueQoS Class: BestEffortNode-Selectors: <none>Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300sEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 10s default-scheduler Successfully assigned default/nginx-deploy-7c7bbf4cc9-gc2qs to masterNormal Pulled 9s kubelet Container image "nginx:1.27.3" already present on machineNormal Created 9s kubelet Created container nginxNormal Started 9s kubelet Started container nginx
执行升级操作
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-7c7bbf4cc9-gc2qs 1/1 Running 0 14s
nginx-deploy-7c7bbf4cc9-rrlh6 1/1 Running 0 14s
nginx-deploy-7c7bbf4cc9-tcqrk 1/1 Running 0 14s
[root@master 5-deployment]# kubectl apply -f nginx-deploy-update-recreate.yaml
deployment.apps/nginx-deploy configured
这里可以看到,之前的三个pod,已经全部被删除,即使新的pod还没创建成功,这就是Recreate策略,升级之前先删除全部旧pod
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-767c5479df-f5l5t 0/1 Pending 0 0s
nginx-deploy-767c5479df-p9fss 0/1 ContainerCreating 0 0s
nginx-deploy-767c5479df-vfjrf 0/1 ContainerCreating 0 0s
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-767c5479df-f5l5t 1/1 Running 0 1s
nginx-deploy-767c5479df-p9fss 0/1 ContainerCreating 0 1s
nginx-deploy-767c5479df-vfjrf 0/1 ContainerCreating 0 1s
升级完成,所有pod状态为Running
[root@master 5-deployment]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deploy-767c5479df-f5l5t 1/1 Running 0 2s
nginx-deploy-767c5479df-p9fss 1/1 Running 0 2s
nginx-deploy-767c5479df-vfjrf 1/1 Running 0 2s
查看pod详情,可以看到nginx版本已经是1.27.5
[root@master 5-deployment]# kubectl describe pod nginx-deploy-767c5479df-f5l5t
Name: nginx-deploy-767c5479df-f5l5t
Namespace: default
Priority: 0
Service Account: default
Node: master/192.168.88.130
Start Time: Sat, 19 Jul 2025 21:49:19 +0800
Labels: app=nginx-dm
pod-template-hash=767c5479df
Annotations: <none>Status: RunningIP: 10.42.0.183IPs:IP: 10.42.0.183Controlled By: ReplicaSet/nginx-deploy-767c5479dfContainers:nginx:Container ID: docker://c7dab121baa533a757b9f64e5f6598699206dd14f8bc66cc350b6fe756fb43f7Image: nginx:1.27.5Image ID: docker://sha256:ce663b26176bac0729e88c8008b8dadfc5f164eea15bf7530bf4eed594564b2aPort: 80/TCPHost Port: 0/TCPState: RunningStarted: Sat, 19 Jul 2025 21:49:20 +0800Ready: TrueRestart Count: 0Environment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-4hk4c (ro)Conditions:Type StatusPodReadyToStartContainers TrueInitialized TrueReady TrueContainersReady TruePodScheduled TrueVolumes:kube-api-access-4hk4c:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: trueQoS Class: BestEffortNode-Selectors: <none>Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300sEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 23s default-scheduler Successfully assigned default/nginx-deploy-767c5479df-f5l5t to masterNormal Pulled 23s kubelet Container image "nginx:1.27.5" already present on machineNormal Created 23s kubelet Created container nginxNormal Started 23s kubelet Started container nginx