继续使用上个文档中的环境

滚动更新service镜像版本

滚动更新降低了应用更新的风险,如果某个副本更新失败,整个更新将暂停,其他副本则可以继续提供服务。同时,在更新的过程中,总是有副本在运行的,因此也保证了业务的连续性。

下面我们将部署3个副本的httpd,镜像使用 httpd:2.4.37,然后将其更新到 httpd:2.4.38。

创建service

[root@swarm-manager ~]# docker service create --name my_web --replicas 3 httpd:2.4.37
vfvae5xw4wd9qovd8ih0uhefg
overall progress: 3 out of 3 tasks 
1/3: running   
2/3: running   
3/3: running   
verify: Service converged

滚动更新

[root@swarm-manager ~]# docker service update --image httpd:2.4.38 my_web
my_web
overall progress: 3 out of 3 tasks 
1/3: running   
2/3: running   
3/3: running   
verify: Service converged 

Swarm 将按照如下步骤执行滚动更新:

  1. 停止第一个副本。
  2. 调度任务,选择 worker node。
  3. 在 worker 上用新的镜像启动副本。
  4. 如果副本(容器)运行成功,继续更新下一个副本;如果失败,暂停整个更新过程。

docker service ps 查看更新结果。

2.4.37的都被停掉了

[root@swarm-manager ~]# docker service ps my_web 
ID             NAME            IMAGE         
mfpvk4kqnkft   my_web.1        httpd:2.4.38    
qniygmr79yuu    \_ my_web.1    httpd:2.4.37     
y2se4lfu7jva   my_web.2        httpd:2.4.38           
cqq7ge9lmblc    \_ my_web.2    httpd:2.4.37             
261lhqli5xa5   my_web.3        httpd:2.4.38              
fwm542b6z8no    \_ my_web.3    httpd:2.4.37  

默认配置下,Swarm 一次只更新一个副本,并且两个副本之间没有等待时间。我们可以通过 –update-parallelism 设置并行更新的副本数目,通过 –update-delay 指定滚动更新的间隔时间。

修改my_web的service的配置为以下,先将副本扩展为6个与

[root@swarm-manager ~]# docker service update --replicas 6 \
--update-parallelism 2 --update-delay 1m30s my_web
# 释义
--replicas 6:将副本更新为6个
--update-parallelism 2:更新时两个副本一起更新
--update-delay 1m30s:更新2个结束后,等待1分30s

查看service的当前配置

[root@swarm-manager ~]# docker service inspect --pretty my_web 
ID:        vfvae5xw4wd9qovd8ih0uhefg
Name:        my_web
Service Mode:    Replicated
 Replicas:    6   # 更新6个副本
UpdateStatus:
 State:        updating
 Started:    2 minutes ago
 Message:    update in progress
Placement:
UpdateConfig:
 Parallelism:    2   # 一次更新的副本数量
 Delay:        1m30s  # 更新间隔
 ...

再次进行更新时,就会根据以上的配置来进行更新

[root@swarm-manager ~]# docker service update --image  httpd:latest my_web
my_web
overall progress: 6 out of 6 tasks 
1/6: running   
2/6: running   
3/6: running   
4/6: running   
5/6: running   
6/6: running   
verify: Service converged

更新之后查看镜像版本,旧版本的都已停用,只有新版本在运行

[root@swarm-manager ~]# docker service ps my_web 
ID                  NAME                IMAGE                
k62is6b883jo        my_web.1            httpd:latest    
mfpvk4kqnkft         \_ my_web.1        httpd:2.4.38    
qniygmr79yuu         \_ my_web.1        httpd:2.4.37    
ntgoqpzvw3ay        my_web.2            httpd:latest    
y2se4lfu7jva         \_ my_web.2        httpd:2.4.38    
cqq7ge9lmblc         \_ my_web.2        httpd:2.4.37    
rp7n40xayqkr        my_web.3            httpd:latest    
261lhqli5xa5         \_ my_web.3        httpd:2.4.38    
fwm542b6z8no         \_ my_web.3        httpd:2.4.37    
d2rlqaexzh49        my_web.4            httpd:latest    
7fyxrhoscvlj         \_ my_web.4        httpd:2.4.38    
jdy1dvp3a4vv        my_web.5            httpd:latest    
6525qpumi6h9         \_ my_web.5        httpd:2.4.38    
jc5j7yvo965n        my_web.6            httpd:latest
7t7qy2boyjyp         \_ my_web.6        httpd:2.4.38

