7 Docker Swarm

7.1 Docker Swarm 介绍

💫32 Docker Swarm - 图1

在之前的使用中,所有的操作都是在本地上执行的!

:::color5 到处都使用容器 = 麻烦来了

:::

  • 怎么去管理这么多容器?
  • 怎么能方便的横向扩展?
  • 如果容器down了,怎么能自动恢复?
  • 如何去更新容器而不影响业务?
  • 如何去监控追踪这些容器?
  • 怎么去调度容器的创建?
  • 保护隐私数据?

:::color5 Swarm Mode

:::

💫32 Docker Swarm - 图2

Swarm是Docker公司推出的用来管理docker集群的平台,几乎全部用GO语言来完成的开发的,代码开源在 https://github.com/docker/swarm, 它是将一群Docker宿主机变成一个单一的虚拟主机,Swarm使用标准的Docker API接口作为其前端的访问入口,换言之,各种形式的DockerClient(compose,docker-py等)均可以直接与Swarm通信,甚至Docker本身都可以很容易的与Swarm集成,这大大方便了用户将原本基于单节点的系统移植到Swarm上,同时Swarm内置了对Docker网络插件的支持,用户也很容易的部署跨主机的容器集群服务。

Docker Swarm 和 Docker Compose 一样,都是 Docker 官方容器编排项目,但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,显然 Docker Swarm 会更加适合

从 Docker 1.12.0 版本开始,Docker Swarm 已经包含在 Docker 引擎中(docker swarm),并且已经内置了服务发现工具,我们就不需要像之前一样,再配置 Etcd 或者 Consul 来进行服务发现配置了。

Swarm deamon只是一个调度器(Scheduler)加路由器(router),Swarm自己不运行容器,它只是接受Docker客户端发来的请求,调度适合的节点来运行容器,这就意味着,即使Swarm由于某些原因挂掉了,集群中的节点也会照常运行,放Swarm重新恢复运行之后,他会收集重建集群信息。

:::color5 Docker Swarm Mode Architecture

:::

Reference:Docker Swarm简介fastjson的博客-CSDN博客_docker swam

💫32 Docker Swarm - 图3

  1. Swarm

集群的管理和编排是使用嵌入docker引擎的SwarmKit,可以在docker初始化时启动swarm模式或者加入已存在的swarm

  1. Node

一个节点是docker引擎集群的一个实例。您还可以将其视为Docker节点。您可以在单个物理计算机或云服务器上运行一个或多个节点,但生产群集部署通常包括分布在多个物理和云计算机上的Docker节点。

要将应用程序部署到swarm,请将服务定义提交给 管理器节点。管理器节点将称为任务的工作单元分派 给工作节点。

Manager节点还执行维护所需群集状态所需的编排和集群管理功能。Manager节点选择单个领导者来执行编排任务。

工作节点接收并执行从管理器节点分派的任务。默认情况下,管理器节点还将服务作为工作节点运行,但您可以将它们配置为仅运行管理器任务并且是仅管理器节点。代理程序在每个工作程序节点上运行,并报告分配给它的任务。工作节点向管理器节点通知其分配的任务的当前状态,以便管理器可以维持每个工作者的期望状态。

:::color5 Service 和 Replicas

:::

💫32 Docker Swarm - 图4

  1. Service

一个服务是任务的定义,管理机或工作节点上执行。它是群体系统的中心结构,是用户与群体交互的主要根源。创建服务时,你需要指定要使用的容器镜像。

  1. Task

任务是在docekr容器中执行的命令,Manager节点根据指定数量的任务副本分配任务给worker节点

:::color5 服务创建和调度

:::

💫32 Docker Swarm - 图5

Swarm在调度(scheduler)节点(leader节点)运行容器的时候,会根据指定的策略来计算最适合运行容器的节点,目前支持的策略有:spread, binpack, random.

1)Random

顾名思义,就是随机选择一个Node来运行容器,一般用作调试用,spread和binpack策略会根据各个节点的可用的CPU, RAM以及正在运行的容器的数量来计算应该运行容器的节点。

2)Spread

在同等条件下,Spread策略会选择运行容器最少的那台节点来运行新的容器,binpack策略会选择运行容器最集中的那台机器来运行新的节点。使用Spread策略会使得容器会均衡的分布在集群中的各个节点上运行,一旦一个节点挂掉了只会损失少部分的容器。

3)Binpack

Binpack策略最大化的避免容器碎片化,就是说binpack策略尽可能的把还未使用的节点留给需要更大空间的容器运行,尽可能的把容器运行在一个节点上面。

7.2 Docker Swarm 集群

7.2.1 Nodes Swarm Cluster Setup

范例:部署 Docker 环境

  1. #!/bin/bash
  2. DOCKER_VERSION="20.10.10"
  3. #UBUNTU_DOCKER_VERSION="5:${DOCKER_VERSION}~3-0~`lsb_release -si`-`lsb_release -cs`"
  4. DOCKER_COMPOSE_VERSION=1.29.2
  5. DOCKER_COMPOSE_FILE=docker-compose-Linux-x86_64
  6. COLOR_SUCCESS="echo -e \\033[1;32m"
  7. COLOR_FAILURE="echo -e \\033[1;31m"
  8. END="\033[m"
  9. . /etc/os-release
  10. color () {
  11. RES_COL=60
  12. MOVE_TO_COL="echo -en \\033[${RES_COL}G"
  13. SETCOLOR_SUCCESS="echo -en \\033[1;32m"
  14. SETCOLOR_FAILURE="echo -en \\033[1;31m"
  15. SETCOLOR_WARNING="echo -en \\033[1;33m"
  16. SETCOLOR_NORMAL="echo -en \E[0m"
  17. echo -n "$1" && $MOVE_TO_COL
  18. echo -n "["
  19. if [ $2 = "success" -o $2 = "0" ] ;then
  20. ${SETCOLOR_SUCCESS}
  21. echo -n $" OK "
  22. elif [ $2 = "failure" -o $2 = "1" ] ;then
  23. ${SETCOLOR_FAILURE}
  24. echo -n $"FAILED"
  25. else
  26. ${SETCOLOR_WARNING}
  27. echo -n $"WARNING"
  28. fi
  29. ${SETCOLOR_NORMAL}
  30. echo -n "]"
  31. echo
  32. }
  33. install_docker(){
  34. if [ $ID = "centos" -o $ID = "rocky" ];then
  35. if [ $VERSION_ID = "7" ];then
  36. cat > /etc/yum.repos.d/docker.repo <<EOF
  37. [docker]
  38. name=docker
  39. gpgcheck=0
  40. #baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/
  41. baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/x86_64/stable/
  42. EOF
  43. else
  44. cat > /etc/yum.repos.d/docker.repo <<EOF
  45. [docker]
  46. name=docker
  47. gpgcheck=0
  48. #baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/8/x86_64/stable/
  49. baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/8/x86_64/stable/
  50. EOF
  51. fi
  52. yum clean all
  53. ${COLOR_FAILURE} "Docker有以下版本"${END}
  54. yum list docker-ce --showduplicates
  55. ${COLOR_FAILURE}"5秒后即将安装: docker-"${DOCKER_VERSION}" 版本....."${END}
  56. ${COLOR_FAILURE}"如果想安装其它Docker版本,请按ctrl+c键退出,修改版本再执行"${END}
  57. sleep 5
  58. yum -y install docker-ce-$DOCKER_VERSION docker-ce-cli-$DOCKER_VERSION \
  59. || { color "Base,Extras的yum源失败,请检查yum源配置" 1;exit; }
  60. else
  61. dpkg -s docker-ce &> /dev/null && $COLOR"Docker已安装,退出" 1 && exit
  62. apt update || { color "更新包索引失败" 1 ; exit 1; }
  63. apt -y install apt-transport-https ca-certificates curl software-properties-common || \
  64. { color "安装相关包失败" 1 ; exit 2; }
  65. curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
  66. add-apt-repository "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
  67. apt update
  68. ${COLOR_FAILURE} "Docker有以下版本"${END}
  69. apt-cache madison docker-ce
  70. ${COLOR_FAILURE}"5秒后即将安装: docker-"${UBUNTU_DOCKER_VERSION}" 版本....."${END}
  71. ${COLOR_FAILURE}"如果想安装其它Docker版本,请按ctrl+c键退出,修改版本再执行"${END}
  72. sleep 5
  73. apt -y install docker-ce=${UBUNTU_DOCKER_VERSION} docker-ce-cli=${UBUNTU_DOCKER_VERSION}
  74. fi
  75. if [ $? -eq 0 ];then
  76. color "安装软件包成功" 0
  77. else
  78. color "安装软件包失败,请检查网络配置" 1
  79. exit
  80. fi
  81. mkdir -p /etc/docker
  82. tee /etc/docker/daemon.json <<-'EOF'
  83. {
  84. "registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],
  85. "insecure-registries": ["harbor.kubesphere.com:80"]
  86. }
  87. EOF
  88. systemctl daemon-reload
  89. systemctl enable docker
  90. systemctl restart docker
  91. docker version && color "Docker 安装成功" 0 || color "Docker 安装失败" 1
  92. echo 'alias rmi="docker images -qa|xargs docker rmi -f"' >> ~/.bashrc
  93. echo 'alias rmc="docker ps -qa|xargs docker rm -f"' >> ~/.bashrc
  94. }
  95. install_docker_compose(){
  96. if [ $ID = "centos" -o $ID = "rocky" ];then
  97. ${COLOR_SUCCESS}"开始安装 Docker compose....."${END}
  98. sleep 1
  99. if [ ! -e ${DOCKER_COMPOSE_FILE} ];then
  100. curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/${DOCKER_COMPOSE_FILE} -o /usr/bin/docker-compose
  101. # curl -L https://get.daocloud.io/docker/compose/releases/download/v2.12.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
  102. else
  103. mv ${DOCKER_COMPOSE_FILE} /usr/bin/docker-compose
  104. fi
  105. chmod +x /usr/bin/docker-compose
  106. else
  107. apt -y install docker-compose
  108. fi
  109. if docker-compose --version ;then
  110. ${COLOR_SUCCESS}"Docker Compose 安装完成"${END}
  111. else
  112. ${COLOR_FAILURE}"Docker compose 安装失败"${END}
  113. exit
  114. fi
  115. }
  116. install_docker
  117. install_docker_compose

