docker入门(10)--零中断部署

本节主要学习,如何在不终止服务的情况下,升级服务中的应用等。
为了做到零终端,通常,我们应用的部署策略有三种:

  • Rolling updates 滚动部署
  • Blue-green deployments 蓝绿部署
  • Canary releases 金丝雀部署

三者的一些比较:
微服务部署:蓝绿部署、滚动部署、灰度发布等部署方案对比与总结
蓝绿部署、金丝雀发布(灰度发布)、A/B测试的准确定义
docker swarm默认支持Rolling updates的开箱即用。其他两种方式可通过扩展支持。

1. 滚动部署

关于原理部分可参考上面的链接,下面我们进行实践。
定义一个包含rolling update相关配置的stack,命名为rolling-update.yml:

version: "3.5"
services:
  web:
    image: nginx:1.13-alpine
    ports:
      - 8080:80
    deploy:
      replicas: 10
      update_config:
        parallelism: 2
        delay: 10s

上面的大部分内容之前都学习过,我们这里主要看update_config部分。上面的配置表示,一共会启用10个task,在升级时,每2个task会成为一组进行升级操作,每一组升级成功之后,间隔10s开始下一组的升级。

1、开始部署上面的stack:
docker stack deploy -c rolling-update.yml web命令执行部署,部署完成后,可以使用watch docker stack ps web命令查看,刚开始可能如下图,正在Preparing的一般是镜像还没有拉取下来,要等到超时之后下一次重试(每次重试间隔大约5分钟,应该是可以进行相关设置的。在我没换国内镜像仓库之前失败的次数更多,不过镜像下载一次之后,后续就不用下载了,部署起来速度很快)。


所有的task都必须正常启动了之后,才能开始进行下面的升级工作,如下:


2、升级上面的stack
执行升级之前,建议再开一个窗口,并且将docker-machine环境变量设置为node-1,然后执行watch docker stack ps web,可以实时查看相关进度。
执行如下命令,升级上面stack中的nginx版本:
docker service update --image nginx:1.14-alpine web_web
可以看到就是每次两个task进行升级操作,其他task继续提供服务。


3、测试完成,删除stack
docker stack rm web

2. 健康检查

有时候,你在查看容器运行的状态时,它可能是显示OK的状态,但容器内的应用是否OK,你这个时候还无法确定。因此,我们通常使用健康检查来确定一个服务是否确实在正常运行。
我们通常有两种方式来定义健康检查。

2.1 Dockerfile定义健康检查

我们可以在制作镜像时,就为镜像内的服务定义健康检查,通常如下:

FROM alpine:3.6
...
HEALTHCHECK --interval=30s \
    --timeout=10s
    --retries=3
    --start-period=60s
    CMD curl -f http://localhost:3000/health || exit 1
...

--start-period=60s:通常服务的启动,需要一定时间,在这段时间内不会执行健康检查。
--interval=30s:每次检查的时间间隔。
--timeout=10s:每次检查的超时时间。
--retries=3:重试多少次后,认为服务不可用。
CMD curl -f http://localhost:3000/health || exit 1:通过在容器内执行什么命令,来检查服务是否可用。

2.2 stack file文件内定义健康检查

一个示例如下:

version: "3.5"
services:
  web:
    image: nginx:alpine
    healthcheck:
      test: ["CMD", "wget", "-qO", "-", "http://localhost"]
      interval: 5s
      timeout: 2s
      retries: 3
      start_period: 15s

参数与上面的Dockerfile中的类似,需要注意的是:1、你必须为每个service定义一个健康检查,而不是对整个stack进行。2、如果你的service所引用的镜像内已经包含健康检查,那么这里的定义会覆盖它。

部署上面的示例看看:
docker stack deploy -c stack-health.yml myapp


你会看到与之前有所不同的地方是,在STATUS栏,多了个healthy。

3. 回滚操作

可能有多种原因造成新的版本,确实新版无法正常运行的时候,我们需要预定义好回滚操作。
一个配置示例如下:

version: "3.5"
services:
  web:
    image: nginx:1.12-alpine
    ports:
      - 80:80
    deploy:
      replicas: 10
      update_config:
      parallelism: 2
      delay: 10s
      
      failure_action: rollback
      monitor: 10s
      
    healthcheck:
      test: ["CMD", "wget", "-qO", "-", "http://localhost"]
      interval: 2s
      timeout: 2s
      retries: 3
      start_period: 2s

通过前面的知识,我们知道,一个task要被确认为不健康的状态,需要的时间是:start_period + interval*retries,因此,这里需要8秒钟。
monitor: 10s:定义在一个task开始部署后,需要对它持续监控的时间,用来决定是否进行下一组的升级操作。因此,需要大于上面的8秒。
failure_action: rollback:该参数在默认情况下,如果发现升级失败,那么会立即停止这次升级,并保持这个状态退出升级(例如前面包含10个task,每次升级2个的service,会保持其余8个task还是运行老旧版本的状态,并对外提供服务)。而我们如果配置为rollback值的话,表示进行回滚操作,那2个失败的task会恢复运行之前的版本,并提供服务。

4. 密码管理

我们经常需要向容器内传递一些敏感信息,例如最常见的密码。我们可以通过-e参数来指定传入的变量以及对应的值,但是,这样我们的密码就以明文形式暴露了。为了解决这个问题,docker swarm 提供了 secret 机制。
secret需要由manager节点创建,并保存。worker需要使用的时候,通过tmpFS文件系统挂载使用。

4.1 创建密码

从标准输出创建:
echo "sample secret value" | docker secret create sample-secret -
读取文件内容创建:
docker secret create other-secret ~/my-secrets/secret-value.txt
查看当前已有的密码和审查:

[root@node2 swarm]# docker secret ls
ID                          NAME                DRIVER              CREATED             UPDATED
ams8zjhm15z8qpfv9mgv5wrv9   sample-secret                           7 seconds ago       7 seconds ago
[root@node2 swarm]# docker secret inspect sample-secret
[
    {
        "ID": "ams8zjhm15z8qpfv9mgv5wrv9",
        "Version": {
            "Index": 893
        },
        "CreatedAt": "2018-11-05T03:20:51.9911386Z",
        "UpdatedAt": "2018-11-05T03:20:51.9911386Z",
        "Spec": {
            "Name": "sample-secret",
            "Labels": {}
        }
    }
]

4.2 使用密码

[root@node2 swarm]# docker service create --name web \
> --secret sample-secret \
> --publish 8000:8000 \
> fundamentalsofdocker/whoami:latest

jwwd32a5qbld0lviruneezcl5
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged
[root@node2 swarm]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                PORTS
jwwd32a5qbld        web                 replicated          1/1                 fundamentalsofdocker/whoami:latest   *:8000->8000/tcp
[root@node2 swarm]# docker service ps web
ID                  NAME                IMAGE                                NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
kd8jknn6llb6        web.1               fundamentalsofdocker/whoami:latest   node-3              Running             Running 47 seconds ago
[root@node2 swarm]# docker-machine ssh node-3
docker@node-3:~$ docker container ls
CONTAINER ID        IMAGE                                COMMAND             CREATED             STATUS              PORTS               NAMES
cf2952b075cc        fundamentalsofdocker/whoami:latest   "/app/http"         2 minutes ago       Up 2 minutes        8000/tcp            web.1.kd8jknn6llb6vfgne68of5v01
docker@node-3:~$ docker container exec -it cf2952b075cc cat /run/secrets/sample-secret
sample secret value

以上操作为:
1、创建一个使用了sample-secret密码的service。
2、查看对应的task在哪个节点上,node-3。
3、登录到node-3上,查看对应的容器。
4、在容器内执行cat /run/secrets/sample-secret,可以得到明文的密码。
以上操作表明了,默认会把密码挂载到容器的/run/secrets/目录下。
当然,你也可以通过--secret参数,把密码挂载到容器的指定目录下:
--secret source=sample-secret,target=/run/my-secrets/api-secret-key

你可能感兴趣的:(docker入门(10)--零中断部署)