Dockers Compose 可以非常方便的实现单机多容器应用的部署和管理,甚至可以通过 —scale 参数实现水平扩展。但是对应多机之间容器的部署和管理就需要用到 Swarm。
Swarm 是Docker 官方提供的集群管理工具,其主要作用是把若干台 Docker 主机抽象为一个整体,并且通过一个入口统一管理这些 Docker 主机上的各种 Docker 资源。

基础架构

节点

Swarm 是一种集群架构, 集群中包含 Manager 和 Worker 两类节点(Node)。

  • Manager:是管理节点,管理 cluster 的状态。通过 Manager 节点去部署service;
  • Worker:是工作节点,manager在水平扩展 service 数量时,会将 service 平均分配至每个 Worker 节点上面。Worker节点不具备管理功能。

Docker Swarm 容器编排 - 图1

  • Manager 节点的数据存储在一个内置分布式存储数据库中( Internal distributed state store ),不同的 Manager 之间通过 Raft 协议同步数据,Raft 协议能保证 Manager 节点的数据是对称的。
  • Worker 节点之间通过 Gossip 网络同步数据。

    服务和任务

    任务(Task) 是 Swarm 中的最小调度单位,目前来说就是一个单一的容器,服务(Service)是指一组任务的集合,服务定义了任务的属性。
    服务有两种模式:

  • replicated:按照一定规则在各个节点运行指定个数的任务,Service 可以水平扩展

  • global:每个节点上运行一个任务 ,Service 不可以水平扩展

两种可以模式通过 docker service create 的 —mode 参数指定。
容器、任务、服务的关系

Docker Swarm 容器编排 - 图2

服务的创建和调度流程
Docker Swarm 容器编排 - 图3

基本操作

搭建实验环境

实验环境:创建一个三个节点的 swarm 集群

  1. # 初始化一个 Manager 节点
  2. docker swarm init --advertise-addr=192.168.240.119
  3. # 查看加入集群命令
  4. docker swarm join-token worker/manager
  5. # worker 节点
  6. docker swarm join --token SWMTKN-1-4mrd0oqwl9ch3ygdwwhglsto9wbrpvvvus7rs8t57c6ktaa34m-6m4xy67hortwmqd420yu8xt9d 192.168.240.119:2377
  7. # manager 节点
  8. docker swarm join --token SWMTKN-1-4mrd0oqwl9ch3ygdwwhglsto9wbrpvvvus7rs8t57c6ktaa34m-53x7qw7leybbfbhqxusaskq97 192.168.240.119:2377
  9. # 离开集群
  10. docker swarm leave
  11. # 查看集群中节点
  12. docker node ls

service 的创建和水平扩展

  1. # 创建一个 service
  2. docker service create -d --name test busybox /bin/sh -c "while true; do sleep 3600; done"
  3. # 进入 service 中的某个容器
  4. docker exec -it test sh
  5. # 查看 service 中的容器
  6. docker service ps test
  7. # 水平扩展,servie 中的某个容器 down 掉了之后,会自动启动一个新的容器
  8. docker service scale test=5
  9. # 删除某个 service
  10. docker service rm test

service 部署 wordpress

  1. # 部署 mysql
  2. docker service create -d --name mysql --mount type=volume,source=mysql,destination=/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=wordpress --network demo mysql:5.7
  3. # 部署 wordpress
  4. docker service create -d --name wordpress -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_PASSWORD=root --network demo -p 8080:80 wordpress

集群服务间通信

实验:创建两个服务,测试服务间通信情况

  1. # 创建 service test1
  2. docker service create -d --name test1 --network demo busybox:1.28.3 /bin/sh -c "while true; do sleep 3600; done"
  3. # 创建 service test2
  4. docker service create -d --name test2 --network demo busybox:1.28.3 /bin/sh -c "while true; do sleep 3600; done"
  5. # 扩展 service test2
  6. docker service scale test2=3
  7. # 查看 test1 部署在哪个节点
  8. docker service ps test1
  9. # 进入 test1 中的容器
  10. docker exec -it sh
  11. # 测试 ping 和 nslookup
  12. ping test2
  13. nslookup test2
  14. nslookup tasks.test2
  15. # 结论
  16. Swarm 模式下 Service 之间的通信是通过 VIP (虚拟IP) 实现的