初始化 Docker Swarm

  1. # 初始化 Master 节点
  2. $ docker swarm init --advertise-addr 10.0.0.101
  3. Swarm initialized: current node (kdl65arb5xhld1s1ogc78gur7) is now a manager.
  4. To add a worker to this swarm, run the following command:
  5. docker swarm join --token SWMTKN-1-5fqnggzu8j0a3hywv9nhl2kl5rmi02yol31djv90c93igua3ey-bnpxxyf1wxuvba8n004qc102v 10.0.0.101:2377
  6. To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
  7. # 加入工作节点
  8. $ docker swarm join --token SWMTKN-1-5fqnggzu8j0a3hywv9nhl2kl5rmi02yol31djv90c93igua3ey-bnpxxyf1wxuvba8n004qc102v 10.0.0.101:2377
  9. # 在Master节点查看节点信息
  10. $ docker node ls
  11. ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
  12. kdl65arb5xhld1s1ogc78gur7 * docker-node01 Ready Active Leader 19.03.11
  13. pzubdmyszq0or4rtk45lzihts docker-node02 Ready Active 19.03.11
  14. dvl2e5upon3bklq77ijzkp100 docker-node03 Ready Active 20.10.10

(可以使用 Docker-Machine 来创建三个节点)

  1. # 创建Master节点(一个节点)
  2. docker-machine create swarm-manager
  3. # 创建Worker节点(两个节点)
  4. docker-machine create swarm-node01
  5. docker-machine create swarm-node02
  6. # 查看各节点的IP地址
  7. docker-machine ls
  8. # 进入到 Master 节点
  9. $ docker-machine ssh swarm-manager
  10. $ docker swarm init --advertise-addr 10.0.0.101
  11. # 进入到 Worker 节点(执行命令类似)
  12. $ docker-machine ssh swarm-node01 & docker-machine ssh swarm-node02
  13. $ docker swarm join --token SWMTKN-1-5fqnggzu8j0a3hywv9nhl2kl5rmi02yol31djv90c93igua3ey-bnpxxyf1wxuvba8n004qc102v 10.0.0.101:2377

7.2.2 Service 的创建和水平扩展

Service 的创建

  1. # 创建一个Service
  2. $ docker service create --name busybox-node busybox sh -c "while true;do sleep 3600;done"
  3. # 查看Service信息
  4. $ docker service ls
  5. ID NAME MODE REPLICAS IMAGE PORTS
  6. dyenfcor78te busybox-node replicated 1/1 busybox:latest
  7. # 查看Service详细信息
  8. $ docker service ps busybox-node
  9. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  10. 7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running about a minute ago
  11. # 在 docker-node03 查看Docker进程信息
  12. $ docker ps
  13. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  14. 3cb69e5b3cc5 busybox:latest "sh -c 'while true;d…" 3 minutes ago Up 3 minutes busybox-node.1.7jfml4o5yklf061bggak4omqc

Service 的水平扩展

  1. # 设置水平扩展
  2. $ docker service scale busybox-node=3
  3. $ docker service ls
  4. ID NAME MODE REPLICAS IMAGE PORTS
  5. dyenfcor78te busybox-node replicated 3/3 busybox:latest
  6. # 平均分配到各个节点中运行
  7. $ docker service ps busybox-node
  8. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  9. 7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running 7 minutes ago
  10. q3w8bdvu9141 busybox-node.2 busybox:latest docker-node02 Running Running 47 seconds ago
  11. pyhxitis9kr3 busybox-node.3 busybox:latest docker-node01 Running Running about a minute ago
  12. # 在docker-node02上删除相应的容器
  13. $ docker rm -f busybox-node.2
  14. # 在Master节点上查看Service 的副本数(过一段时间再次查看)
  15. $ docker service ls
  16. ID NAME MODE REPLICAS IMAGE PORTS
  17. dyenfcor78te busybox-node replicated 2/3 busybox:latest
  18. # 其Docker Service具有自恢复能力
  19. $ docker service ls
  20. ID NAME MODE REPLICAS IMAGE PORTS
  21. dyenfcor78te busybox-node replicated 3/3 busybox:latest
  22. $ docker service ps busybox-node
  23. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  24. 7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running 10 minutes ago
  25. xtl92syb8d01 busybox-node.2 busybox:latest docker-node02 Running Running about a minute ago
  26. q3w8bdvu9141 \_ busybox-node.2 busybox:latest docker-node02 Shutdown Failed about a minute ago "task: non-zero exit (137)"
  27. pyhxitis9kr3 busybox-node.3 busybox:latest docker-node01 Running Running 4 minutes ago

Service 的删除

  1. $ docker service rm busybox-node
  2. # 各节点的Service 的容器会将其删除

7.3 在 Swarm 集群中通过Service 部署 WordPress

创建 MySQL / MariaDB 数据库 Service

  1. # 需要创建一个 Overlay Network
  2. $ docker network create -d overlay demo
  3. $ docker network ls
  4. NETWORK ID NAME DRIVER SCOPE
  5. d0ba97d9a9e1 bridge bridge local
  6. 1u4udx1r0c6p demo overlay swarm
  7. 458e32a2a13c docker_gwbridge bridge local
  8. 0959653f62aa host host local
  9. j59uwl8alp6o ingress overlay swarm
  10. 891c07cd5918 none null local
  11. # 创建MySQL Service
  12. $ docker service create -d --name db \
  13. -e MYSQL_ROOT_PASSWORD=somewordpress \
  14. -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress \
  15. --network demo --mount type=volume,source=mysql-data,destination=/var/lib/mysql \
  16. -e MYSQL_PASSWORD=wordpress mariadb:10.6.4-focal --default-authentication-plugin=mysql_native_password
  17. # 查看 Docker Service 服务信息
  18. $ docker service ls
  19. ID NAME MODE REPLICAS IMAGE PORTS
  20. vqcbgslbbewv db replicated 1/1 mariadb:10.6.4-focal
  21. $ docker service ps db
  22. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  23. y1fw949ohrb7 db.1 mariadb:10.6.4-focal docker-node01 Running Running 24 seconds ago
  24. $ docker ps -l
  25. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  26. ece3013b7150 mariadb:10.6.4-focal "docker-entrypoint.s…" 23 seconds ago Up 21 seconds 3306/tcp db.1.y1fw949ohrb730ca3l53runji

创建 WordPress Service

  1. # 创建Wordpress Service
  2. $ docker service create -d --name wordpress \
  3. -e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=wordpress \
  4. --network demo \
  5. -e WORDPRESS_DB_PASSWORD=wordpress -e WORDPRESS_DB_NAME=wordpress \
  6. -p 80:80 wordpress
  7. # 查看 Docker Service 服务信息
  8. $ docker service ls
  9. ID NAME MODE REPLICAS IMAGE PORTS
  10. vqcbgslbbewv db replicated 1/1 mariadb:10.6.4-focal
  11. zowojzszkrub wordpress replicated 1/1 wordpress:latest *:80->80/tcp
  12. $ docker service ps wordpress
  13. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  14. azileh6g4kjl wordpress.1 wordpress:latest docker-node02 Running Running about a minute ago
  15. # 在Docker Node 查看Docker 进程
  16. $ docker ps -l
  17. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  18. f283b8b2d6a1 wordpress:latest "docker-entrypoint.s…" About a minute ago Up About a minute 80/tcp wordpress.1.azileh6g4kjl8cxba5j29du8y
  19. # Docker Swarm 集群会通过Swarm自身的机制来维护相应的网络模式
  20. # 实现跨主机网络容器之间通信