回滚service镜像版本

Swarm 还有个方便的功能是回滚,如果更新后效果不理想,可以通过 –rollback 快速恢复到更新之前的状态。

回滚操作仅支持,向上一次回滚,持续操作会还原到回滚之前的版本

[root@swarm-manager ~]# docker service update --rollback my_web
rollback: manually requested rollback 
overall progress: rolling back update: 6 out of 6 tasks 
1/6: running   
2/6: running   
3/6: running   
4/6: running   
5/6: running   
6/6: running   
verify: Service converged

更新之后查看镜像版本,可以看到现在运行的版本是上一次更新到的版本2.4.38

[root@swarm-manager ~]# docker service ps my_web 
ID                  NAME                IMAGE         
7lfpxrfiutjj        my_web.1            httpd:2.4.38  
k62is6b883jo         \_ my_web.1        httpd:latest  
mfpvk4kqnkft         \_ my_web.1        httpd:2.4.38  
qniygmr79yuu         \_ my_web.1        httpd:2.4.37  
veb8g6r2lir1        my_web.2            httpd:2.4.38  
ntgoqpzvw3ay         \_ my_web.2        httpd:latest  
y2se4lfu7jva         \_ my_web.2        httpd:2.4.38  
cqq7ge9lmblc         \_ my_web.2        httpd:2.4.37  
b1soeccx0e39        my_web.3            httpd:2.4.38  
rp7n40xayqkr         \_ my_web.3        httpd:latest  
261lhqli5xa5         \_ my_web.3        httpd:2.4.38  
fwm542b6z8no         \_ my_web.3        httpd:2.4.37  
p3059ib4rado        my_web.4            httpd:2.4.38  
d2rlqaexzh49         \_ my_web.4        httpd:latest  
7fyxrhoscvlj         \_ my_web.4        httpd:2.4.38  
4gitr1l39me8        my_web.5            httpd:2.4.38  
jdy1dvp3a4vv         \_ my_web.5        httpd:latest  
6525qpumi6h9         \_ my_web.5        httpd:2.4.38  
tfoptj9sc28r        my_web.6            httpd:2.4.38  
jc5j7yvo965n         \_ my_web.6        httpd:latest  
7t7qy2boyjyp         \_ my_web.6        httpd:2.4.38  

管理存储数据

service 的容器副本会进行扩展或者伸缩,会 failover,会在不同的主机上创建和销毁,这就引出一个问题,如果 service 有要管理的数据,那么这些数据应该如何存放呢?

failover:就是前面说到过的状态协调,当某个集群主机故障后,swarm将会在其他主机将在故障机中运行过的副本,运行在其他集群主机中,就造成了上面所说的,在不同主机上创建和销毁。

解决方法

选项一:打包在容器里。

显然不行。除非数据不会发生变化,否则,如何在多个副本直接保持同步呢?

选项二:数据放在 Docker 主机的本地目录中,通过 volume 映射到容器里。

位于同一个主机的副本倒是能够共享这个 volume,但不同主机中的副本如何同步呢?

选项三:利用 Docker 的 volume driver,由外部 storage provider 管理和提供 volume,所有 Docker 主机 volume 将挂载到各个副本。

显然第三个是最方便管理的,先来看第二个,在docker service命令中是没有--volume选项的。但是也有使用挂载的选项命令--mount

映射目录

bind mount

例:运行三个副本的web

创建本地映射目录,如上所说使用映射目录的方式同样不能同步到其他主机,所以每台主机都需要创建目录

[root@swarm-manager ~]# mkdir htdocs
[root@node1 ~]# mkdir htdocs
[root@node2 ~]# mkdir htdocs

创建首页文件,同样三台都需要做

[root@swarm-manager ~]# echo "FeiYi" > htdocs/index.html
[root@node1 ~]# echo "FeiYi" > htdocs/index.html
[root@node2 ~]# echo "FeiYi" > htdocs/index.html

创建运行副本

