Kubernetes Deployment的运行

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:

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:            

    Environment Variables:  

Conditions:

  Type          Status

  Initialized   True

  Ready         True

  PodScheduled  True

No volumes.

QoS Class:      BestEffort

Tolerations:   

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

请使用浏览器的分享功能分享到微信等