http://:80 后续的操作就是 WordPress 根据引导进行部署即可

💫32 Docker Swarm - 图6

💫32 Docker Swarm - 图7

💫32 Docker Swarm - 图8

这样 博客就搭建完成了!

7.4 集群服务间通信之 Routing Mesh

7.4.1 DNS 服务发现

Reference:https://blog.csdn.net/linmengmeng_1314/article/details/121271638

💫32 Docker Swarm - 图9

在上面的例子中。总共有两个服务myserviceclient,其中myservice有两个容器,这两个服务在同一个网里面。

在client里针对 docker .commyservice各执行了一个curl操作,下 面时执行的流程:

为了client解析 docker.commyservice。DNS 查询进行初始化

容器内建的解析器在 127.0.0.11:53 拦截到这个DNS查询请求。并把请求转发到docker引擎的DNS服务

myservice被解析成服务对应的虚拟IP ( 10.0.0.3 ) 。在接下来的内部负载均衡阶段再被解析成一个具体任务的IP地址,如果是容器名称这一步接解析成容器对应的IP地址( 10.0.0.4 或者 10.0.0.5 ) 。

docker.commynet网络上不能被解析成服务,所以这个请求被转发到配置好的默认DNS服务器( 8.8.8.8 ) 上。

范例:

  1. # 创建 Overlay 网络
  2. $ docker network create -d overlay demo
  3. $ docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami
  4. $ docker service ls
  5. ID NAME MODE REPLICAS IMAGE PORTS
  6. lyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp
  7. # 测试效果
  8. $ docker ps
  9. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  10. c244936d3a7b jwilder/whoami:latest "/app/http" 8 seconds ago Up 6 seconds 8000/tcp whoami.1.ib70al0738hsu3idmoxqpd658
  11. $ curl 127.0.0.1:8000
  12. I'm c244936d3a7b
  1. # 创建第二个Service
  2. $ docker service create --name client -d --network demo busybox sh -c "while true;do sleep 3600;done"
  3. $ docker service ls
  4. ID NAME MODE REPLICAS IMAGE PORTS
  5. 2q0kyr5r8zg5 client replicated 1/1 busybox:latest
  6. lyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp
  7. # 进入到 client 容器中ping whoami容器
  8. $ docker exec -it client.1.e42t62lhm64oq4bw9onhzsonu sh
  9. / # ping -c1 -W1 whoami
  10. PING whoami (10.0.1.7): 56 data bytes
  11. 64 bytes from 10.0.1.7: seq=0 ttl=64 time=0.094 ms
  12. --- whoami ping statistics ---
  13. 1 packets transmitted, 1 packets received, 0% packet loss
  14. round-trip min/avg/max = 0.094/0.094/0.094 ms
  15. # 将 whoami 容器的副本数提高
  16. $ docker service scale whoami=2
  17. $ docker service ls
  18. ID NAME MODE REPLICAS IMAGE PORTS
  19. 2q0kyr5r8zg5 client replicated 1/1 busybox:latest
  20. lyufxfn8i71j whoami replicated 2/2 jwilder/whoami:latest *:8000->8000/tcp
  21. # 进入到 client 容器中ping whoami容器
  22. $ docker exec -it client.1.e42t62lhm64oq4bw9onhzsonu sh
  23. # 默认访问的是VIP 虚拟IP地址(类似于负载均衡器的作用)
  24. / # ping -c1 -W1 whoami
  25. PING whoami (10.0.1.7): 56 data bytes
  26. 64 bytes from 10.0.1.7: seq=0 ttl=64 time=0.094 ms
  27. --- whoami ping statistics ---
  28. 1 packets transmitted, 1 packets received, 0% packet loss
  29. round-trip min/avg/max = 0.094/0.094/0.094 ms
  30. / # nslookup whoami
  31. Server: 127.0.0.11
  32. Address: 127.0.0.11:53
  33. Name: whoami
  34. Address 1: 10.0.1.7
  35. # 访问实际的后端的容器IP地址
  36. / # ping -c1 -W1 tasks.whoami
  37. PING tasks.whoami (10.0.1.8): 56 data bytes
  38. 64 bytes from 10.0.1.8: seq=0 ttl=64 time=0.097 ms
  39. --- tasks.whoami ping statistics ---
  40. 1 packets transmitted, 1 packets received, 0% packet loss
  41. round-trip min/avg/max = 0.097/0.097/0.097 ms
  42. / # ping -c1 -W1 tasks.whoami
  43. PING tasks.whoami (10.0.1.11): 56 data bytes
  44. 64 bytes from 10.0.1.11: seq=0 ttl=64 time=0.075 ms
  45. --- tasks.whoami ping statistics ---
  46. 1 packets transmitted, 1 packets received, 0% packet loss
  47. round-trip min/avg/max = 0.075/0.075/0.075 ms
  48. / # nslookup tasks.whoami
  49. / # wget whoami:8000
  50. Connecting to whoami:8000 (10.0.1.7:8000)
  51. saving to 'index.html'
  52. index.html 100% |*****************************************************************| 17 0:00:00 ETA
  53. 'index.html' saved
  54. / # cat index.html
  55. I'm' 5dcb2d2d44b4
  56. / # rm -f index.html
  57. / # wget whoami:8000
  58. Connecting to whoami:8000 (10.0.1.7:8000)
  59. saving to 'index.html'
  60. index.html 100% |*****************************************************************| 17 0:00:00 ETA
  61. 'index.html' saved
  62. / # cat index.html
  63. I'm' c244936d3a7b

7.4.2 Routing Mesh 的两种实现

  • Internal —— Container 和 Container 之间的访问通过 overlay 网络 ( 通过VIP虚拟IP )
  • Ingress —— 如果服务有绑定接口,则此服务可以通过任意 swarm 节点的相应接口访问

:::color2 Internel Load Balancing

:::

💫32 Docker Swarm - 图10

💫32 Docker Swarm - 图11

:::color2 DNS + VIP + iptables + LVS

:::

💫32 Docker Swarm - 图12

7.4.3 Ingress Network