swarm-manager

[root@swarm-manager ~]# docker service create --name web_clu --replicas 3 \
--mount type=bind,src=/root/htdocs,dst=/usr/local/apache2/htdocs,ro \
-p 80:80 httpd:latest 

参数释义:

–mount:表示进行目录挂载

type=:表示挂载目录的类型,可以是bind或者volume,代表的bind mount和manage volume

src=:本地路径,自己创建的目录

dst=:容器内路径,将此路径挂载到本地路径,可以使用逗号加权限ro/rw

访问验证

[root@swarm-manager ~]# curl 192.168.1.11
FeiYi
[root@swarm-manager ~]# curl 192.168.1.12
FeiYi
[root@swarm-manager ~]# curl 192.168.1.13
FeiYi

修改其中一台的文件内容,再次验证

确实只修改一台不会同步目录,依旧是进行了每台主机中副本的轮询

[root@swarm-manager ~]# echo MuPei > htdocs/index.html 
[root@swarm-manager ~]# curl 192.168.1.11
MuPei
[root@swarm-manager ~]# curl 192.168.1.11
FeiYi
[root@swarm-manager ~]# curl 192.168.1.11
FeiYi
[root@swarm-manager ~]# curl 192.168.1.11
MuPei

删除service

[root@swarm-manager ~]# docker service rm web_clu 
web_clu

manage volume

使用manage volume只需要指定容器内目录即可,将会映射到本地的docker安装目录下,并且使用容器的id号命名文件目录,因为目录太长,使用src指定一个目录名,方便修改

[root@swarm-manager ~]# docker service create --name web_clu --replicas 3 \
--mount type=volume,src=html,dst=/usr/local/apache2/htdocs \
-p 80:80 httpd:latest

访问验证

[root@swarm-manager ~]# curl 192.168.1.11
<html><body><h1>It works!</h1></body></html>
[root@swarm-manager ~]# curl 192.168.1.12
<html><body><h1>It works!</h1></body></html>
[root@swarm-manager ~]# curl 192.168.1.13
<html><body><h1>It works!</h1></body></html>

找到本地挂载目录

[root@swarm-manager ~]# docker inspect web_clu.1.45b6figyrkrjg9kqjcu13q4di | grep Source
                    "Source": "html",
                "Source": "/var/lib/docker/volumes/html/_data",

修改页面文件,并访问验证,因为只改了一台的文件,所以其他两台还是默认的页面

[root@swarm-manager ~]# echo pjf > /var/lib/docker/volumes/html/_data/index.html 
[root@swarm-manager ~]# curl 192.168.1.11
pjf
[root@swarm-manager ~]# curl 192.168.1.11
<html><body><h1>It works!</h1></body></html>
[root@swarm-manager ~]# curl 192.168.1.11
<html><body><h1>It works!</h1></body></html>

删除service

[root@swarm-manager ~]# docker service rm web_clu 
web_clu

外部应用管理数据(此部分待研究)

volume 不依赖 Docker 主机和容器,生命周期由 storage provider 管理,volume 的高可用和数据有效性也全权由 provider 负责,Docker 只管使用。

Rex-Ray 是开源的容器存储管理解决方案。支持主流的容器编排引擎 Docker Swarm、 Kubernetes 和 Mesos,为容器集群提供自动化的存储编排功能。

Rex-Ray driver的优点

  1. Rex-Ray 是开源的,而且社区活跃。
  2. 支持多种 backend,VirtualBox 的 Virtual Media、Amazon EBS、Ceph RBD、OpenStack Cinder 等。
  3. 支持多种操作系统,Ubuntu、CentOS、RHEL 和 CoreOS。
  4. 支持多种容器编排引擎,Docker Swarm、Kubernetes 和 Mesos。
  5. Rex-Ray 安装使用方法非常简单。

安装Rex-Ray

swarm集群都需要安装

[root@swarm-manager ~]# curl -sSL https://rexray.io/install | sh -s – stable

rexray has been installed to /usr/bin/rexray

REX-Ray
-------
Binary: /usr/bin/rexray
Flavor: client+agent+controller
SemVer: 0.11.4
OsArch: Linux-x86_64
Commit: e7414eaa971b27977d2283f2882825393493179d
Formed: Wed, 16 Jan 2019 00:03:57 CST

