Kubernetes Cookbook 编程指南 中文版教程
创建时间:2018-12-07  访问量:3668  7  0

Kubernetes Cookbook 编程指南 中文版教程

更新活动容器

容器所带来的好处是,我们可以很容易通过执行新的镜像发布新的程序,并且可以减少环境设置带来的麻烦。但是,怎样在运行的容器中发布程序呢?使用本地Docker命令,我们不得不先停止容器,再使用新的镜像与相同的配置启动一个容器。在Kubernetes系统中还有一个简单高效零时间停机的方法更新你的容器中的程序。它叫作滚动更新。本节我们将向你展示这种方式。

开始

滚动更新是工作在副本控制器单元上的。效果是一个一个的创建新的Pod代替旧的Pod。在目标副本控制器中,新的Pod被附加上原始标签。因此,如果任何服务暴露这个副本控制器,它将会直接接管新创建Pod。

对于接下来的描述,我们将更新一个新的nginx镜像。除此之外,我们将确保Node节点能够获取你放在Docker Hub、公共Docker仓库或私有仓库上的自定义镜像。

例如,你可以通过编写你自己Dockerfile来创建镜像:

$ cat Dockerfile
FROM nginx
RUN echo "Happy Programming!" > /usr/share/nginx/html/index.html

在这个Docker镜像中,我们改变了index.html页面的黙认内容。然后,你可以构建镜像并使用以下命令将其推送到Docker Hub:

// push to Docker Hub
$ docker build -t <DOCKERHUB_ACCOUNT>/common-nginx . && docker push <DOCKERHUB_ACCOUNT>/common-nginx
// Or, you can also push to your private docker registry
$ docker build -t <RESITRY_NAME>/common-nginx . && docker push <RESITRY_NAME>/common-nginx

为了让Node节点能够访问私有Docker仓库的认证,请参考第5章构建持续交付管线,私有Docker registry的使用。

如何去做...

你现在将学习如何发布一个Docker镜像。下面的步骤将帮助你成功发布一个Docker镜像:

  1. 首先,为滚动更新测试创建一对副本控制器和服务。如下述所表达的,一个将要创建5个副本的副本控制器。nginx程序为容器暴露80端口,Kubernetes服务会将这个端口传送到内网的8080端口:

// Create a replication controller named nginx-rc
# kubectl run nginx-rc --image=nginx --replicas=5 --port=80 --labels="User=Amy,App=Web,State=Testing"
replicationcontroller "nginx-rc" created
// Create a service supporting nginx-rc
# kubectl expose rc nginx-rc --port=8080 --target-port=80
--name="nginx-service"
service "nginx-service" exposed
# kubectl get service nginx-service
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
nginx-service 192.168.163.46 <none> 8080/TCP App=Web,State=Testing,User=Amy 35s

你可以通过检验<POD_IP>:80和<CLUSTER_IP>:8080评估一下组件是否工作良好。

  1. 现在,我们就能够将目标转到容器的更新步骤上了!这个Kubernetes子命令rolling-update会帮助保留活动副本控制器的更新。在下面的命令中,用户需要指定副本控制器的名称和新的镜像。这里,我们将使用刚刚上传到Docker Hub上的新镜像:

# kubectl rolling-update nginx-rc --image=<DOCKERHUB_ACCOUNT>/
common-nginx
Created nginx-rc-b6610813702bab5ad49d4aadd2e5b375
Scaling up nginx-rc-b6610813702bab5ad49d4aadd2e5b375 from 0 to 5,
scaling down nginx-rc from 5 to 0 (keep 5 pods available, don't
exceed 6 pods)
Scaling nginx-rc-b6610813702bab5ad49d4aadd2e5b375 up to 1
  1. 你可能看到进程挂起了。因为rolling-update命令将一次只单独启动一个新的Pod并待一段时间;黙认停止旧的Pod并创建第二个新的Pod需要一分钟时间。以这个观点来说,在更新的时候,总是会多出一个Pod提供服务,与就是比副本控制所期望的数量要多一个。在这种情况下,将有6个Pod。因此,当更新副本控制器时,请访问另一个终端来进行处理。

  2. 验证副本控制器更多的概念:

# kubectl get rc
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS AGE
nginx-rc nginx-rc nginx App=Web,State=Testing,User=Amy,deployment=313da350dea9227b89b4f0340699a388 5 1m
nginx-rc-b6610813702bab5ad49d4aadd2e5b375 nginxrc <DOCKERHUB_ACCOUNT>/common-nginx
App=Web,State=Testing,User=Amy,deployment=b6610813702bab5ad49d4aadd2e5b375 1 16s
  1. 正如你发现的,系统创建了一个几乎一样的副本控制器,只是在名称后添加了一个后缀。一个新标签的键deployment这两个副本控制器的后面以示区分。另一方面,新的nginx-rc被附加了其它原始标签的后面。服务同时也会关注新的Pod:

// Check service nginx-service while updating
# kubectl describe service nginx-service
Name: nginx-service
Namespace: default
Labels: App=Web,State=Testing,User=Amy
Selector: App=Web,State=Testing,User=Amy
Type: ClusterIP
IP: 192.168.163.46
Port: <unnamed> 8080/TCP
Endpoints: 192.168.15.5:80,192.168.15.6:80,192.168.15.7:80 + 3
more...
Session Affinity: None
No events.

nginx-service Pod包含了6个端点,这是由滚动更新的定义支持的。

  1. 返回更新处理进程的命令行。在更新完成后,人可以查看以下更新过程:

Created nginx-rc-b6610813702bab5ad49d4aadd2e5b375
Scaling up nginx-rc-b6610813702bab5ad49d4aadd2e5b375 from 0 to 5,
scaling down nginx-rc from 5 to 0 (keep 5 pods available, don't
exceed 6 pods)
Scaling nginx-rc-b6610813702bab5ad49d4aadd2e5b375 up to 1
Scaling nginx-rc down to 4
Scaling nginx-rc-b6610813702bab5ad49d4aadd2e5b375 up to 2
Scaling nginx-rc down to 3
Scaling nginx-rc-b6610813702bab5ad49d4aadd2e5b375 up to 3
Scaling nginx-rc down to 2
Scaling nginx-rc-b6610813702bab5ad49d4aadd2e5b375 up to 4
Scaling nginx-rc down to 1
Scaling nginx-rc-b6610813702bab5ad49d4aadd2e5b375 up to 5
Scaling nginx-rc down to 0
Update succeeded. Deleting old controller: nginx-rc
Renaming nginx-rc-b6610813702bab5ad49d4aadd2e5b375 to nginx-rc
replicationcontroller "nginx-rc" rolling updated

通过慢慢缩小Pod的数量,旧的nginx-rc会渐渐的停止服务。

  1. 在更新的最后一步,新的副本控制器扩展到5个Pod达到期望值,最终替代了旧的副本控制器:

// Take a look a current replication controller
// The new label "deployment" is remained after update
# kubectl get rc nginx-rc
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR
REPLICAS AGE
nginx-rc nginx-rc <DOCKERHUB_ACCOUNT>/common-nginx App
=Web,State=Testing,User=Amy,deployment=b6610813702bab5ad49d4aadd2e
5b375 5 40s
  1. 使用ClusterIP和端口验证服务,我们现在已经在副本控制器更中完成所有的Pod更换了:
# curl 192.168.163.46:8080
Happy Programming!
  1. 依据之前的描述,它花费了大约5分钟的时间来发布新的Docker镜像。因此黙认的伸缩过程的更新时间设置了1分钟。对你来说依靠--update-period标记,可以设置更快或更慢时间。有效时间单位有ns、us、ms、s、m和h。例如,--update-period=1m0s:
// Try on this one!
# kubectl rolling-update <REPLICATION_CONTROLLER_NAME>
--image=<IMAGE_NAME> --update-period=10s

它是如何工作的...

本节,我们将详细讨论滚动更新。以N秒为更新周期来更新副本控制器如何?看下面的图片:

前面一个图片指明了更新过程的每一步。我们可以从滚动更新中获取一样重新的概念:

  • 这两个副本控制器中的每一个Pod都有一个新的标签,当是一个不同的值指向不同。此外,其它标签相同,因此在更新过程中,服务仍可以通过选择器覆盖这两个副本控制器。

  • 我们将花费#副本控制器中Pod的数量*更新时间来牵移新的配置。

  • 对于零时间停机更新,服务所覆盖的Pod总数量应该总能达到期望的数量。例如,在前面的图片中,总有3个Pod同时在提供服务。

  • 滚动更新过程不保证用在HAPPY-RC-<HashKey2>中新创建的Pod处于运行状态。这就是我们需要更新周期的原因。在新更周期过后,这个过程要需要N秒,一个新的Pod应该能够代替一个旧的Pod。然后,就好终止旧的Pod了。

  • 更新时间的周期应该是新pod从拉取镜像到运行所需时间的最坏情况。

不止这些...

当滚动更新时,我们可以指定一个新副本控制器的镜像。但有些时候,我们不能成功的更新一个镜像。那是因为容器镜像拉取策略的原因。

为了更新一个指定的镜像,如果用户提供一个应该拉取镜像的版本标签请晰精确的话那就非常好了。然而,大部分时间,用户都是查找最新的镜像并且新的镜像与本地的镜像会被认为是同一个,因为本地的镜像也叫latest。在更新时使用类似的命令<DOCKERHUB_ACCOUNT>/common-nginx:latest image,如下所示:

# kubectl rolling-update nginx-rc --image=<DOCKERHUB_ACCOUNT>/commonnginx --update-period=10s

尽管如此,如果Node节点发现一个与镜像标签相同的请求,它将会忽略拉取latest版本的common-nginx。对于这个原因,我们需要保证指定我镜像能够从Regitry中拉取。

为了更改配置,子命令edit可以帮助,方式如下:

# kubectl edit rc <REPLICATION_CONTROLLER_NAME>

然后,你就可以在YAML格式的文件中编辑副本控制器的配置了。镜像拉取策略可以从下面的类结构中找到:

apiVersion: v1
kind: replicationcontroller
spec:
    template:
        spec:
            containers:
            - name: <CONTAINER_NAME>
                image: <IMAGE_TAG>
               		imagePullPolicy: IfNotPresent
:

IfNotPresent的值告诉Node节点仅仅拉取镜像,不要存储在本地磁盘上。通过改变Always策略,用户将能避免更新失败。在配置文件中设置键值对是可行的。因此,指定的镜像能够保证这是Registry中的镜像。

还可以参考

在Kubernetes系统中Pod中基本的计算单元。你可以通过以下章节更高效的学习如何使用Pod:

  • 扩展你的容器

  • 第5章构建持续交付管线,从整体到微服务、与Jenkins集成、使用私有Docker registry和设置持续交付管线这几节