💫32 Docker Swarm - 图13

  • 外部访问的负载均衡
  • 服务端口被暴露到各个swarm节点
  • 内部通过IPVS进行负载均衡
  1. $ docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami
  2. $ docker service ls
  3. ID NAME MODE REPLICAS IMAGE PORTS
  4. lyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp
  5. # 测试效果
  6. $ docker ps
  7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  8. c244936d3a7b jwilder/whoami:latest "/app/http" 8 seconds ago Up 6 seconds 8000/tcp whoami.1.ib70al0738hsu3idmoxqpd658
  9. $ docker service scale whoami=2
  10. $ docker service ls
  11. ID NAME MODE REPLICAS IMAGE PORTS
  12. lyufxfn8i71j whoami replicated 2/2 jwilder/whoami:latest *:8000->8000/tcp
  13. $ curl 127.0.0.1:8000
  14. I'm' 5dcb2d2d44b4
  15. $ curl 127.0.0.1:8000
  16. I'm' c244936d3a7b
  1. # 查看 iptables 转发规则
  2. $ iptables -vnL -t nat
  3. Chain DOCKER-INGRESS (2 references)
  4. pkts bytes target prot opt in out source destination
  5. 12 624 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 to:172.28.0.2:8000
  6. 9767 455K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
  7. # 查看本机的网卡配置
  8. $ ip addr
  9. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  10. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  11. inet 127.0.0.1/8 scope host lo
  12. valid_lft forever preferred_lft forever
  13. inet6 ::1/128 scope host
  14. valid_lft forever preferred_lft forever
  15. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  16. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  17. inet 192.168.0.64/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0
  18. valid_lft 78847sec preferred_lft 78847sec
  19. inet6 fe80::f816:3eff:fe6b:c203/64 scope link
  20. valid_lft forever preferred_lft forever
  21. 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  22. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  23. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  24. valid_lft forever preferred_lft forever
  25. inet6 fe80::42:c5ff:fe3b:4b05/64 scope link
  26. valid_lft forever preferred_lft forever
  27. 266: docker_gwbridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  28. link/ether 02:42:ce:ad:01:2d brd ff:ff:ff:ff:ff:ff
  29. inet 172.28.0.1/16 brd 172.28.255.255 scope global docker_gwbridge
  30. valid_lft forever preferred_lft forever
  31. inet6 fe80::42:ceff:fead:12d/64 scope link
  32. valid_lft forever preferred_lft forever
  33. # 使用python的json模块或者jq美化输出
  34. $ yum install -y jq && yum install -y ipvsadm
  35. $ docker network inspect -f "{{json .Containers}}" docker_gwbridge | jq
  36. {
  37. "5dcb2d2d44b4d6fecb67ab2ef2c2bd4c77455668e7d64e413529ff902809e796": {
  38. "Name": "gateway_20bb87568f17",
  39. "EndpointID": "ba0a5c05a375ecc80344ea8347a23dff40e14a43483372d8dc65d5b0da156916",
  40. "MacAddress": "02:42:ac:1c:00:07",
  41. "IPv4Address": "172.28.0.7/16",
  42. "IPv6Address": ""
  43. },
  44. "ac78df3a00dd3da44749ef7ece9f0a7b028123fa417a76f49b111f62943646cb": {
  45. "Name": "gateway_a8c1106c4cbc",
  46. "EndpointID": "619d81e415d146174895dc8a3d91cf62284f81656c03082ec091a762fbfd21b6",
  47. "MacAddress": "02:42:ac:1c:00:06",
  48. "IPv4Address": "172.28.0.6/16",
  49. "IPv6Address": ""
  50. },
  51. "c244936d3a7b214528171854e247684c0f31e4fc4cbe89e1375d2087801c1c57": {
  52. "Name": "gateway_973350406e56",
  53. "EndpointID": "6cca3c43a5b22677514c38816782bee0da2d17cd1a67e4bd08c808345aa62879",
  54. "MacAddress": "02:42:ac:1c:00:05",
  55. "IPv4Address": "172.28.0.5/16",
  56. "IPv6Address": ""
  57. },
  58. "ingress-sbox": {
  59. "Name": "gateway_ingress-sbox",
  60. "EndpointID": "ed635ca990e0903788385e4236110781954afd85909f826b9baa61e25d9e051f",
  61. "MacAddress": "02:42:ac:1c:00:02",
  62. "IPv4Address": "172.28.0.2/16",
  63. "IPv6Address": ""
  64. }
  65. }
  66. $ ls -l /var/run/docker/netns/ | grep ingress_sbox
  67. -r--r--r-- 1 root root 0 Nov 10 10:49 ingress_sbox
  68. # 进入到 ingress_sbox 的网络名称空间
  69. $ nsenter --net=/var/run/docker/netns/ingress_sbox
  70. $ ip addr
  71. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  72. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  73. inet 127.0.0.1/8 scope host lo
  74. valid_lft forever preferred_lft forever
  75. 264: eth0@if265: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
  76. link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  77. inet 10.0.0.2/24 brd 10.0.0.255 scope global eth0
  78. valid_lft forever preferred_lft forever
  79. inet 10.0.0.5/32 scope global eth0
  80. valid_lft forever preferred_lft forever
  81. 267: eth1@if268: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  82. link/ether 02:42:ac:1c:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 1
  83. inet 172.28.0.2/16 brd 172.28.255.255 scope global eth1
  84. valid_lft forever preferred_lft forever
  85. # 查看 ingress_sbox 的网络名称空间流量走向
  86. $ iptables -vnL -t mangle
  87. Chain PREROUTING (policy ACCEPT 78 packets, 4999 bytes)
  88. pkts bytes target prot opt in out source destination
  89. 54 3130 MARK tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 MARK set 0x104
  90. Chain INPUT (policy ACCEPT 48 packets, 2732 bytes)
  91. pkts bytes target prot opt in out source destination
  92. 0 0 MARK all -- * * 0.0.0.0/0 10.0.0.5 MARK set 0x104
  93. Chain FORWARD (policy ACCEPT 30 packets, 2267 bytes)
  94. pkts bytes target prot opt in out source destination
  95. Chain OUTPUT (policy ACCEPT 48 packets, 2732 bytes)
  96. pkts bytes target prot opt in out source destination
  97. Chain POSTROUTING (policy ACCEPT 78 packets, 4999 bytes)
  98. pkts bytes target prot opt in out source destination
  99. $ ipvsadm -l
  100. IP Virtual Server version 1.2.1 (size=4096)
  101. Prot LocalAddress:Port Scheduler Flags
  102. -> RemoteAddress:Port Forward Weight ActiveConn InActConn
  103. FWM 260 rr
  104. # 对应的是 whoami 的容器IP地址
  105. -> 10.0.0.6:0 Masq 1 0 0
  106. -> 10.0.0.7:0 Masq 1 0 0

:::color5 Ingress Network 的数据包走向详情

:::

💫32 Docker Swarm - 图14

8 Docker Stack

Docker Reference:https://docs.docker.com/engine/reference/commandline/stack/

Docker在进行多服务部署和管理时通常会使用Docker Stack来解决大规模部署管理问题,Docker引擎在1.12 版本集成了Docker Swarm, 内置新的容器编排工具docker stack,通过提供期望状态、滚动升级、简单易用、扩缩容、健康检查等特性简化了应用的管理。 从体系结构上来讲,Stack 位于 Docker 应用层级的最顶端。Stack 基于服务进行构建,而服务又基于容器,如下图所示。

💫32 Docker Swarm - 图15

8.1 Docker Stack 部署 WordPress

Docker Compose Version 3 Reference:https://docs.docker.com/compose/compose-file/compose-file-v3/

  1. #创建一个项目的文件夹(这就是项目名project)
  2. $ mkdir /opt/my_wordpress ; cd /opt/my_wordpress
  3. $ vim docker-compose.yml
  4. version: "3.9"
  5. services:
  6. db:
  7. # We use a mariadb image which supports both amd64 & arm64 architecture
  8. image: mariadb:10.6.4-focal
  9. # If you really want to use MySQL, uncomment the following line
  10. #image: mysql:8.0.27
  11. command: '--default-authentication-plugin=mysql_native_password'
  12. volumes:
  13. - db_data:/var/lib/mysql
  14. restart: always
  15. environment:
  16. - MYSQL_ROOT_PASSWORD=somewordpress
  17. - MYSQL_DATABASE=wordpress
  18. - MYSQL_USER=wordpress
  19. - MYSQL_PASSWORD=wordpress
  20. expose:
  21. - 3306
  22. - 33060
  23. networks:
  24. - my-networks
  25. deploy:
  26. mode: global
  27. placement:
  28. constraints:
  29. - "node.role==manager"
  30. web:
  31. image: wordpress:latest
  32. ports:
  33. - 80:80
  34. restart: always
  35. environment:
  36. - WORDPRESS_DB_HOST=db
  37. - WORDPRESS_DB_USER=wordpress
  38. - WORDPRESS_DB_PASSWORD=wordpress
  39. - WORDPRESS_DB_NAME=wordpress
  40. networks:
  41. - my-networks
  42. depends_on:
  43. - db
  44. deploy:
  45. mode: replicated
  46. replicas: 3
  47. restart_policy:
  48. condition: on-failure
  49. delay: 5s
  50. max_attempts: 3
  51. update_config:
  52. parallelism: 1
  53. delay: 10s
  54. order: stop-first
  55. volumes:
  56. db_data:
  57. networks:
  58. my-networks:
  59. driver: overlay
  60. # 启动Docker Stack项目
  61. $ docker stack deploy wordpress --compose-file docker-compose.yml
  62. Creating network wordpress_my-networks
  63. Creating service wordpress_db
  64. Creating service wordpress_web
  65. # 查看Docker Stack项目
  66. $ docker stack ls
  67. NAME SERVICES ORCHESTRATOR
  68. wordpress 2 Swarm
  69. $ docker stack ps wordpress
  70. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  71. jzt5ip9zkiix wordpress_db.dracuxro5id7nku0vrn7azgtt mariadb:10.6.4-focal gz-kubesphere-node Running Running 2 minutes ago
  72. tt6bwucxisb3 wordpress_web.1 wordpress:latest gz-kubesphere-node Running Running 2 minutes ago
  73. ocd5up0c2kfr wordpress_web.2 wordpress:latest gz-kubesphere-node Running Running 2 minutes ago
  74. up5u96qrwa7m wordpress_web.3 wordpress:latest gz-kubesphere-node Running Running 2 minutes ago
  75. # 使用浏览器登录平台
http://:80 后续的操作就是 WordPress 根据引导进行部署即可

💫32 Docker Swarm - 图16

💫32 Docker Swarm - 图17

💫32 Docker Swarm - 图18

这样 博客就搭建完成了

:::color1

目前的IT主流的技术:Linux + Docker + Kubernetes(掌握) 掌握的技术:Docker 基础、原理、网络、服务、集群、错误排查、日志

:::

  1. # 删除Docker Stack项目
  2. docker stack rm wordpress

8.2 部署一个复杂的投票应用