编写配置文件

[root@swarm-manager ~]# vim /etc/rexray/config.yml
libstorage:
  service: virtualbox
virtualbox:
  endpoint: http://192.168.1.11:18083
  userName: root
  password: 123qwe
  tls: false
  volumePath: /root/htdocs /usr/local/apache2/htdocs
  controllerName: SATA
  localMachineNameOrId: cjm

配置文件释义

service选择VirtualBox的virtualbox;
endpoint设置为你启动VirtualBox的宿主机加18083端口,这是因为你在宿主机上启动了VirtualBox而虚拟机都是使用桥接网络,所以ip是宿主机的ip;
volumePath是你的第一台虚拟机的存放位置,我的第一台虚拟机是cjm所以位置是这个;
controllerName:设置SATA类型;
localMachineNameOrId是指定的vm的名字。

管理集群主机的副本

在swarm集群下,创建副本的数量,有两种方法,replicasglobal

replicas

Swarm 可以在 service 创建或运行过程中灵活地通过 --replicas 调整容器副本的数量,内部调度器则会根据当前集群的资源使用状况在不同 node 上启停容器,这就是 service 默认的 replicated mode。在此模式下,node 上运行的副本数有多有少,一般情况下,资源更丰富的 node 运行的副本数更多,反之亦然。可以控制资源合理的分配。

此方法前面一直在用,就不在举例了

global

作用是强制在每个 node 上都运行一个且最多一个副本。

此模式特别适合需要运行 daemon 的集群环境。比如要收集所有容器的日志,就可以 global mode 创建 service,在所有 node 上都运行日志收集的容器,即使之后有新的 node 加入,swarm 也会自动在新 node 上启动一副本。

设置global模式只需要一条选项即可--mode global

[root@swarm-manager ~]# docker service create --name web_clu --mode global httpd:latest 
isqfrao2d4ip3sw760z5ruyy1
overall progress: 3 out of 3 tasks 
m8kwla1rw6r3: running   
12dmi9teb730: running   
ivhjsgwkc9vk: running   
verify: Service converged 

因为集群中有三台主机,所以即使没有指定副本数量,仍然运行了三个容器

查看副本所在主机

[root@swarm-manager ~]# docker service ps web_clu 
ID               NAME                                IMAGE               NODE 
lfn9rw92yeng     web_clu.ivhjsgwkc9vkmzrpbz84ef9y6   httpd:latest        node1  
kxai4uukh19l     web_clu.12dmi9teb730erqsej642j9ka   httpd:latest        swarm-manager
oo6mtnpdybu0     web_clu.m8kwla1rw6r3m0koi8cemyukw   httpd:latest        node2         

查看service模式

[root@swarm-manager ~]# docker service inspect web_clu --pretty | grep "Service Mode"
Service Mode:    Global

删除service

[root@swarm-manager ~]# docker service rm web_clu 
web_clu

控制service运行位置(Label)

无论采用 global mode 还是 replicated mode,副本运行在哪些节点都是由 Swarm 决定的,有时候,为了方便管理,会想要将某台主机运行的副本全都是一个服务,这个时候就可以使用label标签。

逻辑上分为两步操作

通过为集群主机定义标签的操作

指定service运行在哪个标签主机上。

label 可以灵活描述 node 的属性,其形式是 key=value,可以进行任意指定label名。

如下:

定义标签

[root@swarm-manager ~]# docker node update --label-add env=test node1
node1
[root@swarm-manager ~]# docker node update --label-add env=prod node2
node2

将node1主机的标签定义为test,测试

node2主机的标签定义为prod,生产

修改标签后通过图形界面同样可以看出来

查看标签

[root@swarm-manager ~]# docker node inspect node1 --pretty 
ID:            ivhjsgwkc9vkmzrpbz84ef9y6
Labels:
 - env=test
 ...

指定service运行的标签

将web_clu的3个副本全都部署在test标签的主机上,也就是node1

--constraint node.labels.env==test:将此次运行的service限制只能部署到标签为test的主机

[root@swarm-manager ~]# docker service create --name web_clu \
--constraint node.labels.env==test \
--replicas 3 -p 80:80 httpd:latest

