Docker Swarm集群

| 分类 docker  | 标签 docker  swarm  浏览次数: -

环境信息

  • ubuntu1: 192.168.1.7 (swarm-manager)
  • ubuntu2: 192.168.1.8 (swarm-work1)
  • ubuntu3: 192.168.1.9 (swarm-work2)

swarm-manager上创建swarm

  • 获取当前机器IP
ip a | grep "inet " | grep -v "127.0.0.1" | awk '{print $2}' | cut -d "/" -f1 | head -n 1
  • 创建
docker swarm init --advertise-addr $(ip a | grep "inet " | grep -v "127.0.0.1" | awk '{print $2}' | cut -d "/" -f1 | head -n 1)

--advertise-addr: 指定与其他node通信的地址

  • 查看当前swarm的node
docker node ls
  • 把swarm-work1加入到swarm中

复制刚刚创建时提示的命令,在两个work节点执行

docker swarm join --token SWMTKN-1-4ma185sbk9umfk9ju0qnt88yrj8wxidk24ap9wf689xnxst4pe-7tw50gu7asl76xnbh0x1osptj 192.168.1.7:2377

若刚刚提示的命令被刷掉了,可以通过下面的命令进行查看

docker swarm join-token worker
  • 把swarm-work1从swarm中删除
docker swarm leave

运行service

  • 在manager节点创建
docker service create --name web_server httpd
  • 查看swarm中的service
docker service ls

REPLICAS 显示当前副本信息,0/1 的意思是 web_server 这个 service 期望的容器副本数量为 1,目前已经启动的副本数量为 0。也就是当前 service 还没有部署完成。

  • 查看 service 每个副本的状态
docker service ps web_server

service伸缩

  • 增加副本数
docker service scale web_server=5

默认配置下manager node 也是 worker node,所以swarm-manager上也会运行副本。如果不希望在manager上运行service,可以执行以下命令

docker node update --availability drain $(hostname)

Drain 表示 swarm-manager 已经不负责运行 service

  • 减少副本数
docker service scale web_server=3

failover特性

对ubuntu2进行关机重启,关机后副本会被调度到其它节点

shutdown -r now

访问Service

恢复干净的环境,重新部署 web_server

  • 删除web_server
docker service rm web_server
  • 创建两个副本
docker service create --name web_server --replicas=2 httpd
  • 查看服务情况
docker service ps web_server
  • 查询副本1所在主机(ubuntu2)上容器IP
docker inspect $(docker ps | grep -o -E "web_server\.[0-9]+\.\w+") | grep '"IPAddress"' | head -n 1 | grep -o -E "[0-9\.]+"

curl 172.17.0.2

说明在同一主机内是可以正常访问的

外部访问

  • 将 service 暴露外部访问
docker service update --publish-add 8080:80 web_server

在创建时可以直接指定 --publish-add 参数进行暴露

docker service create --name web_server --publish 8080:80 --replicas=2 httpd
  • 测试
curl 192.168.1.7:8080
curl 192.168.1.8:8080
curl 192.168.1.9:8080
curl 127.0.0.1:8080

测试发现,即使是没有运行副本的节点,其service也是能正常访问的。这个功能叫做 routing mesh.

routing mesh

  • ingress 网络

当我们应用 --publish-add 8080:80 时,swarm会重新配置service

docker network ls

ingress 网络是 swarm 创建时 Docker 为自动我们创建的,swarm 中的每个 node 都能使用 ingress

服务发现

一种实现方法是将所有 service 都 publish 出去,然后通过 routing mesh 访问。但明显的缺点是把 memcached 和 mysql 等暴露到外网,增加了安全隐患。

如果不 publish,那么 swarm 就要提供一种机制,能够:

  • 1.让 service 通过简单的方法访问到其他 service。
  • 2.当 service 副本的 IP 发生变化时,不会影响访问该 service 的其他 service。
  • 3.当 service 的副本数发生变化时,不会影响访问该 service 的其他 service。

  • 准备镜像

需要在所有work节点都执行,管理节点不需要,因为已经不分配service

docker pull busybox:1.28.3
docker pull httpd:2.4.34
  • 创建 overlay 网络

要使用服务发现,需要相互通信的 service 必须属于同一个 overlay 网络,所以我们先得创建一个新的 overlay 网络。

docker network create --driver overlay myapp_net
  • 部署service到overlay
docker service create --name my_web --replicas=3 --network myapp_net httpd:2.4.34
  • 部署个busybox进行测试,挂载到同一个overlay网络
docker service create --name test --network myapp_net busybox:1.28.3 sleep 10000000
  • 验证

查看 test 所在节点

docker service ps test

登录test所在节点,在容器test中ping my_web

docker exec $(docker ps -aq -f name=test.1) ping -c 3 my_web

查看每个副本的IP

docker exec $(docker ps -aq -f name=test.1) nslookup tasks.my_web

滚动更新

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

docker service update --image httpd:2.4.35 my_web

--image: 指定新的镜像

更新步骤如下:

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

新开终端查看更新过程

watch -n 1 'docker service ps my_web'

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

docker service update --replicas 6 --update-parallelism 2 --update-delay 1m30s my_web

service 增加到六个副本,每次更新两个副本,间隔时间一分半钟。

查看service配置

docker service inspect --pretty my_web