💫32 Docker Swarm - 图19

  1. # GitHub Reference:
  2. # https://github.com/dockersamples/example-voting-app
  3. $ mkdir -pv example-voting-app ; cd example-voting-app
  4. $ git clone https://github.com/dockersamples/example-voting-app.git
  5. # 将压缩包进行解压
  6. # $ unzip example-voting-app-master.zip
  7. $ cat ./example-voting-app/docker-stack.yml
  8. version: "3"
  9. services:
  10. redis:
  11. image: redis:alpine
  12. networks:
  13. - frontend
  14. deploy:
  15. replicas: 1
  16. update_config:
  17. parallelism: 2
  18. delay: 10s
  19. restart_policy:
  20. condition: on-failure
  21. db:
  22. image: postgres:9.4
  23. environment:
  24. POSTGRES_USER: "postgres"
  25. POSTGRES_PASSWORD: "postgres"
  26. volumes:
  27. - db-data:/var/lib/postgresql/data
  28. networks:
  29. - backend
  30. deploy:
  31. placement:
  32. constraints: [node.role == manager]
  33. vote:
  34. image: dockersamples/examplevotingapp_vote:before
  35. ports:
  36. - 5000:80
  37. networks:
  38. - frontend
  39. depends_on:
  40. - redis
  41. deploy:
  42. replicas: 2
  43. update_config:
  44. parallelism: 2
  45. restart_policy:
  46. condition: on-failure
  47. result:
  48. image: dockersamples/examplevotingapp_result:before
  49. ports:
  50. - 5001:80
  51. networks:
  52. - backend
  53. depends_on:
  54. - db
  55. deploy:
  56. replicas: 1
  57. update_config:
  58. parallelism: 2
  59. delay: 10s
  60. restart_policy:
  61. condition: on-failure
  62. worker:
  63. image: dockersamples/examplevotingapp_worker
  64. networks:
  65. - frontend
  66. - backend
  67. depends_on:
  68. - db
  69. - redis
  70. deploy:
  71. mode: replicated
  72. replicas: 1
  73. labels: [APP=VOTING]
  74. restart_policy:
  75. condition: on-failure
  76. delay: 10s
  77. max_attempts: 3
  78. window: 120s
  79. placement:
  80. constraints: [node.role == manager]
  81. visualizer:
  82. image: dockersamples/visualizer:stable
  83. ports:
  84. - "8080:8080"
  85. stop_grace_period: 1m30s
  86. volumes:
  87. - "/var/run/docker.sock:/var/run/docker.sock"
  88. deploy:
  89. placement:
  90. constraints: [node.role == manager]
  91. networks:
  92. frontend:
  93. backend:
  94. volumes:
  95. db-data:

运行 Docker Stack 项目(查看Stack项目状态)

  1. $ docker stack deploy --compose-file docker-stack.yml vote
  2. Creating network vote_frontend
  3. Creating network vote_backend
  4. Creating network vote_default
  5. Creating service vote_vote
  6. Creating service vote_result
  7. Creating service vote_worker
  8. Creating service vote_visualizer
  9. Creating service vote_redis
  10. Creating service vote_db
  11. $ docker stack ls
  12. NAME SERVICES ORCHESTRATOR
  13. vote 6 Swarm
  14. # 需要等待所有的容器启动成功
  15. $ docker stack services vote
  16. ID NAME MODE REPLICAS IMAGE PORTS
  17. 5fbyhua4lrcc vote_db replicated 1/1 postgres:9.4
  18. 1mryq3wt80f1 vote_redis replicated 1/1 redis:alpine
  19. c47lnwxyb5ua vote_result replicated 1/1 dockersamples/examplevotingapp_result:before *:5001->80/tcp
  20. qcm0mjkfaetv vote_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcp
  21. t8ulyhamy1kt vote_vote replicated 2/2 dockersamples/examplevotingapp_vote:before *:5000->80/tcp
  22. lubk1ee2fxc2 vote_worker replicated 1/1 dockersamples/examplevotingapp_worker:latest
  23. $ docker stack ps vote
  24. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  25. i7uyw26p4kht vote_db.1 postgres:9.4 gz-kubesphere-node Running Running 32 seconds ago
  26. kuvghwnalv3w vote_redis.1 redis:alpine gz-kubesphere-node Running Running 2 minutes ago
  27. 3v1gar3ixljt vote_result.1 dockersamples/examplevotingapp_result:before gz-kubesphere-node Running Running 7 minutes ago
  28. tckb1qxa9t9v vote_visualizer.1 dockersamples/visualizer:stable gz-kubesphere-node Running Running 2 minutes ago
  29. louvev5676x7 vote_vote.1 dockersamples/examplevotingapp_vote:before gz-kubesphere-node Running Running 9 minutes ago
  30. xxd8264mka54 vote_vote.2 dockersamples/examplevotingapp_vote:before gz-kubesphere-node Running Running 9 minutes ago
  31. ibus8q5i6f2y vote_worker.1 dockersamples/examplevotingapp_worker:latest gz-kubesphere-node Running Running 29 seconds ago
  1. # 投票的页面
  2. http://110.41.20.249:5000/
  3. # 统计的页面
  4. http://110.41.20.249:5001/

💫32 Docker Swarm - 图20

访问 Docker Stack 的可视化界面

  1. # Docker Stack 的可视化界面
  2. http://110.41.20.249:8080/

💫32 Docker Swarm - 图21

8.3 Portainer 安装

官网:https://www.portainer.io/ 安装文档:Install Portainer with Docker on Linux - Portainer Documentation ### 8.3.1 Portainer 安装步骤 + docker 命令安装 bash # 9443 端口是 HTTPS # --restart=always 在Docker重启服务之后会自动启动 $ docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 --name portainer \ --restart=always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer + 第一次登录需创建admin,访问地址:IP地址:9000 [http://IP:9000/#/init/admin](http://IP:9000/#/init/admin) + 设置admin用户和密码后首次登录 :::warning > 用户名,直接用默认admin >(密码记得8位,随便你写) ::: 💫32 Docker Swarm - 图22 💫32 Docker Swarm - 图23 + 选择local选项卡后本地docker详细信息显示 💫32 Docker Swarm - 图24 💫32 Docker Swarm - 图25 + 上一步的图形展示,以及对应的docker命令 bash $ docker system df # Stack 是docker-compose ### 8.3.2 相关报错 在启动Docker 容器时,会出现报错:Error response from daemon: driver failed programming external connectivity on endpoint XXX(端口映射或启动容器时报错) 💫32 Docker Swarm - 图26 解决方法: :::warning 输入指令:systemctl restart docker。重启Docker服务即可重新生成自定义链DOCKER ::: ## 8.4 登录并演示介绍常用操作 case 💫32 Docker Swarm - 图27 查看容器的资源占用 💫32 Docker Swarm - 图28 创建容器实例 💫32 Docker Swarm - 图29 根据引导对容器的配置进行修改 ## 8.5 Docker Compose 和 Docker Stack 的区别 1. 来源:docker-compose是一个Python项目,作用在Docker引擎的顶层,必须单独安装docker-compose工具包才能将其与Docker一起使用;docker stack 来源docker 引擎原生支持,不许要额外安装 2. compose-file版本支持:docker stack 只能支持 version3 以上版本;docker compose支持所有版本 3. docker stack 不支持 compose file中的“build”指令,docker compose 不支持 deploy(https://docs.docker.com/compose/compose-file/#deploy 4. docker stack 是swarm mode的一部分, 即使是单机使用, 也需要一个 swarm 节点 5. docker stack 强化了service的概念:服务可理解为发布到生产环境时某组容器的预期状态 ,以及强化了( 复制集、 容器重启策略、回滚策略、服务更新策略 )等生产特性 总结:
  1. docker-compose 更像是被定义为单机容器编排工具
  2. docker stack为适用于生产环境的编排工具
docker-compose、docker stack工具命令都可以使用 version3 编写的docker-compose.yml 文件上,版本3之前的<font style="color:rgb(51, 51, 51);">docker-compose.yml</font> 文件可继续使用docker-compose工具,如果你仅需要一个能操作多个容器的工具,依旧可以使用docker-compose工具。 docker stack几乎能做docker-compose所有的事情 (生产部署docker stack表现还更好),如果打算使用docker swarm集群编排,可迁移到docker stack。 参考 Reference:https://docs.docker.com/compose/compose-file/ # 9 Docker Secret ## 9.0 Docker Secret 声明式配置中,若直接定义用户名及密码等环境变量时,会造成安全隐患;因此,引入secret,对保密数据(用户名及密码、ssh key、TLS认证信息、其他需保密数据)进行加密。

💫32 Docker Swarm - 图30

