Deployment提供了一种更加简单的更新Replication Controller和Pod的机制,更好地解决了Pod的编排问题。本节将详细介绍如何通过Deployment实现Pod的管理。
15.1.1 什么是Deployment
Deployment的中文意思为部署、调集,它是在Kubernetes的1.2版本中新增加的一个核心概念。Deployment的实现为用户管理Pod提供了一种更为便捷的方式。用户可以通过在Deployment中描述所期望的集群状态,将现在的集群状态在一个可控的速度下逐步更新成所期望的集群状态。与Replication Controller(复制控制器)基本一样,Deployment的主要职责同样是保证Pod的数量和健康。Deployment的绝大部分功能与Replication Controller完全一样,因此,用户可以将Deployment看作是升级版的Replication Controller。
与Replication Controller相比,除了继承Replication Controller的全部功能之外,Deployment还有以下新的特性。
- 事件和状态查看:可以查看Deployment升级的详细进度和状态。
- 回滚:当升级Pod镜像或者相关参数的时候发现问题,可以使用回滚操作回退到上一个稳定的版本或者指定的版本。
- 版本记录:每次对Deployment的操作都能保存下来,以备后续可能的回滚操作。
- 暂停和启动:对于每次升级,都能够随时暂停和启动。
- 多种升级方案:主要包括重建,即删除所有已存在的Pod,重新创建新的Pod;滚动升级,即采用逐步替换的策略,同时滚动升级时支持更多的附加参数。
15.1.2 Deployment与ReplicaSet
讲到ReplicaSet对象,不得不提到Replication Controller。在旧版本的Kubernetes中,只有Replication Controller对象,它的主要作用是确保Pod以用户指定的副本数运行,即如果有容器异常退出,Replication Controller会自动创建新的Pod来替代,因异常情况而多出来的容器也会自动回收。可以说,通过Replication Controller,Kubernetes实现了集群的高可用性。
在Kubernetes 1.15后续版本中,建议使用ReplicaSet来取代Replication Controller。ReplicaSet跟Replication Controller没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的选择器,而Replication Controller只支持等式选择器。
虽然ReplicaSet也可以独立使用,但是Kubernetes并不建议用户直接操作ReplicaSet对象。而是通过更高层次的对象Deployment来自动管理ReplicaSet,这样就无须担心与其他机制不兼容的问题,比如ReplicaSet不支持滚动更新,但Deployment支持,并且Deployment还支持版本记录、回滚、暂停升级等高级特性。这意味着用户几乎不会有机会直接管理ReplicaSet。
15.1.3 运行Deployment
我们先从一个简单的例子开始介绍如何运行Deployment,执行如下命令,结果如下:
$ kubectl run nginx-deployment --image=nginx:1.7.9 --replicas=3
deployment "nginx-deployment" created
在上面的命令中,nginx-deployment是指要创建的Deployment的名称,--image选项用来指定容器所使用的镜像,其中nginx为镜像名称,1.7.9为版本号。replicas选项用来指定Pod的副本数为3,即当前集群中在任何时候都要保证有3个Nginx的副本在运行。
执行完命令之后,用户可以通过get命令查看刚才运行的Deployment,如下所示:
$ kubectl get deployment nginx-deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 10s
在上面的输出结果中,DESIRED表示预期的副本数,即我们在命令中通过--replicas参数指定的数量。CURRENT表示当前的副本数。实际上,CURRENT是Deployment所创建的ReplicaSet中Replica的值,在部署的过程中,这个数值会不断地增加,一直增加到DESIRED所指定的值为止。UP-TO-DATE表示当前已经处于新版本的Pod的副本数,主要用于在滚动升级的过程中,表示当前已经有多少个副本已经成功升级。AVAILABLE表示当前集群中属于当前Deployment的、可用的Pod的副本数量,实际上,就是当前Deployment所产生的、在当前集群中存活的Pod的数量。AGE表示当前Deployment的年龄,即从创建到现在的时间差。
接下来,我们通过describe deployment命令来查看当前Deployment更加详细的信息,如下所示:
$ kubectl describe deployment nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 24 Mar 2023 06:57:18 +0800
Labels: run=nginx-deployment
Selector: run=nginx-deployment
Replicas: 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-3954615459 (3/3 replicas created)
No events.
上面的输出信息的含义大部分都非常明确,我们重点关注几点即可。首先Namespace表示当前Deployment所属的命名空间为default,即默认的命名空间。Replicas表示当前Pod的副本信息。NewReplicaSet表示由Deployment自动创建的ReplicaSet,其名称为nginx-deployment-3954615459,可以发现ReplicaSet的名称使用了所属的Deployment的名称作为前缀,这样可以非常容易地分辨这个ReplicaSet是由哪个Deployment创建的。
前面已经介绍过ReplicaSet是一个非常重要的概念,而且用户几乎不会直接操作ReplicaSet,而是通过Deployment间接地管理。下面我们通过get replicaset命令来查看ReplicaSet的信息,如下所示:
$ kubectl get replicaset
NAME DESIRED CURRENT READY AGE
nginx-deployment-3954615459 3 3 3 10s
在上面的输出信息中,ReplicaSet的名称为nginx-deployment-3954615459。READY表示当前已经就绪的副本数。
为了了解更多关于nginx-deployment-3954615459的信息,可以通过describe replicaset命令来查看,如下所示:
$ kubectl describe replicaset nginx-deployment-3954615459
Name: nginx-deployment-3954615459
Namespace: default
Image(s): nginx:1.7.9
Selector: pod-template-hash=3954615459,run=nginx-deployment
Labels: pod-template-hash=3954615459
run=nginx-deployment
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
No volumes.
No events.
Image表示容器所使用的镜像为nginx:1.7.9,Replicas表示副本数,Pods Status表示当前Deployment所创建的Pod的状态,可以看到有3个副本处于运行(Running)状态,没有处于等待(Waiting)、结束(Succeeded)或者失败(Failed)状态的Pod。
接下来,我们继续探讨Deployment所创建的Pod。执行get pod命令,获取当前集群中的Pod信息,如下所示:
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
...
nginx-deployment-3954615459-4zp22 1/1 Running 0 1h 172.17.0.5 192.168.1.122
nginx-deployment-3954615459-b2jvj 1/1 Running 0 1h 172.17.0.3 127.0.0.1
nginx-deployment-3954615459-rpjcp 1/1 Running 0 1h 172.17.0.4 127.0.0.1
...
可以得知,3个Pod副本都处于运行状态。另外,Kubernetes还为每个Pod自动分配了IP地址。其中1个副本运行在名称为192.168.1.122的节点上,2个副本运行在名称为127.0.0.1的节点上。为了便于维护,Pod的命名规则也是以Deployment的名称以及ReplicaSet的名称作为前缀的。由此可以推断出,在同一个节点上,可以同时运行一个Pod的多个副本。
前面已经介绍过,Kubernetes中的各种服务最终是由Pod中的容器提供的。因此,了解Pod及其容器是我们的最终目标。所以,下面通过kubectl describe pod命令来查看其中某个Pod副本的详细信息,如下所示:
$ kubectl describe pod nginx-deployment-3954615459-4zp22
Name: nginx-deployment-3954615459-4zp22
Namespace: default
Node: 192.168.1.122/192.168.1.122
Start Time: Sun, 24 Mar 2019 06:57:19 +0800
Labels: pod-template-hash=3954615459
run=nginx-deployment
Status: Running
IP: 172.17.0.2
Controllers: ReplicaSet/nginx-deployment-3954615459
Containers:
nginx-deployment:
Container ID: docker://df381a4ea070522af06d897d0c49a253def23ac7264a8b5bc3b50fbe67e86b6a
Image: nginx:1.7.9
Image ID: docker-pullable://docker.io/nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
Port:
State: Running
Started: Sun, 24 Mar 2019 17:02:43 +0800
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Sun, 24 Mar 2019 07:59:14 +0800
Finished: Sun, 24 Mar 2019 08:03:36 +0800
Ready: True
Restart Count: 1
Volume Mounts: <none>
Environment Variables: <none>
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
No volumes.
QoS Class: BestEffort
Tolerations: <none>
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
56m 56m 2 {kubelet 192.168.1.122} Warning MissingClusterDNS kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to DNSDefault policy.
56m 56m 1 {kubelet 192.168.1.122} spec.containers{nginx-deployment} Normal Pulled Container image "nginx:1.7.9" already present on machine
56m 56m 1 {kubelet 192.168.1.122} spec.containers{nginx-deployment} Normal Created Created container with docker id df381a4ea070; Security:[seccomp=unconfined]
56m 56m 1 {kubelet 192.168.1.122} spec.containers{nginx-deployment} Normal Started Started container with docker id df381a4ea070
该命令的输出信息非常多,我们只要关注其中重要的部分即可。Node表示当前Pod所处的节点。IP是Kubernetes为当前Pod副本分配的IP地址,用户可以通过该IP地址与Pod通信。Controllers表示当前Pod由哪个Deployment和ReplicaSet创建。在本例中,Deployment名称为nginx-deployment,ReplicaSet名称为nginx-deployment-3954615459。Containers表示当前Pod中的容器的列表,在本例中,只有一个用户容器,其容器ID为docker://df381a4ea070522af06d897d0c49a253def23ac7264a8b5bc3b50fbe67e86b6a。Events为当前Pod副本的日志信息,便于用户调试。
最后,我们的关注点落在了容器上。由于nginx-deployment-3954615459-4zp22当前运行在名称为192.168.1.122的节点上,因此我们登录到192.168.1.122,然后使用前面介绍的容器管理命令docker ps来查看当前节点的容器列表,如下所示:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
...
df381a4ea070 nginx:1.7.9 "nginx -g 'daemon ..." About an hour ago Up About an hour k8s_nginx-deployment.a8dee3c8_nginx-deployment-3954615459-4zp22
_default_0271d1ca-4dbf-11e9-867a-000c2994a2b7_20f4bc78
fb16d8356f3c registry.access.redhat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" About an hour ago Up About an hour k8s_POD.ae8ee9ac_nginx-deployment-3954615459-4zp22_default_0271d1ca-4dbf-11e9-867a-000c2994a2b7_5927077c
...
可以看到,在192.168.1.122节点上有2个容器,这2个容器都是由nginx-deployment创建的。还记得前面介绍的Pod的结构吗?在每个Pod中都存在着一个名称为Pause的根容器,这个根容器是Kubernetes系统的一部分。在上面的容器列表中,ID为df381a4ea070的是用户容器,ID为fb16d8356f3c的即为当前Pod的根容器。
用户可以通过docker inspect命令查看容器的详细信息,如下所示:
$ docker inspect df381a4ea070
[
{
"Id": "df381a4ea070522af06d897d0c49a253def23ac7264a8b5bc3b50fbe67e86b6a",
"Created": "2019-03-24T09:02:43.579970795Z",
"Path": "nginx",
"Args": [
"-g",
"daemon off;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 13830,
"ExitCode": 0,
"Error": "",
"StartedAt": "2019-03-24T09:02:43.808003Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:84581e99d807a703c9c03bd1a31cd9621815155ac72a7365fd02311264512656",
"ResolvConfPath": "/var/lib/docker/containers/fb16d8356f3c7e2f630e9f7349791369cbbbfd813a77072e6ac1c3780f2ac710/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/fb16d8356f3c7e2f630e9f7349791369cbbbfd813a77072e6ac1c3780f2ac710/hostname",
"HostsPath": "/var/lib/kubelet/pods/0271d1ca-4dbf-11e9-867a-000c2994a2b7/etc-hosts",
"LogPath": "",
"Name": "/k8s_nginx-deployment.a8dee3c8_nginx-deployment-3954615459-4zp22_default_0271d1ca-4dbf-11e9-867a-000c2994a2b7_20f4bc78",
"RestartCount": 0,
"Driver": "overlay2",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": [
...
由于这部分内容前面已经详细介绍过,因此此处不再重复讲解。
至此,我们已经成功地运行了一个Deployment。