更新效果不理想,可以进行回滚

docker service update --rollback my_web

注意,--rollback 只能回滚到上一次执行 docker service update 之前的状态,并不能无限制地回滚

swarm存储数据

  • 1.打包在容器里。

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

  • 2.数据放在 Docker 主机的本地目录中,通过 volume 映射到容器里。

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

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

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

准备环境

参考选择Rex-Raydriver小结,在所有节点都安装部署Rex-Ray,并使用VirtualBox backend

创建service

1.创建service

docker service create --name my_web \
       --publish 8080:80 \
       --mount "type=volume,volume-driver=rexray,source=web_data,target=/usr/local/apache2/htdocs" \
       httpd:2.4.34
  • --mount: 指定数据卷的 volume-driver 为 rexray。
  • source: 指定数据卷的名字为 web_data,如果不存在,则会新建。
  • target: 指定将数据卷 mount 到每个副本容器的 /usr/local/apache2/htdocs,即存放静态页面的目录。

2.访问service

ubuntu2@root  ~ curl http://127.0.0.1:8080
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /
on this server.<br />
</p>
</body></html>

3.修改文件权限

ubuntu2@root  ~ docker exec -it $(docker ps | grep -o -E "my_web\.[0-9]+\.\w+") sh
# ls -ld /usr/local/apache2/htdocs
drwxr-xr-x 2 root www-data 4096 Sep 25 05:51 /usr/local/apache2/htdocs
# chmod 755 /usr/local/apache2/htdocs
# exit
ubuntu2@root  ~

4.再次访问

ubuntu2@root  ~ curl http://127.0.0.1:8080
<html><body><h1>It works!</h1></body></html>
ubuntu2@root  ~

Scale Up

增加一个副本

docker service update --replicas 2 my_web

理想的结果应该是:swarm 在 另一个work节点 上启动第二个副本,同时也将挂载 volume my_web

ubuntu2@root  ~ docker service ps my_web
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE             ERROR                              PORTS
1ybq9i6jmhy6        my_web.1            httpd:2.4.34        ubuntu3             Running             Running 2 minutes ago
sqdmdijn17a4        my_web.2            httpd:2.4.34        ubuntu3             Running             Running 5 seconds ago
yg20chlchhyo         \_ my_web.2        httpd:2.4.34        ubuntu2             Shutdown            Rejected 15 seconds ago   "VolumeDriver.Mount: docker-le…"
ow8i4s24ftpe         \_ my_web.2        httpd:2.4.34        ubuntu2             Shutdown            Rejected 20 seconds ago   "VolumeDriver.Mount: docker-le…"
ra5sp8eaxz6o         \_ my_web.2        httpd:2.4.34        ubuntu2             Shutdown            Rejected 25 seconds ago   "VolumeDriver.Mount: docker-le…"
vovdfewjxwct         \_ my_web.2        httpd:2.4.34        ubuntu2             Shutdown            Rejected 30 seconds ago   "VolumeDriver.Mount: docker-le…"

出现了一点复杂的状况:

  • 1.swarm 首先尝试在 ubuntu2 上启动第二个副本,但在 mount volume 失败。
  • 2.重试了三次都失败了。
  • 3.最后在 ubuntu3 成功启动第二个副本。

mount 失败的原因是:以 VirtualBox 为 backend 的 Rex-Ray volume 不支持同时 attach 到多个 Host。

需要注意:这实际上是 VirtualBox 的限制,而非 Rex-Ray。如果 backend 选择 Ceph RBD 就没有这个问题。

更新Volume

  • 需要在my_web运行的节点上执行
echo "Hello Rex-Ray $(date +'%F %T')! " > /var/lib/rexray/volumes/web_data/data/index.html

Failover

现在模拟故障情况。shutdown 节点 ubuntu3,过一会,所有副本都会迁移到 ubuntu2

ubuntu2@root  ~ docker service ps my_web
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE             ERROR                              PORTS
w2pgldrvf398        my_web.1            httpd:2.4.34        ubuntu2             Running             Running 27 seconds ago
jjrtiy0epbs6         \_ my_web.1        httpd:2.4.34        ubuntu2             Shutdown            Rejected 37 seconds ago   "VolumeDriver.Mount: docker-le…"
1ybq9i6jmhy6         \_ my_web.1        httpd:2.4.34        ubuntu3             Shutdown            Running 50 seconds ago
ih3n786q22oz        my_web.2            httpd:2.4.34        ubuntu2             Running             Running 31 seconds ago
sqdmdijn17a4         \_ my_web.2        httpd:2.4.34        ubuntu3             Shutdown            Running 50 seconds ago
yg20chlchhyo         \_ my_web.2        httpd:2.4.34        ubuntu2             Shutdown            Rejected 10 minutes ago   "VolumeDriver.Mount: docker-le…"
ow8i4s24ftpe         \_ my_web.2        httpd:2.4.34        ubuntu2             Shutdown            Rejected 10 minutes ago   "VolumeDriver.Mount: docker-le…"
ra5sp8eaxz6o         \_ my_web.2        httpd:2.4.34        ubuntu2             Shutdown            Rejected 10 minutes ago   "VolumeDriver.Mount: docker-le…"
ubuntu2@root  ~

参考


上一篇 MySQL索引     下一篇 持续学习docker(六)-Volume
目录导航