<font style="color:rgb(0, 0, 0);">docker swarm</font>架构中,<font style="color:rgb(0, 0, 0);">manager</font>节点(单数>3)内置<font style="color:rgb(0, 0, 0);">raft</font>分布式存储(可实现<font style="color:rgb(0, 0, 0);">manager</font>各节点数据同步),<font style="color:rgb(0, 0, 0);">manager</font><font style="color:rgb(0, 0, 0);">worker</font>之间通信是经过SSL/TLS加密的,而<font style="color:rgb(0, 0, 0);">private key</font>是通过加密后存储在<font style="color:rgb(0, 0, 0);">manager</font><font style="color:rgb(0, 0, 0);">raft</font>存储中。
secret管理:
  1. 存在<font style="color:rgb(0, 0, 0);">swarm manager</font>节点<font style="color:rgb(0, 0, 0);">raft database</font>里;
  2. <font style="color:rgb(0, 0, 0);">secret</font>可以<font style="color:rgb(0, 0, 0);">assign</font>给一个<font style="color:rgb(0, 0, 0);">service</font>,这个<font style="color:rgb(0, 0, 0);">service</font>内部就能看到这个<font style="color:rgb(0, 0, 0);">secret</font>
  3. <font style="color:rgb(0, 0, 0);">container</font>内部<font style="color:rgb(0, 0, 0);">secret</font>看起来像文件,但实际是在内存中;

9.1 Docker Secret 管理和使用

9.1.1 什么是 Secret ?

  • 用户名密码
  • SSH Key
  • TLS 认证
  • 任何不想让别人看到的数据

💫32 Docker Swarm - 图31

9.1.2 Docker Secret 创建

使用文件创建 Docker Secret

  1. $ docker secret create
  2. "docker secret create" requires at least 1 and at most 2 arguments.
  3. See 'docker secret create --help'.
  4. Usage: docker secret create [OPTIONS] SECRET [file|-]
  5. Create a secret from a file or STDIN as content
  6. # 本地创建一个文件
  7. $ vim password
  8. Admin@h3c
  9. # 创建一个Docker Secret
  10. $ docker secret create my-pwd password
  11. pej64bng7hfo6d25ve3wqtsuh
  12. # 创建完毕后将 password 文件删除
  13. # 查看Docker Secret的列表
  14. $ docker secret ls
  15. ID NAME DRIVER CREATED UPDATED
  16. pej64bng7hfo6d25ve3wqtsuh my-pwd 7 minutes ago 7 minutes ago

使用管道符创建Docker Secret

  1. $ echo "adminadmin" | docker secret create my-passwd -
  2. 4ytq5cy4ph4r39h9w20ynj8ep
  3. $ docker secret ls
  4. ID NAME DRIVER CREATED UPDATED
  5. 4ytq5cy4ph4r39h9w20ynj8ep my-passwd 3 minutes ago 3 minutes ago
  6. pej64bng7hfo6d25ve3wqtsuh my-pwd 12 minutes ago 12 minutes ago
  7. # 删除 Docker Secret
  8. $ docker secret rm my-passwd

使用 Docker Secret

  1. # 可以使用多次--secret 传入多个Docker Secret的值
  2. $ docker service create --name client --secret my-pwd busybox sh -c "while true;do sleep 3600;done"
  3. $ docker service ls
  4. ID NAME MODE REPLICAS IMAGE PORTS
  5. xi4qklnu2afm client replicated 1/1 busybox:latest
  6. $ docker ps
  7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  8. ce98fc881bac busybox:latest "sh -c 'while true;d…" 27 seconds ago Up 26 seconds client.1.qnzbctl8qel7g9gt6h1ixnuhy
  9. # 进入到client的容器中
  10. $ docker exec -it client.1.qnzbctl8qel7g9gt6h1ixnuhy sh
  11. / # cd /run/secrets/
  12. /run/secrets # ls -l
  13. total 4
  14. -r--r--r-- 1 root root 10 Nov 11 09:00 my-pwd
  15. /run/secrets # cat my-pwd
  16. Admin@h3c

范例:MySQL 使用 Docker Secret

  1. $ docker service create --name db --secret my-pwd -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pwd mysql:5.7.40
  2. $ docker service ls
  3. ID NAME MODE REPLICAS IMAGE PORTS
  4. 4yqgzc70q73w db replicated 1/1 mysql:5.7.40
  5. # 查看容器状态
  6. $ docker ps
  7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  8. 0f1012d87066 mysql:5.7.40 "docker-entrypoint.s…" 43 seconds ago Up 41 seconds 3306/tcp, 33060/tcp db.1.j5ihhu78b3hyruveyyhgzwqwc
  9. # 进入到容器控制台
  10. $ docker exec -it db.1.j5ihhu78b3hyruveyyhgzwqwc bash
  11. bash-4.2# ls -l /run/secrets/my-pwd
  12. -r--r--r-- 1 root root 10 Nov 11 09:06 /run/secrets/my-pwd
  13. bash-4.2# cat /run/secrets/my-pwd
  14. Admin@h3c
  15. bash-4.2# mysql -uroot -pAdmin@h3c
  16. mysql: [Warning] Using a password on the command line interface can be insecure.
  17. Welcome to the MySQL monitor. Commands end with ; or \g.
  18. Your MySQL connection id is 2
  19. Server version: 5.7.40 MySQL Community Server (GPL)
  20. Copyright (c) 2000, 2022, Oracle and/or its affiliates.
  21. Oracle is a registered trademark of Oracle Corporation and/or its
  22. affiliates. Other names may be trademarks of their respective
  23. owners.
  24. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  25. mysql> show databases;
  26. +--------------------+
  27. | Database |
  28. +--------------------+
  29. | information_schema |
  30. | mysql |
  31. | performance_schema |
  32. | sys |
  33. +--------------------+
  34. 4 rows in set (0.00 sec)

9.2 Docker Secret 在 Docker Stack 的使用

编辑 docker-compose.yml
在各个 service 下添加:secrets 参数 和 environment 参数
  1. #例如:
  2. services:
  3. web:
  4.    image: wordpress
  5.     secrets:
  6.      - my-pass
  7.     environment:
  8.      WORDPRESS_DB_HOST: mysql
  9.       WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pass
  10.     ...
eg: docker-compose.yml,secrets是直接从文件中读取,这种方式是创建和使用一起做
  1. version: '3.1'
  2. services:
  3. db:
  4. image: mysql:5.7.27
  5. volumes:
  6. - db_data:/var/lib/mysql
  7. environment:
  8. MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
  9. MYSQL_DATABASE: wordpress
  10. MYSQL_USER: wordpress
  11. MYSQL_PASSWORD_FILE: /run/secrets/db_password
  12. secrets:
  13. - db_root_password
  14. - db_password
  15. wordpress:
  16. depends_on:
  17. - db
  18. image: wordpress:latest
  19. ports:
  20. - "8888:80"
  21. environment:
  22. WORDPRESS_DB_HOST: db:3306
  23. WORDPRESS_DB_USER: wordpress
  24. WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
  25. secrets:
  26. - db_password
  27. secrets:
  28. db_password:
  29. file: password.txt
  30. db_root_password:
  31. file: password.txt
  32. volumes:
  33. db_data:
eg: docker-compose.yml,这种方式是password secrets先创建好,然后在使用
  1. version: '3.1'
  2. services:
  3. db:
  4. image: mysql:5.7.27
  5. volumes:
  6. - db_data:/var/lib/mysql
  7. environment:
  8. MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
  9. MYSQL_DATABASE: wordpress
  10. MYSQL_USER: wordpress
  11. MYSQL_PASSWORD_FILE: /run/secrets/db_password
  12. secrets:
  13. - my-pw
  14. wordpress:
  15. depends_on:
  16. - db
  17. image: wordpress:latest
  18. ports:
  19. - "8888:80"
  20. environment:
  21. WORDPRESS_DB_HOST: db:3306
  22. WORDPRESS_DB_USER: wordpress
  23. WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
  24. secrets:
  25. - my-pw
  26. volumes:
  27. db_data:

Docker Secret 在 Docker Stack 实例:

  1. cat > docker-compose.yml <<EOF
  2. version: '3.9'
  3. services:
  4. web:
  5. image: wordpress:latest
  6. ports:
  7. - 10880:80
  8. secrets:
  9. - my-pwd
  10. environment:
  11. WORDPRESS_DB_HOST: db:3306
  12. WORDPRESS_DB_USER: "root"
  13. WORDPRESS_DB_NAME: "wordpress"
  14. # WORDPRESS_DB_PASSWORD: "/run/secrets/my-pwd"
  15. WORDPRESS_DB_PASSWORD_FILE: "/run/secrets/my-pwd"
  16. networks:
  17. - my-network
  18. volumes:
  19. - wordpress_config:/var/www/html
  20. depends_on:
  21. - db
  22. deploy:
  23. mode: replicated
  24. # 一个副本数
  25. replicas: 1
  26. restart_policy:
  27. condition: on-failure
  28. delay: 5s
  29. max_attempts: 3
  30. update_config:
  31. parallelism: 1
  32. delay: 10s
  33. db:
  34. image: mariadb:10.6.4-focal
  35. command: '--default-authentication-plugin=mysql_native_password'
  36. volumes:
  37. - db_data:/var/lib/mysql
  38. - db_config:/etc/mysql
  39. ports:
  40. - 3306:3306
  41. environment:
  42. MYSQL_ROOT_PASSWORD_FILE: "/run/secrets/my-pwd"
  43. MYSQL_DATABASE: "wordpress"
  44. MYSQL_USER: "wordpress"
  45. MYSQL_PASSWORD_FILE: "/run/secrets/my-pwd"
  46. secrets:
  47. - my-pwd
  48. networks:
  49. - my-network
  50. deploy:
  51. mode: global
  52. placement:
  53. constraints:
  54. - "node.role==manager"
  55. volumes:
  56. db_data: {}
  57. db_config: {}
  58. wordpress_config: {}
  59. networks:
  60. my-network:
  61. driver: overlay
  62. secrets:
  63. my-pwd:
  64. file: ./password.txt
  65. EOF
  1. cat > password.txt <<EOF
  2. admin123
  3. EOF
  4. # MySQL配置文件(可选择)
  5. cat > mysql.cnf <<EOF
  6. [client]
  7. default-character-set=utf8
  8. [mysql]
  9. default-character-set=utf8
  10. [mysqld]
  11. skip-grant-tables
  12. pid-file = /var/run/mysqld/mysqld.pid
  13. socket = /var/run/mysqld/mysqld.sock
  14. datadir = /var/lib/mysql
  15. #log-error = /var/log/mysql/error.log
  16. # By default we only accept connections from localhost
  17. #bind-address = 127.0.0.1
  18. # Disabling symbolic-links is recommended to prevent assorted security risks
  19. symbolic-links=0
  20. lower_case_table_names=1
  21. init_connect='SET collation_connection = utf8_general_ci'
  22. init_connect='SET NAMES utf8'
  23. character-set-server=utf8
  24. collation-server=utf8_general_ci
  25. max_connections = 1000
  26. EOF

启动 Docker Stack 项目

  1. # 启用 Docker Stack 项目
  2. $ docker stack deploy wordpress --compose-file docker-compose.yml
  3. $ docker stack ls
  4. NAME SERVICES ORCHESTRATOR
  5. wordpress 2 Swarm
  6. # 查看Docker Stack的状态
  7. $ docker stack ps wordpress
  8. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  9. imh1o7tcgx57 wordpress_db.dracuxro5id7nku0vrn7azgtt mariadb:10.6.4-focal gz-kubesphere-node Running Running 12 seconds ago
  10. zalthk69hso1 wordpress_web.1 wordpress:latest gz-kubesphere-node Running Running 27 seconds ago
  11. # 查看服务的副本状态
  12. $ docker service ls
  13. ID NAME MODE REPLICAS IMAGE PORTS
  14. wjax6djbozp4 wordpress_db global 1/1 mariadb:10.6.4-focal
  15. rtlbuvua6gak wordpress_web replicated 1/1 wordpress:latest *:10880->80/tcp
  16. # 删除 Docker Stack 项目
  17. $ docker stack rm wordpress
http://:10880 后续的操作就是 WordPress 根据引导进行部署即可

💫32 Docker Swarm - 图32

💫32 Docker Swarm - 图33

💫32 Docker Swarm - 图34

这样 博客就搭建完成了!

9.3 Docker Service 更新

  1. # 创建一个 Overlay 的网络模式
  2. $ docker network create -d overlay demo
  3. $ docker network ls
  4. NETWORK ID NAME DRIVER SCOPE
  5. ceb235716540 bridge bridge local
  6. mngekyo6uepz demo overlay swarm
  7. 0e660fabfa96 docker_gwbridge bridge local
  8. a40831f989fe host host local
  9. 610mgoxey5g7 ingress overlay swarm
  10. f314686d0f0f none null local
  11. # 使用Dockerfile创建相应的web镜像
  12. $ vim app.py
  13. from flask import Flask
  14. app = Flask(__name__)
  15. @app.route('/')
  16. def hello():
  17. return "hello docker , version 1.0"
  18. if __name__ == '__main__':
  19. app.run()
  20. $ vim Dockerfile
  21. FROM python:2.7
  22. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"
  23. RUN pip install flask && \
  24. mkdir -pv /app
  25. WORKDIR /app
  26. ADD app.py /app/
  27. CMD [ "python", "app.py" ]
  28. EXPOSE 5000
  29. $ docker build -t flask-demo:v1.0 -f Dockerfile .
  30. $ docker images
  31. REPOSITORY TAG IMAGE ID CREATED SIZE
  32. flask-demo v1.0 7c259632347e 5 seconds ago 906MB
  33. # Service使用Overlay网络模式创建
  34. $ docker service create --name web --publish 8080:5000 --network demo flask-demo:v1.0
  35. $ docker service ps web
  36. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  37. wkwflwfm9x9t web.1 flask-demo:v1.0 gz-kubespere-docker Running Running about a minute ago
  38. # 增加Service的副本数
  39. $ docker service scale web=2
  40. $ docker service ps web
  41. ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
  42. wkwflwfm9x9t web.1 flask-demo:v1.0 gz-kubespere-docker Running Running 2 minutes ago
  43. wwhln2hek0mh web.2 flask-demo:v1.0 gz-kubespere-docker Running Running 25 seconds ago
  44. # 检查服务运行是否正常
  45. $ curl 127.0.0.1:8080
  46. hello docker , version 1.0
编写Shell脚本一直访问
  1. sh -c "while true;do curl 127.0.0.1:8080 && sleep 1;done"
更新镜像到2.0
中间没有发生中断操作,直接升级成了2.0
  1. # 使用Dockerfile创建相应的web镜像
  2. $ vim app.py
  3. from flask import Flask
  4. app = Flask(__name__)
  5. @app.route('/')
  6. def hello():
  7. return "hello docker , version 2.0"
  8. if __name__ == '__main__':
  9. app.run()
  10. $ vim Dockerfile
  11. FROM python:2.7
  12. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"
  13. RUN pip install flask && \
  14. mkdir -pv /app
  15. WORKDIR /app
  16. ADD app.py /app/
  17. CMD [ "python", "app.py" ]
  18. EXPOSE 5000
  19. # 构建2.0镜像
  20. $ docker build -t flask-demo:v2.0 -f Dockerfile .
  21. # 更新镜像到2.0
  22. docker service update --image flask-demo:2.0 web
  23. # 1.0已经shutdown了,启动了2.0
  24. docker service ps web
更新访问服务的端口
端口更新可能存在业务中断的情况
  1. docker service update --publish-rm 8080:5000 --publish-add 8088:5000 web
  2. docker service ps web
  3. docker service web

:::color5 Docker Stack 的更新会根据 docker-compose.yml 文件与当前的环境的配置进行对比,实现相应的 Docker Stack 的更新效果!

:::

10 Docker Cloud

Docker Cloud是由Docker提供的服务,您可以在其中进行以下操作 -
  • 节点 - 您可以将Docker Cloud连接到现有的云提供商(如Azure和AWS),以便在这些环境中旋转容器。
  • 云存储库 - 提供一个可以存储自己的存储库的地方。
  • 持续集成 - 与Github连接并创建一个持续的集成管道。
  • 应用程序部署 - 部署和扩展基础架构和容器。
  • 持续部署 - 可自动部署。

10.1 Docker Cloud

Video Reference:

https://www.bilibili.com/video/BV1xe4y1q7fC/?p=59

https://www.bilibili.com/video/BV1xe4y1q7fC/?p=60

💫32 Docker Swarm - 图35

Docker Cloud 是caas(Container as a Service)容器即服务,阿里云和腾讯云属于paas平台即服务,caas是在paas之上的,我们要提供docker的service,必须要有底层infrastructure的支持,paas他们虚拟的计算资源,在这些虚拟资源之上在进行搭建docker的微服务;

Docker Cloud,Docker在2015年11月收购了tutum.co在今年2月份推出了Docker Cloud,它基本上提供了Docker自身原生的一个编排的API;

  • Docker Compose,也是收购了一个公司叫 FIG ,才有了现在的docker-compose;
  • Docker Cloud 是提供容器的管理,编排,部署的托管服务。

:::color5

主要模块

:::

💫32 Docker Swarm - 图36

:::color5

主要有两种运行模式:

:::

  • Standard 模式。一个Node就是一个Docker Host
  • Swarm 模式(beta)。多个Node组成的Swarm Cluster

:::color5 DevOps 流程

:::

💫32 Docker Swarm - 图37

10.2 Docker Cloud 之自动 build Docker Images