查看副本所运行的主机

[root@swarm-manager ~]# docker service ps web_clu 
ID                  NAME                IMAGE               NODE   
0bjez7px2qsr        web_clu.1           httpd:latest        node1    
t028ovglr3wg        web_clu.2           httpd:latest        node1   
wrdjo0axkip3        web_clu.3           httpd:latest        node1   

查看web_clu的标签限制

[root@swarm-manager ~]# docker service inspect web_clu --pretty | grep Constraint
 Constraints:    [node.labels.env==test]

标签迁移

比如在测试环境中迁移到生产环境投入使用,就非常适合标签迁移

从刚才的test迁移到prod

# 从test主机删除
[root@swarm-manager ~]# docker service update --constraint-rm node.labels.env==test web_clu
# 添加到prod主机
[root@swarm-manager ~]# docker service update --constraint-add node.labels.env==prod web_clu

删除service

[root@swarm-manager ~]# docker service rm web_clu +
web_clu

健康检查(health-check)

容器状态是 UP 的,应用也不一定是健康的

docker 只能从容器启动进程的返回代码判断其状态,而对于容器内部应用的运行情况基本没有了解。

启动进程就是在构建镜像时,最后的CMD执行的那个进程。

执行 docker run 命令时,通常会根据 Dockerfile 中的 CMD 或 ENTRYPOINT 启动一个进程,这个进程的状态就是 docker ps STATUS 列显示容器的状态。

即使容器状态是 UP,也不能保证应用没有问题。web server 虽然没有崩溃,但如果总是返回 HTTP 500 – Internal Server Error ,对应用来说这就是很严重的故障。

这是就可以通过健康检查来验证应用是否好用健康

Docker 支持的 Health Check 可以是任何一个单独的命令,Docker 会在容器中执行该命令,如果返回 0,容器被认为是 healthy,如果返回 1,则为 unhealthy。

对于提供 HTTP 服务接口的应用,常用的 Health Check 是通过 curl 检查 HTTP 状态码,比如:

curl --fail http://192.168.1.11 || exit 1

表示如果访问时报错,则执行exit,并返回1,代表此网站服务是不健康的。

除了curl,很多命令也可以进行这样的检查,只要命令执行失败,就表示不健康,如:

cat /tmp/cyj || exit 1

如果没有该文件,则不健康,有则健康

在swarm中也可以使用这样的机制,比如判断index.html是否存在,不存在则不健康

如:

--health-interval 5s:表示每5s检查一次

--health-timeout 3s:超过3s没有回应则重试

--health-cmd:进行检查的命令

--health-retries 3:没有回应的重试次数

[root@swarm-manager ~]# docker service create -td --name web_clu -p 80:80 \
--health-interval 5s --health-timeout 3s \
--health-cmd "cat /usr/local/apache2/htdocs/index.html || exit 1" httpd:latest

查看健康状态

STATUS的值为healthy,表示健康

[root@swarm-manager ~]# docker ps
CONTAINER ID        IMAGE                      COMMAND              CREATED             STATUS                   
e22424013d88        httpd:latest               "httpd-foreground"   16 seconds ago      Up 14 seconds (healthy) 
2078a41d790a        dockersamples/visualizer   "npm start"          8 hours ago         Up 8 hours (healthy)     

再运行一个不健康的容器

[root@swarm-manager ~]# docker service create -td  --name web_clu1 -p 8080:80 \
> --health-interval 5s --health-timeout 3s \
> --health-retries 3 --health-cmd "cat /usr/local/apache2/htdocs/saffa" httpd:latest

docker service ps web_clu1查看该副本在哪台节点运行

等待重试三次之后,查看健康状态,状态为unhealthy,不健康

但是好像一直在重启,貌似是个bug,并不是三次之后就会停止