注意:上面两个服务能够通信,是因为他们在同一个网络下,不同网络下的服务是无法直接通信的。
每个服务都有一个 虚拟的 IP 地址,并且该 IP 地址映射到与该服务关联的多个容器的 IP 地址。在这种情况下,与服务关联的服务 IP 不会改变,即使与该服务关联的容器挂掉并重新启动。
Docker Swarm 容器编排 - 图4
在上面的例子中,总共有两个服务 myservice 和 client,其中 myservice 有两个容器,这两个服务在同一个网络中。在 client 里针对 docker.com 和 myservice 各执行了一个 curl 操作,下面是执行的流程:

  • 首先会对DNS 查询进行初始化
  • 容器内置的域名解析器在 127.0.0.11:53 拦截到这个 DNS 查询请求,并把请求转发到宿主机上 Docker 引擎的 DNS 服务中
  • myservice 被解析成服务对应的 VIP,在接下来的 内部负载均衡阶段再被解析成一个具体容器的IP地址。如果是 myservice 是一个容器名称这一步会直接解析成容器对应的 IP 地址。
  • docker.com 在 mynet 网络上不能被解析成服务,所以这个请求被转发到配置好的默认DNS服务器上

    ingress network

    初始化或加入 Swarm 集群时会自动创建 ingress 网络, ingress 网络是一个特殊的 overlay 网络,用于服务节点间的负载均衡。当任何 Swarm 节点在发布的端口上接收到请求时,它将该请求交给一个名为 IPVS 的模块。IPVS 跟踪参与该服务的所有容器的IP地址,并将请求转发到其中某一个容器上。
    Docker Swarm 容器编排 - 图5

    Docker Stack 多服务集群部署

    部署 Wordpress ```yaml

    docker-compose.yml

    version: ‘3’

services:

web: image: wordpress ports:

  1. - 8080:80
  2. environment:
  3. WORDPRESS_DB_HOST: mysql
  4. WORDPRESS_DB_PASSWORD: root
  5. networks:
  6. - demo
  7. depends_on:
  8. - mysql
  9. deploy:
  10. mode: replicated
  11. replicas: 3
  12. restart_policy:
  13. condition: on-failure
  14. delay: 5s
  15. max_attempts: 3
  16. update_config:
  17. parallelism: 1
  18. delay: 10s

mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: wordpress volumes:

  1. - mysql-data:/var/lib/mysql
  2. networks:
  3. - demo
  4. deploy:
  5. mode: global
  6. placement:
  7. constraints:
  8. - node.role == manager

volumes: mysql-data:

networks: demo: driver: overlay

部署

docker stack deploy wordpress -c=docker-compose.yml # -c 等价于 —compose-file

删除

docker stack rm wordpress

查看 stack 下的服务

docker stack services wordpress

  1. <a name="UcPH6"></a>
  2. ## Docker Secret
  3. Docker 中的 Secret 包含:
  4. - 用户名、密码
  5. - SSH Key
  6. - TLS 认证
  7. - 任何不想让别人看到的数据
  8. <a name="mRgNN"></a>
  9. ### Secret 管理和使用
  10. - Secret 存储在 Swram Manager 节点的 Raft database 中(数据默认是加密的)
  11. - Secret 可以 assign 给一个 **service**,这个 service 就能使用这个 secret
  12. - **在 container 内部 Secret 看起来像文件,但实际是存在内存中的**
  13. ```bash
  14. # password.txt
  15. a1234567
  16. # 从文件创建 secret
  17. docker secret create pwd password.txt
  18. # 从标准输入创建 secret
  19. echo "admin" | docker secret create pwd2 -
  20. # 查看当前 secret
  21. docker secret ls
  22. # 创建一个 service 并传入 secret
  23. docker service create -d --name test --secret pwd busybox /bin/sh -c "while true; do sleep 3600; done"
  24. # 进入容器中
  25. docker exec -it 8224bbd0d8cc sh
  26. # 进入容器中 secret 存在的目录
  27. cd /run/secrets
  28. # 查看 secret
  29. cat pwd # a1234567
  30. # 创建一个 mysql,通过 secret 指定 root 用户的密码
  31. docker service create -d --name db --secret pwd2 -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/pwd2 mysql:5.7

Secret 在 Stack 中的使用

  1. # docker-compose.yml
  2. version: '3.6'
  3. services:
  4. web:
  5. image: wordpress
  6. ports:
  7. - 8080:80
  8. secrets:
  9. - db-pw
  10. environment:
  11. WORDPRESS_DB_HOST: mysql
  12. WORDPRESS_DB_PASSWORD: /run/secrets/db-pw
  13. networks:
  14. - demo
  15. depends_on:
  16. - mysql
  17. deploy:
  18. mode: replicated
  19. replicas: 3
  20. restart_policy:
  21. condition: on-failure
  22. delay: 5s
  23. max_attempts: 3
  24. update_config:
  25. parallelism: 1
  26. delay: 10s
  27. mysql:
  28. image: mysql:5.7
  29. secrets:
  30. - db-pw
  31. environment:
  32. MYSQL_ROOT_PASSWORD: /run/secrets/db-pw
  33. MYSQL_DATABASE: wordpress
  34. volumes:
  35. - mysql-data:/var/lib/mysql
  36. networks:
  37. - demo
  38. deploy:
  39. mode: global
  40. placement:
  41. constraints:
  42. - node.role == manager
  43. volumes:
  44. mysql-data:
  45. networks:
  46. demo:
  47. driver: overlay
  48. # 不建议在这里指定 secrets 参数,建议创建好了 secret 之后在创建服务
  49. secrets:
  50. db-pw:
  51. file: ./password.txt
  52. # 部署
  53. docker stack deploy wordpress -c=docker-compose.yml # -c 等价于 --compose-file
  54. # 删除
  55. docker stack rm wordpress
  56. # 查看 stack 下的服务
  57. docker stack services wordpress

注意:版本号小于 3.1 会报错:secrets Additional property secrets is not allowed