您可以访问以下链接以开始使用Docker Cloud - https://cloud.docker.com/ > Reference:http://github.com/imooc-course/docker-cloud/flask-demo > 💫32 Docker Swarm - 图38 登录后,您将获得以下基本界面 -

💫32 Docker Swarm - 图39

10.2.1 连接到云提供商

第一步是连接到现有的云提供商。以下步骤将向您展示如何与Amazon Cloud提供商进行连接。

步骤1 - 第一步是确保您拥有正确的AWS密钥。这可以从aws控制台取出使用以下链接登录您的aws帐户 - https://aws.amazon.com/console/

💫32 Docker Swarm - 图40

步骤2 - 登录后,转到安全凭证部分。记录将从Docker Hub使用的访问键。

💫32 Docker Swarm - 图41

步骤3 - 接下来,您需要在aws创建一个允许Docker查看EC2实例的策略。aws中转到配置文件部分单击创建策略按钮。

💫32 Docker Swarm - 图42

步骤4 - 点击“创建自己的策略”,并将策略名称作为dockercloudpolicy和策略定义,如下所示。

  1. {
  2. "Version": "2012-10-17",
  3. "Statement": [ {
  4. "Action": [
  5. "ec2:*",
  6. "iam:ListInstanceProfiles"
  7. ],
  8. "Effect": "Allow",
  9. "Resource": "*"
  10. } ]
  11. }

💫32 Docker Swarm - 图43

接下来,单击创建策略按钮

步骤5 - 接下来,您需要创建一个将由Docker用于在AWS上启动节点角色为此,请转到AWS 中的“ 角色”部分,然后单击“ 创建新角色”选项。

💫32 Docker Swarm - 图44

步骤6 - 将角色的名称命名为dockercloud-role

💫32 Docker Swarm - 图45

步骤7 - 在下一个屏幕上,转到“跨帐户访问角色”,然后选择“在您的帐户和第三方AWS帐户之间提供访问权限”。

💫32 Docker Swarm - 图46

步骤8 - 在下一个屏幕上,输入以下详细信息 -

  • 在“帐户ID”字段中,输入Docker Cloud服务的ID:689684103426。
  • 在外部ID字段中,输入您的Docker Cloud用户名。

💫32 Docker Swarm - 图47

步骤9 - 然后,单击下一步按钮,然后在下一个屏幕上,附上之前创建的策略。

💫32 Docker Swarm - 图48

步骤10 - 最后,在创建角色的最后一个屏幕上,确保复制创建arn角色。

  1. arn:aws:iam::085363624145:role/dockercloud-role

💫32 Docker Swarm - 图49

步骤11 - 现在回到Docker Cloud,选择Cloud Providers,然后单击Amazon Web Services旁边插头符号

💫32 Docker Swarm - 图50

输入arn角色,然后单击保存按钮。

💫32 Docker Swarm - 图51

一旦保存,与AWS的集成将会完成。

💫32 Docker Swarm - 图52

10.2.2 设置节点

一旦与AWS的集成完成,下一步就是设置一个节点。转到Docker Cloud中的节点部分。请注意,节点的设置将首先自动设置节点群集。

步骤1 - 转到Docker Cloud中的节点部分。

💫32 Docker Swarm - 图53

步骤2 - 接下来,您可以给出将在AWS中设置的节点的详细信息。

💫32 Docker Swarm - 图54

然后,您可以单击将出现在屏幕底部的启动节点集群。一旦部署了节点,您将在“节点集群”屏幕中获取通知。

💫32 Docker Swarm - 图55

10.2.3 部署服务

部署节点后的下一步是部署服务。为此,我们需要执行以下步骤。

步骤1 - 转到Docker Cloud 服务部门单击创建按钮

💫32 Docker Swarm - 图56

步骤2 - 选择所需的服务。在我们的例子中,我们选择mongo

💫32 Docker Swarm - 图57

步骤3 - 在下一个屏幕上,选择“ 创建和部署”选项。这将开始在您的节点集群上部署Mongo容器。

💫32 Docker Swarm - 图58

一旦部署,您将能够看到容器处于运行状态。

💫32 Docker Swarm - 图59

10.3 Docker Cloud 之持续集成和持续部署

Video Reference:https://www.bilibili.com/video/BV1xe4y1q7fC/?p=61

了解即可,企业中使用的是GitLab + Kubernetes 的组合实现持续集成和持续部署!

:::info Docker Cloud 已经在官网下架,Docker 官方不再支持 Docker Cloud 的使用!

:::

11 DockerEE 企业版

11.1 Docker EE 官方已不再支持

Video Reference:

https://www.bilibili.com/video/BV1xe4y1q7fC/?p=62

https://www.bilibili.com/video/BV1xe4y1q7fC/?p=63

https://www.bilibili.com/video/BV1xe4y1q7fC/?p=64

https://www.bilibili.com/video/BV1xe4y1q7fC/?p=65

Reference:https://www.docker.com/

:::info Docker-EE 企业版也已经在 Docker 官网中没有信息,并且Docker-Machine 和 Toolbox 已经放弃!

Docker 官方不再支持 Docker-EE 的版本。

:::

11.2 阿里云上使用容器服务和安装 Docker EE

11.2.1 体验阿里云容器服务

Video Reference:https://www.bilibili.com/video/BV1xe4y1q7fC?p=66

Aliyun Product Reference:https://www.aliyun.com/product/containerservice?spm=a2c6h.21258778.0.0.70df2617aGKst1

前提条件

如果您还未创建集群,您需要先创建集群。有关如何创建集群的详细信息,参见创建集群

操作步骤

  1. 登录容器服务管理控制台
  2. 单击左侧导航栏中的应用 并单击右上角的创建应用,如下图所示。💫32 Docker Swarm - 图60
  3. 输入应用相关信息,单击使用镜像创建 - 应用名称:要创建的应用的名称。本示例中,应用名称为 nginx。 - 应用版本:所创建应用的版本。默认为 1.0。 - 部署集群:要部署到的集群。 - 默认更新策略:应用更新的方式,您可以选择标准发布 蓝绿发布,参见 发布策略说明 - 应用描述:应用的相关信息。该信息将显示在应用列表页面。 - 检查最新 Docker 镜像:选中该选项后,表示当镜像 Tag 不变的情况下,也会去仓库拉取最新的镜像。为了提高效率,容器服务会对镜像进行缓存。部署时,如果发现镜像 Tag 与本地缓存的一致,则会直接复用而不重新拉取。所以,如果您基于上层业务便利性等因素考虑,在做代码和镜像变更时没有同步修改 Tag ,就会导致部署时还是使用本地缓存内旧版本镜像。而勾选该选项后,会忽略缓存,每次部署时重新拉取镜像,确保使用的始终是最新的镜像和代码。
  4. 单击选择镜像。在搜索框中输入nginx,单击全局搜索。在搜索结果中选择nginx,单击确定容器服务会默认使用镜像的最新版本。如果您需要使用镜像的其它版本,单击选择镜像版本,单击所需版本并单击确定💫32 Docker Swarm - 图61💫32 Docker Swarm - 图62
  5. 端口映射中配置容器与主机的端口映射。为了能够通过公网访问容器内的 Nginx 服务器,我们还需要配置简单路由配置💫32 Docker Swarm - 图63说明 您也可以填写自己的域名,关于如何添加您的自有域名,参见 简单路由-域名配置。关于配置路由的容器端口和 HTTP 服务的域名,参见 标签概览 中的 routing。关于路由服务如何将请求转发到容器,参见 简单路由(支持 HTTP/HTTPS) 1. 配置容器的 80 和 443 的端口映射。本示例未指定主机端口。 2. 配置简单路由。 单击简单路由配置右侧的加号图标。 容器端口框中输入80,即表示访问 nginx 容器的 80 端口。 *域名框中输入nginx。域名字段只填写了域名前缀 nginx,如果域名前缀为 XXX,会给到域名 XXX.$cluster_id.$region_id.alicontainer.com 供测试使用。本例中您获得的测试域名为 nginx.c9b424ed591eb4892a2d18dd264a6fdfb.cn-hangzhou.alicontainer.com
  6. 单击创建。容器服务根据以上设置创建应用 nginx。
  7. 单击查看应用列表返回应用列表 或左侧导航栏中的 应用 返回应用列表。如下图所示,单击应用名称nginx,查看应用详情。💫32 Docker Swarm - 图64
  8. 服务列表中,单击服务名称nginx,进入服务 nginx 页面。💫32 Docker Swarm - 图65
  9. 单击服务 nginx 的访问端点,即可进入 Nginx 服务器的默认欢迎页面。💫32 Docker Swarm - 图66

11.2.2 在阿里云安装 DockerEE

Video Reference:https://www.bilibili.com/video/BV1xe4y1q7fC?p=67