[root@node1 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS                     
0ae409e7e90e        httpd:latest        "httpd-foreground"   25 seconds ago      Up 19 seconds (unhealthy) 

删除service

[root@swarm-manager ~]# docker service rm web_clu web_clu1
web_clu
web_clu1

secret安全机制

我们经常要向容器传递敏感信息,最常见的莫过于密码了

明文运行

如:

[root@swarm-manager ~]#  docker  run --name mysql -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123.com -d mysql

进入容器并登录

[root@swarm-manager ~]# docker exec -it mysql /bin/bash
root@f1498eeadeb6:/# mysql -uroot -p123.com

在启动 MySQL 容器时我们通过环境变量 MYSQL_ROOT_PASSWORD 设置了 MySQL 的管理员密码。不过密码是以明文的形式写在 docker run 命令中,有潜在的安全隐患。

为了解决这个问题,docker swarm 提供了 secret 机制,允许将敏感信息加密后保存到 secret 中,用户可以指定哪些容器可以使用此 secret。

secret启动MySQL容器

secret其实就是将不想让别人知道的东西保存或者加密

secret只能在swarm集群的service中使用。

创建密码文件

[root@swarm-manager ~]# echo '123.com' | docker secret create my_secret_data -
14sbpchk09j4nzixf146hxe5e

查看密码文件

[root@swarm-manager ~]# docker secret ls
ID                          NAME              
14sbpchk09j4nzixf146hxe5e   my_secret_data     

启动mysql并指定该文件作为密码

# 先将之前运行的mysql删除
[root@swarm-manager ~]# docker rm -f mysql 
mysql
# 启动新的mysql service
[root@swarm-manager ~]# docker service create --name mysql \
--secret source=my_secret_data,target=mysql_root_password \
-e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \
-p 3306:3306 mysql

source 指定容器使用 secret 后,secret 会被解密并存放到容器的文件系统中,默认位置为 /run/secrets/,source=my_secret_data,target=mysql_root_password 的作用就是指定使用 secret my_secret_data,然后把容器解密后的内容保存到容器 /run/secrets/mysql_root_password 文件中,文件名称 mysql_root_password 由 target 指定。

环境变量 MYSQL_ROOT_PASSWORD_FILE 指定从 /run/secrets/mysql_root_password 中读取并设置 MySQL 的管理员密码。

这里存在两个问题

问:在第一步创建 secret 时,不也是使用了明文吗?这跟在环境变量中直接指定密码有什么不同呢?

答:在我们的例子中创建 secret 和使用 secret 是分开完成的,其好处是将密码和容器解耦合。secret 可以由专人(比如管理员)创建,而运行容器的用户只需使用 secret 而不需要知道 secret 的内容。也就是说,例子中的这两个步骤可以由不同的人在不同的时间完成。

问:secret 是以文件的形式 mount 到容器中,容器怎么知道去哪里读取 secret 呢?
答:这需要 image 的支持。如果 image 希望它部署出来的容器能够从 secret 中读取数据,那么此 image 就应该提供一种方式,让用户能够指定 secret 的位置。最常用的方法就是通过环境变量,Docker 的很多官方 image 都是采用这种方式。比如 MySQL 镜像同时提供了 MYSQL_ROOT_PASSWORD 和 MYSQL_ROOT_PASSWORD_FILE 两个环境变量。用户可以用 MYSQL_ROOT_PASSWORD 显示地设置管理员密码,也可以通过 MYSQL_ROOT_PASSWORD_FILE 指定 secret 路径。

可以进去容器看一下,这个文件

docker service ps mysql查看运行在哪个节点

[root@swarm-manager ~]# docker exec -it mysql.1.hpgczgs8aryatra1ontq0e01a /bin/bash
# 登录mysql尝试
root@0be9696f84f7:/# mysql -uroot -p123.com  # 成功
# 查看密码被解密后保存的位置
root@0be9696f84f7:/# cat /run/secrets/mysql_root_password 
123.com

删除service和密码文件

[root@swarm-manager ~]# docker service rm mysql 
mysql
[root@swarm-manager ~]# docker secret rm  my_secret_data 
my_secret_data

secret的使用场景

我们可以用 secret 管理任何敏感数据。这些敏感数据是容器在运行时需要的,同时我们不又想将这些数据保存到镜像中。

secret 可用于管理:

  • 用户名和密码。
  • TLS 证书。
  • SSH 秘钥。
  • 其他小于 500 KB 的数据。

secret 只能在 swarm service 中使用。普通容器想使用 secret,可以将其包装成副本数为 1 的 service。

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0