7 Docker Swarm
7.1 Docker Swarm 介绍

在之前的使用中,所有的操作都是在本地上执行的!
:::color5 到处都使用容器 = 麻烦来了
:::
- 怎么去管理这么多容器?
- 怎么能方便的横向扩展?
- 如果容器down了,怎么能自动恢复?
- 如何去更新容器而不影响业务?
- 如何去监控追踪这些容器?
- 怎么去调度容器的创建?
- 保护隐私数据?
:::color5 Swarm Mode
:::

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
:::

- Swarm
集群的管理和编排是使用嵌入docker引擎的SwarmKit,可以在docker初始化时启动swarm模式或者加入已存在的swarm
- Node
一个节点是docker引擎集群的一个实例。您还可以将其视为Docker节点。您可以在单个物理计算机或云服务器上运行一个或多个节点,但生产群集部署通常包括分布在多个物理和云计算机上的Docker节点。
要将应用程序部署到swarm,请将服务定义提交给 管理器节点。管理器节点将称为任务的工作单元分派 给工作节点。
Manager节点还执行维护所需群集状态所需的编排和集群管理功能。Manager节点选择单个领导者来执行编排任务。
工作节点接收并执行从管理器节点分派的任务。默认情况下,管理器节点还将服务作为工作节点运行,但您可以将它们配置为仅运行管理器任务并且是仅管理器节点。代理程序在每个工作程序节点上运行,并报告分配给它的任务。工作节点向管理器节点通知其分配的任务的当前状态,以便管理器可以维持每个工作者的期望状态。
:::color5 Service 和 Replicas
:::

- Service
一个服务是任务的定义,管理机或工作节点上执行。它是群体系统的中心结构,是用户与群体交互的主要根源。创建服务时,你需要指定要使用的容器镜像。
- Task
任务是在docekr容器中执行的命令,Manager节点根据指定数量的任务副本分配任务给worker节点
:::color5 服务创建和调度
:::

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
- Vagrant + Virtualbox
- Docker Machine + Virtualbox
- Paly with docker https://labs.play-with-docker.com/
范例:部署 Docker 环境
#!/bin/bashDOCKER_VERSION="20.10.10"#UBUNTU_DOCKER_VERSION="5:${DOCKER_VERSION}~3-0~`lsb_release -si`-`lsb_release -cs`"DOCKER_COMPOSE_VERSION=1.29.2DOCKER_COMPOSE_FILE=docker-compose-Linux-x86_64COLOR_SUCCESS="echo -e \\033[1;32m"COLOR_FAILURE="echo -e \\033[1;31m"END="\033[m". /etc/os-releasecolor () {RES_COL=60MOVE_TO_COL="echo -en \\033[${RES_COL}G"SETCOLOR_SUCCESS="echo -en \\033[1;32m"SETCOLOR_FAILURE="echo -en \\033[1;31m"SETCOLOR_WARNING="echo -en \\033[1;33m"SETCOLOR_NORMAL="echo -en \E[0m"echo -n "$1" && $MOVE_TO_COLecho -n "["if [ $2 = "success" -o $2 = "0" ] ;then${SETCOLOR_SUCCESS}echo -n $" OK "elif [ $2 = "failure" -o $2 = "1" ] ;then${SETCOLOR_FAILURE}echo -n $"FAILED"else${SETCOLOR_WARNING}echo -n $"WARNING"fi${SETCOLOR_NORMAL}echo -n "]"echo}install_docker(){if [ $ID = "centos" -o $ID = "rocky" ];thenif [ $VERSION_ID = "7" ];thencat > /etc/yum.repos.d/docker.repo <<EOF[docker]name=dockergpgcheck=0#baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/x86_64/stable/EOFelsecat > /etc/yum.repos.d/docker.repo <<EOF[docker]name=dockergpgcheck=0#baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/8/x86_64/stable/baseurl=https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/8/x86_64/stable/EOFfiyum clean all${COLOR_FAILURE} "Docker有以下版本"${END}yum list docker-ce --showduplicates${COLOR_FAILURE}"5秒后即将安装: docker-"${DOCKER_VERSION}" 版本....."${END}${COLOR_FAILURE}"如果想安装其它Docker版本,请按ctrl+c键退出,修改版本再执行"${END}sleep 5yum -y install docker-ce-$DOCKER_VERSION docker-ce-cli-$DOCKER_VERSION \|| { color "Base,Extras的yum源失败,请检查yum源配置" 1;exit; }elsedpkg -s docker-ce &> /dev/null && $COLOR"Docker已安装,退出" 1 && exitapt update || { color "更新包索引失败" 1 ; exit 1; }apt -y install apt-transport-https ca-certificates curl software-properties-common || \{ color "安装相关包失败" 1 ; exit 2; }curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -add-apt-repository "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable"apt update${COLOR_FAILURE} "Docker有以下版本"${END}apt-cache madison docker-ce${COLOR_FAILURE}"5秒后即将安装: docker-"${UBUNTU_DOCKER_VERSION}" 版本....."${END}${COLOR_FAILURE}"如果想安装其它Docker版本,请按ctrl+c键退出,修改版本再执行"${END}sleep 5apt -y install docker-ce=${UBUNTU_DOCKER_VERSION} docker-ce-cli=${UBUNTU_DOCKER_VERSION}fiif [ $? -eq 0 ];thencolor "安装软件包成功" 0elsecolor "安装软件包失败,请检查网络配置" 1exitfimkdir -p /etc/dockertee /etc/docker/daemon.json <<-'EOF'{"registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],"insecure-registries": ["harbor.kubesphere.com:80"]}EOFsystemctl daemon-reloadsystemctl enable dockersystemctl restart dockerdocker version && color "Docker 安装成功" 0 || color "Docker 安装失败" 1echo 'alias rmi="docker images -qa|xargs docker rmi -f"' >> ~/.bashrcecho 'alias rmc="docker ps -qa|xargs docker rm -f"' >> ~/.bashrc}install_docker_compose(){if [ $ID = "centos" -o $ID = "rocky" ];then${COLOR_SUCCESS}"开始安装 Docker compose....."${END}sleep 1if [ ! -e ${DOCKER_COMPOSE_FILE} ];thencurl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/${DOCKER_COMPOSE_FILE} -o /usr/bin/docker-compose# curl -L https://get.daocloud.io/docker/compose/releases/download/v2.12.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-composeelsemv ${DOCKER_COMPOSE_FILE} /usr/bin/docker-composefichmod +x /usr/bin/docker-composeelseapt -y install docker-composefiif docker-compose --version ;then${COLOR_SUCCESS}"Docker Compose 安装完成"${END}else${COLOR_FAILURE}"Docker compose 安装失败"${END}exitfi}install_dockerinstall_docker_compose
初始化 Docker Swarm
# 初始化 Master 节点$ docker swarm init --advertise-addr 10.0.0.101Swarm initialized: current node (kdl65arb5xhld1s1ogc78gur7) is now a manager.To add a worker to this swarm, run the following command:docker swarm join --token SWMTKN-1-5fqnggzu8j0a3hywv9nhl2kl5rmi02yol31djv90c93igua3ey-bnpxxyf1wxuvba8n004qc102v 10.0.0.101:2377To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.# 加入工作节点$ docker swarm join --token SWMTKN-1-5fqnggzu8j0a3hywv9nhl2kl5rmi02yol31djv90c93igua3ey-bnpxxyf1wxuvba8n004qc102v 10.0.0.101:2377# 在Master节点查看节点信息$ docker node lsID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSIONkdl65arb5xhld1s1ogc78gur7 * docker-node01 Ready Active Leader 19.03.11pzubdmyszq0or4rtk45lzihts docker-node02 Ready Active 19.03.11dvl2e5upon3bklq77ijzkp100 docker-node03 Ready Active 20.10.10
(可以使用 Docker-Machine 来创建三个节点)
# 创建Master节点(一个节点)docker-machine create swarm-manager# 创建Worker节点(两个节点)docker-machine create swarm-node01docker-machine create swarm-node02# 查看各节点的IP地址docker-machine ls# 进入到 Master 节点$ docker-machine ssh swarm-manager$ docker swarm init --advertise-addr 10.0.0.101# 进入到 Worker 节点(执行命令类似)$ docker-machine ssh swarm-node01 & docker-machine ssh swarm-node02$ docker swarm join --token SWMTKN-1-5fqnggzu8j0a3hywv9nhl2kl5rmi02yol31djv90c93igua3ey-bnpxxyf1wxuvba8n004qc102v 10.0.0.101:2377
7.2.2 Service 的创建和水平扩展
Service 的创建
# 创建一个Service$ docker service create --name busybox-node busybox sh -c "while true;do sleep 3600;done"# 查看Service信息$ docker service lsID NAME MODE REPLICAS IMAGE PORTSdyenfcor78te busybox-node replicated 1/1 busybox:latest# 查看Service详细信息$ docker service ps busybox-nodeID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running about a minute ago# 在 docker-node03 查看Docker进程信息$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES3cb69e5b3cc5 busybox:latest "sh -c 'while true;d…" 3 minutes ago Up 3 minutes busybox-node.1.7jfml4o5yklf061bggak4omqc
Service 的水平扩展
# 设置水平扩展$ docker service scale busybox-node=3$ docker service lsID NAME MODE REPLICAS IMAGE PORTSdyenfcor78te busybox-node replicated 3/3 busybox:latest# 平均分配到各个节点中运行$ docker service ps busybox-nodeID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running 7 minutes agoq3w8bdvu9141 busybox-node.2 busybox:latest docker-node02 Running Running 47 seconds agopyhxitis9kr3 busybox-node.3 busybox:latest docker-node01 Running Running about a minute ago# 在docker-node02上删除相应的容器$ docker rm -f busybox-node.2# 在Master节点上查看Service 的副本数(过一段时间再次查看)$ docker service lsID NAME MODE REPLICAS IMAGE PORTSdyenfcor78te busybox-node replicated 2/3 busybox:latest# 其Docker Service具有自恢复能力$ docker service lsID NAME MODE REPLICAS IMAGE PORTSdyenfcor78te busybox-node replicated 3/3 busybox:latest$ docker service ps busybox-nodeID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running 10 minutes agoxtl92syb8d01 busybox-node.2 busybox:latest docker-node02 Running Running about a minute agoq3w8bdvu9141 \_ busybox-node.2 busybox:latest docker-node02 Shutdown Failed about a minute ago "task: non-zero exit (137)"pyhxitis9kr3 busybox-node.3 busybox:latest docker-node01 Running Running 4 minutes ago
Service 的删除
$ docker service rm busybox-node# 各节点的Service 的容器会将其删除
7.3 在 Swarm 集群中通过Service 部署 WordPress
创建 MySQL / MariaDB 数据库 Service
# 需要创建一个 Overlay Network$ docker network create -d overlay demo$ docker network lsNETWORK ID NAME DRIVER SCOPEd0ba97d9a9e1 bridge bridge local1u4udx1r0c6p demo overlay swarm458e32a2a13c docker_gwbridge bridge local0959653f62aa host host localj59uwl8alp6o ingress overlay swarm891c07cd5918 none null local# 创建MySQL Service$ docker service create -d --name db \-e MYSQL_ROOT_PASSWORD=somewordpress \-e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress \--network demo --mount type=volume,source=mysql-data,destination=/var/lib/mysql \-e MYSQL_PASSWORD=wordpress mariadb:10.6.4-focal --default-authentication-plugin=mysql_native_password# 查看 Docker Service 服务信息$ docker service lsID NAME MODE REPLICAS IMAGE PORTSvqcbgslbbewv db replicated 1/1 mariadb:10.6.4-focal$ docker service ps dbID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTSy1fw949ohrb7 db.1 mariadb:10.6.4-focal docker-node01 Running Running 24 seconds ago$ docker ps -lCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESece3013b7150 mariadb:10.6.4-focal "docker-entrypoint.s…" 23 seconds ago Up 21 seconds 3306/tcp db.1.y1fw949ohrb730ca3l53runji
创建 WordPress Service
# 创建Wordpress Service$ docker service create -d --name wordpress \-e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=wordpress \--network demo \-e WORDPRESS_DB_PASSWORD=wordpress -e WORDPRESS_DB_NAME=wordpress \-p 80:80 wordpress# 查看 Docker Service 服务信息$ docker service lsID NAME MODE REPLICAS IMAGE PORTSvqcbgslbbewv db replicated 1/1 mariadb:10.6.4-focalzowojzszkrub wordpress replicated 1/1 wordpress:latest *:80->80/tcp$ docker service ps wordpressID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTSazileh6g4kjl wordpress.1 wordpress:latest docker-node02 Running Running about a minute ago# 在Docker Node 查看Docker 进程$ docker ps -lCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESf283b8b2d6a1 wordpress:latest "docker-entrypoint.s…" About a minute ago Up About a minute 80/tcp wordpress.1.azileh6g4kjl8cxba5j29du8y# Docker Swarm 集群会通过Swarm自身的机制来维护相应的网络模式# 实现跨主机网络容器之间通信
http://:80 后续的操作就是 WordPress 根据引导进行部署即可



7.4 集群服务间通信之 Routing Mesh
7.4.1 DNS 服务发现
Reference:https://blog.csdn.net/linmengmeng_1314/article/details/121271638

在上面的例子中。总共有两个服务myservice和client,其中myservice有两个容器,这两个服务在同一个网里面。
在client里针对 docker .com 和 myservice各执行了一个curl操作,下 面时执行的流程:
为了client解析 docker.com 和 myservice。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.com在mynet网络上不能被解析成服务,所以这个请求被转发到配置好的默认DNS服务器( 8.8.8.8 ) 上。
范例:
# 创建 Overlay 网络$ docker network create -d overlay demo$ docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami$ docker service lsID NAME MODE REPLICAS IMAGE PORTSlyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp# 测试效果$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESc244936d3a7b jwilder/whoami:latest "/app/http" 8 seconds ago Up 6 seconds 8000/tcp whoami.1.ib70al0738hsu3idmoxqpd658$ curl 127.0.0.1:8000I'm c244936d3a7b
# 创建第二个Service$ docker service create --name client -d --network demo busybox sh -c "while true;do sleep 3600;done"$ docker service lsID NAME MODE REPLICAS IMAGE PORTS2q0kyr5r8zg5 client replicated 1/1 busybox:latestlyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp# 进入到 client 容器中ping whoami容器$ docker exec -it client.1.e42t62lhm64oq4bw9onhzsonu sh/ # ping -c1 -W1 whoamiPING whoami (10.0.1.7): 56 data bytes64 bytes from 10.0.1.7: seq=0 ttl=64 time=0.094 ms--- whoami ping statistics ---1 packets transmitted, 1 packets received, 0% packet lossround-trip min/avg/max = 0.094/0.094/0.094 ms# 将 whoami 容器的副本数提高$ docker service scale whoami=2$ docker service lsID NAME MODE REPLICAS IMAGE PORTS2q0kyr5r8zg5 client replicated 1/1 busybox:latestlyufxfn8i71j whoami replicated 2/2 jwilder/whoami:latest *:8000->8000/tcp# 进入到 client 容器中ping whoami容器$ docker exec -it client.1.e42t62lhm64oq4bw9onhzsonu sh# 默认访问的是VIP 虚拟IP地址(类似于负载均衡器的作用)/ # ping -c1 -W1 whoamiPING whoami (10.0.1.7): 56 data bytes64 bytes from 10.0.1.7: seq=0 ttl=64 time=0.094 ms--- whoami ping statistics ---1 packets transmitted, 1 packets received, 0% packet lossround-trip min/avg/max = 0.094/0.094/0.094 ms/ # nslookup whoamiServer: 127.0.0.11Address: 127.0.0.11:53Name: whoamiAddress 1: 10.0.1.7# 访问实际的后端的容器IP地址/ # ping -c1 -W1 tasks.whoamiPING tasks.whoami (10.0.1.8): 56 data bytes64 bytes from 10.0.1.8: seq=0 ttl=64 time=0.097 ms--- tasks.whoami ping statistics ---1 packets transmitted, 1 packets received, 0% packet lossround-trip min/avg/max = 0.097/0.097/0.097 ms/ # ping -c1 -W1 tasks.whoamiPING tasks.whoami (10.0.1.11): 56 data bytes64 bytes from 10.0.1.11: seq=0 ttl=64 time=0.075 ms--- tasks.whoami ping statistics ---1 packets transmitted, 1 packets received, 0% packet lossround-trip min/avg/max = 0.075/0.075/0.075 ms/ # nslookup tasks.whoami/ # wget whoami:8000Connecting to whoami:8000 (10.0.1.7:8000)saving to 'index.html'index.html 100% |*****************************************************************| 17 0:00:00 ETA'index.html' saved/ # cat index.htmlI'm' 5dcb2d2d44b4/ # rm -f index.html/ # wget whoami:8000Connecting to whoami:8000 (10.0.1.7:8000)saving to 'index.html'index.html 100% |*****************************************************************| 17 0:00:00 ETA'index.html' saved/ # cat index.htmlI'm' c244936d3a7b
7.4.2 Routing Mesh 的两种实现
- Internal —— Container 和 Container 之间的访问通过 overlay 网络 ( 通过VIP虚拟IP )
- Ingress —— 如果服务有绑定接口,则此服务可以通过任意 swarm 节点的相应接口访问
:::color2 Internel Load Balancing
:::


:::color2 DNS + VIP + iptables + LVS
:::

7.4.3 Ingress Network

- 外部访问的负载均衡
- 服务端口被暴露到各个swarm节点
- 内部通过IPVS进行负载均衡
$ docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami$ docker service lsID NAME MODE REPLICAS IMAGE PORTSlyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp# 测试效果$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESc244936d3a7b jwilder/whoami:latest "/app/http" 8 seconds ago Up 6 seconds 8000/tcp whoami.1.ib70al0738hsu3idmoxqpd658$ docker service scale whoami=2$ docker service lsID NAME MODE REPLICAS IMAGE PORTSlyufxfn8i71j whoami replicated 2/2 jwilder/whoami:latest *:8000->8000/tcp$ curl 127.0.0.1:8000I'm' 5dcb2d2d44b4$ curl 127.0.0.1:8000I'm' c244936d3a7b
# 查看 iptables 转发规则$ iptables -vnL -t natChain DOCKER-INGRESS (2 references)pkts bytes target prot opt in out source destination12 624 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 to:172.28.0.2:80009767 455K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0# 查看本机的网卡配置$ ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ffinet 192.168.0.64/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0valid_lft 78847sec preferred_lft 78847secinet6 fe80::f816:3eff:fe6b:c203/64 scope linkvalid_lft forever preferred_lft forever3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group defaultlink/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::42:c5ff:fe3b:4b05/64 scope linkvalid_lft forever preferred_lft forever266: docker_gwbridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:ce:ad:01:2d brd ff:ff:ff:ff:ff:ffinet 172.28.0.1/16 brd 172.28.255.255 scope global docker_gwbridgevalid_lft forever preferred_lft foreverinet6 fe80::42:ceff:fead:12d/64 scope linkvalid_lft forever preferred_lft forever# 使用python的json模块或者jq美化输出$ yum install -y jq && yum install -y ipvsadm$ docker network inspect -f "{{json .Containers}}" docker_gwbridge | jq{"5dcb2d2d44b4d6fecb67ab2ef2c2bd4c77455668e7d64e413529ff902809e796": {"Name": "gateway_20bb87568f17","EndpointID": "ba0a5c05a375ecc80344ea8347a23dff40e14a43483372d8dc65d5b0da156916","MacAddress": "02:42:ac:1c:00:07","IPv4Address": "172.28.0.7/16","IPv6Address": ""},"ac78df3a00dd3da44749ef7ece9f0a7b028123fa417a76f49b111f62943646cb": {"Name": "gateway_a8c1106c4cbc","EndpointID": "619d81e415d146174895dc8a3d91cf62284f81656c03082ec091a762fbfd21b6","MacAddress": "02:42:ac:1c:00:06","IPv4Address": "172.28.0.6/16","IPv6Address": ""},"c244936d3a7b214528171854e247684c0f31e4fc4cbe89e1375d2087801c1c57": {"Name": "gateway_973350406e56","EndpointID": "6cca3c43a5b22677514c38816782bee0da2d17cd1a67e4bd08c808345aa62879","MacAddress": "02:42:ac:1c:00:05","IPv4Address": "172.28.0.5/16","IPv6Address": ""},"ingress-sbox": {"Name": "gateway_ingress-sbox","EndpointID": "ed635ca990e0903788385e4236110781954afd85909f826b9baa61e25d9e051f","MacAddress": "02:42:ac:1c:00:02","IPv4Address": "172.28.0.2/16","IPv6Address": ""}}$ ls -l /var/run/docker/netns/ | grep ingress_sbox-r--r--r-- 1 root root 0 Nov 10 10:49 ingress_sbox# 进入到 ingress_sbox 的网络名称空间$ nsenter --net=/var/run/docker/netns/ingress_sbox$ ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever264: eth0@if265: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group defaultlink/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 10.0.0.2/24 brd 10.0.0.255 scope global eth0valid_lft forever preferred_lft foreverinet 10.0.0.5/32 scope global eth0valid_lft forever preferred_lft forever267: eth1@if268: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:ac:1c:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 1inet 172.28.0.2/16 brd 172.28.255.255 scope global eth1valid_lft forever preferred_lft forever# 查看 ingress_sbox 的网络名称空间流量走向$ iptables -vnL -t mangleChain PREROUTING (policy ACCEPT 78 packets, 4999 bytes)pkts bytes target prot opt in out source destination54 3130 MARK tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 MARK set 0x104Chain INPUT (policy ACCEPT 48 packets, 2732 bytes)pkts bytes target prot opt in out source destination0 0 MARK all -- * * 0.0.0.0/0 10.0.0.5 MARK set 0x104Chain FORWARD (policy ACCEPT 30 packets, 2267 bytes)pkts bytes target prot opt in out source destinationChain OUTPUT (policy ACCEPT 48 packets, 2732 bytes)pkts bytes target prot opt in out source destinationChain POSTROUTING (policy ACCEPT 78 packets, 4999 bytes)pkts bytes target prot opt in out source destination$ ipvsadm -lIP Virtual Server version 1.2.1 (size=4096)Prot LocalAddress:Port Scheduler Flags-> RemoteAddress:Port Forward Weight ActiveConn InActConnFWM 260 rr# 对应的是 whoami 的容器IP地址-> 10.0.0.6:0 Masq 1 0 0-> 10.0.0.7:0 Masq 1 0 0
:::color5 Ingress Network 的数据包走向详情
:::

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

8.1 Docker Stack 部署 WordPress
Docker Compose Version 3 Reference:https://docs.docker.com/compose/compose-file/compose-file-v3/
#创建一个项目的文件夹(这就是项目名project)$ mkdir /opt/my_wordpress ; cd /opt/my_wordpress$ vim docker-compose.ymlversion: "3.9"services:db:# We use a mariadb image which supports both amd64 & arm64 architectureimage: mariadb:10.6.4-focal# If you really want to use MySQL, uncomment the following line#image: mysql:8.0.27command: '--default-authentication-plugin=mysql_native_password'volumes:- db_data:/var/lib/mysqlrestart: alwaysenvironment:- MYSQL_ROOT_PASSWORD=somewordpress- MYSQL_DATABASE=wordpress- MYSQL_USER=wordpress- MYSQL_PASSWORD=wordpressexpose:- 3306- 33060networks:- my-networksdeploy:mode: globalplacement:constraints:- "node.role==manager"web:image: wordpress:latestports:- 80:80restart: alwaysenvironment:- WORDPRESS_DB_HOST=db- WORDPRESS_DB_USER=wordpress- WORDPRESS_DB_PASSWORD=wordpress- WORDPRESS_DB_NAME=wordpressnetworks:- my-networksdepends_on:- dbdeploy:mode: replicatedreplicas: 3restart_policy:condition: on-failuredelay: 5smax_attempts: 3update_config:parallelism: 1delay: 10sorder: stop-firstvolumes:db_data:networks:my-networks:driver: overlay# 启动Docker Stack项目$ docker stack deploy wordpress --compose-file docker-compose.ymlCreating network wordpress_my-networksCreating service wordpress_dbCreating service wordpress_web# 查看Docker Stack项目$ docker stack lsNAME SERVICES ORCHESTRATORwordpress 2 Swarm$ docker stack ps wordpressID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTSjzt5ip9zkiix wordpress_db.dracuxro5id7nku0vrn7azgtt mariadb:10.6.4-focal gz-kubesphere-node Running Running 2 minutes agott6bwucxisb3 wordpress_web.1 wordpress:latest gz-kubesphere-node Running Running 2 minutes agoocd5up0c2kfr wordpress_web.2 wordpress:latest gz-kubesphere-node Running Running 2 minutes agoup5u96qrwa7m wordpress_web.3 wordpress:latest gz-kubesphere-node Running Running 2 minutes ago# 使用浏览器登录平台
http://:80 后续的操作就是 WordPress 根据引导进行部署即可



:::color1
目前的IT主流的技术:Linux + Docker + Kubernetes(掌握) 掌握的技术:Docker 基础、原理、网络、服务、集群、错误排查、日志:::
# 删除Docker Stack项目docker stack rm wordpress
8.2 部署一个复杂的投票应用

# GitHub Reference:# https://github.com/dockersamples/example-voting-app$ mkdir -pv example-voting-app ; cd example-voting-app$ git clone https://github.com/dockersamples/example-voting-app.git# 将压缩包进行解压# $ unzip example-voting-app-master.zip$ cat ./example-voting-app/docker-stack.ymlversion: "3"services:redis:image: redis:alpinenetworks:- frontenddeploy:replicas: 1update_config:parallelism: 2delay: 10srestart_policy:condition: on-failuredb:image: postgres:9.4environment:POSTGRES_USER: "postgres"POSTGRES_PASSWORD: "postgres"volumes:- db-data:/var/lib/postgresql/datanetworks:- backenddeploy:placement:constraints: [node.role == manager]vote:image: dockersamples/examplevotingapp_vote:beforeports:- 5000:80networks:- frontenddepends_on:- redisdeploy:replicas: 2update_config:parallelism: 2restart_policy:condition: on-failureresult:image: dockersamples/examplevotingapp_result:beforeports:- 5001:80networks:- backenddepends_on:- dbdeploy:replicas: 1update_config:parallelism: 2delay: 10srestart_policy:condition: on-failureworker:image: dockersamples/examplevotingapp_workernetworks:- frontend- backenddepends_on:- db- redisdeploy:mode: replicatedreplicas: 1labels: [APP=VOTING]restart_policy:condition: on-failuredelay: 10smax_attempts: 3window: 120splacement:constraints: [node.role == manager]visualizer:image: dockersamples/visualizer:stableports:- "8080:8080"stop_grace_period: 1m30svolumes:- "/var/run/docker.sock:/var/run/docker.sock"deploy:placement:constraints: [node.role == manager]networks:frontend:backend:volumes:db-data:
运行 Docker Stack 项目(查看Stack项目状态)
$ docker stack deploy --compose-file docker-stack.yml voteCreating network vote_frontendCreating network vote_backendCreating network vote_defaultCreating service vote_voteCreating service vote_resultCreating service vote_workerCreating service vote_visualizerCreating service vote_redisCreating service vote_db$ docker stack lsNAME SERVICES ORCHESTRATORvote 6 Swarm# 需要等待所有的容器启动成功$ docker stack services voteID NAME MODE REPLICAS IMAGE PORTS5fbyhua4lrcc vote_db replicated 1/1 postgres:9.41mryq3wt80f1 vote_redis replicated 1/1 redis:alpinec47lnwxyb5ua vote_result replicated 1/1 dockersamples/examplevotingapp_result:before *:5001->80/tcpqcm0mjkfaetv vote_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcpt8ulyhamy1kt vote_vote replicated 2/2 dockersamples/examplevotingapp_vote:before *:5000->80/tcplubk1ee2fxc2 vote_worker replicated 1/1 dockersamples/examplevotingapp_worker:latest$ docker stack ps voteID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTSi7uyw26p4kht vote_db.1 postgres:9.4 gz-kubesphere-node Running Running 32 seconds agokuvghwnalv3w vote_redis.1 redis:alpine gz-kubesphere-node Running Running 2 minutes ago3v1gar3ixljt vote_result.1 dockersamples/examplevotingapp_result:before gz-kubesphere-node Running Running 7 minutes agotckb1qxa9t9v vote_visualizer.1 dockersamples/visualizer:stable gz-kubesphere-node Running Running 2 minutes agolouvev5676x7 vote_vote.1 dockersamples/examplevotingapp_vote:before gz-kubesphere-node Running Running 9 minutes agoxxd8264mka54 vote_vote.2 dockersamples/examplevotingapp_vote:before gz-kubesphere-node Running Running 9 minutes agoibus8q5i6f2y vote_worker.1 dockersamples/examplevotingapp_worker:latest gz-kubesphere-node Running Running 29 seconds ago
# 投票的页面http://110.41.20.249:5000/# 统计的页面http://110.41.20.249:5001/

访问 Docker Stack 的可视化界面
# Docker Stack 的可视化界面http://110.41.20.249:8080/

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位,随便你写)
:::
+ 选择local选项卡后本地docker详细信息显示
+ 上一步的图形展示,以及对应的docker命令
bash
$ docker system df
# Stack 是docker-compose
### 8.3.2 相关报错
在启动Docker 容器时,会出现报错:Error response from daemon: driver failed programming external connectivity on endpoint XXX(端口映射或启动容器时报错)
解决方法:
:::warning
输入指令:systemctl restart docker。重启Docker服务即可重新生成自定义链DOCKER
:::
## 8.4 登录并演示介绍常用操作 case
查看容器的资源占用
创建容器实例
根据引导对容器的配置进行修改
## 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的概念:服务可理解为发布到生产环境时某组容器的预期状态 ,以及强化了( 复制集、 容器重启策略、回滚策略、服务更新策略 )等生产特性
总结:
- docker-compose 更像是被定义为单机容器编排工具
- docker stack为适用于生产环境的编排工具
<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认证信息、其他需保密数据)进行加密。

<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管理:
- 存在
<font style="color:rgb(0, 0, 0);">swarm manager</font>节点<font style="color:rgb(0, 0, 0);">raft database</font>里; <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>;- 在
<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 认证
- 任何不想让别人看到的数据

9.1.2 Docker Secret 创建
使用文件创建 Docker Secret
$ docker secret create"docker secret create" requires at least 1 and at most 2 arguments.See 'docker secret create --help'.Usage: docker secret create [OPTIONS] SECRET [file|-]Create a secret from a file or STDIN as content# 本地创建一个文件$ vim passwordAdmin@h3c# 创建一个Docker Secret$ docker secret create my-pwd passwordpej64bng7hfo6d25ve3wqtsuh# 创建完毕后将 password 文件删除# 查看Docker Secret的列表$ docker secret lsID NAME DRIVER CREATED UPDATEDpej64bng7hfo6d25ve3wqtsuh my-pwd 7 minutes ago 7 minutes ago
使用管道符创建Docker Secret
$ echo "adminadmin" | docker secret create my-passwd -4ytq5cy4ph4r39h9w20ynj8ep$ docker secret lsID NAME DRIVER CREATED UPDATED4ytq5cy4ph4r39h9w20ynj8ep my-passwd 3 minutes ago 3 minutes agopej64bng7hfo6d25ve3wqtsuh my-pwd 12 minutes ago 12 minutes ago# 删除 Docker Secret$ docker secret rm my-passwd
使用 Docker Secret
# 可以使用多次--secret 传入多个Docker Secret的值$ docker service create --name client --secret my-pwd busybox sh -c "while true;do sleep 3600;done"$ docker service lsID NAME MODE REPLICAS IMAGE PORTSxi4qklnu2afm client replicated 1/1 busybox:latest$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESce98fc881bac busybox:latest "sh -c 'while true;d…" 27 seconds ago Up 26 seconds client.1.qnzbctl8qel7g9gt6h1ixnuhy# 进入到client的容器中$ docker exec -it client.1.qnzbctl8qel7g9gt6h1ixnuhy sh/ # cd /run/secrets//run/secrets # ls -ltotal 4-r--r--r-- 1 root root 10 Nov 11 09:00 my-pwd/run/secrets # cat my-pwdAdmin@h3c
范例:MySQL 使用 Docker Secret
$ docker service create --name db --secret my-pwd -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pwd mysql:5.7.40$ docker service lsID NAME MODE REPLICAS IMAGE PORTS4yqgzc70q73w db replicated 1/1 mysql:5.7.40# 查看容器状态$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES0f1012d87066 mysql:5.7.40 "docker-entrypoint.s…" 43 seconds ago Up 41 seconds 3306/tcp, 33060/tcp db.1.j5ihhu78b3hyruveyyhgzwqwc# 进入到容器控制台$ docker exec -it db.1.j5ihhu78b3hyruveyyhgzwqwc bashbash-4.2# ls -l /run/secrets/my-pwd-r--r--r-- 1 root root 10 Nov 11 09:06 /run/secrets/my-pwdbash-4.2# cat /run/secrets/my-pwdAdmin@h3cbash-4.2# mysql -uroot -pAdmin@h3cmysql: [Warning] Using a password on the command line interface can be insecure.Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 2Server version: 5.7.40 MySQL Community Server (GPL)Copyright (c) 2000, 2022, Oracle and/or its affiliates.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys |+--------------------+4 rows in set (0.00 sec)
9.2 Docker Secret 在 Docker Stack 的使用
编辑 docker-compose.yml在各个 service 下添加:secrets 参数 和 environment 参数
eg: docker-compose.yml,secrets是直接从文件中读取,这种方式是创建和使用一起做
#例如:services:web:image: wordpresssecrets:- my-passenvironment:WORDPRESS_DB_HOST: mysqlWORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pass...
eg: docker-compose.yml,这种方式是password secrets先创建好,然后在使用
version: '3.1'services:db:image: mysql:5.7.27volumes:- db_data:/var/lib/mysqlenvironment:MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_passwordMYSQL_DATABASE: wordpressMYSQL_USER: wordpressMYSQL_PASSWORD_FILE: /run/secrets/db_passwordsecrets:- db_root_password- db_passwordwordpress:depends_on:- dbimage: wordpress:latestports:- "8888:80"environment:WORDPRESS_DB_HOST: db:3306WORDPRESS_DB_USER: wordpressWORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_passwordsecrets:- db_passwordsecrets:db_password:file: password.txtdb_root_password:file: password.txtvolumes:db_data:
version: '3.1'services:db:image: mysql:5.7.27volumes:- db_data:/var/lib/mysqlenvironment:MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_passwordMYSQL_DATABASE: wordpressMYSQL_USER: wordpressMYSQL_PASSWORD_FILE: /run/secrets/db_passwordsecrets:- my-pwwordpress:depends_on:- dbimage: wordpress:latestports:- "8888:80"environment:WORDPRESS_DB_HOST: db:3306WORDPRESS_DB_USER: wordpressWORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_passwordsecrets:- my-pwvolumes:db_data:
Docker Secret 在 Docker Stack 实例:
cat > docker-compose.yml <<EOFversion: '3.9'services:web:image: wordpress:latestports:- 10880:80secrets:- my-pwdenvironment:WORDPRESS_DB_HOST: db:3306WORDPRESS_DB_USER: "root"WORDPRESS_DB_NAME: "wordpress"# WORDPRESS_DB_PASSWORD: "/run/secrets/my-pwd"WORDPRESS_DB_PASSWORD_FILE: "/run/secrets/my-pwd"networks:- my-networkvolumes:- wordpress_config:/var/www/htmldepends_on:- dbdeploy:mode: replicated# 一个副本数replicas: 1restart_policy:condition: on-failuredelay: 5smax_attempts: 3update_config:parallelism: 1delay: 10sdb:image: mariadb:10.6.4-focalcommand: '--default-authentication-plugin=mysql_native_password'volumes:- db_data:/var/lib/mysql- db_config:/etc/mysqlports:- 3306:3306environment:MYSQL_ROOT_PASSWORD_FILE: "/run/secrets/my-pwd"MYSQL_DATABASE: "wordpress"MYSQL_USER: "wordpress"MYSQL_PASSWORD_FILE: "/run/secrets/my-pwd"secrets:- my-pwdnetworks:- my-networkdeploy:mode: globalplacement:constraints:- "node.role==manager"volumes:db_data: {}db_config: {}wordpress_config: {}networks:my-network:driver: overlaysecrets:my-pwd:file: ./password.txtEOF
cat > password.txt <<EOFadmin123EOF# MySQL配置文件(可选择)cat > mysql.cnf <<EOF[client]default-character-set=utf8[mysql]default-character-set=utf8[mysqld]skip-grant-tablespid-file = /var/run/mysqld/mysqld.pidsocket = /var/run/mysqld/mysqld.sockdatadir = /var/lib/mysql#log-error = /var/log/mysql/error.log# By default we only accept connections from localhost#bind-address = 127.0.0.1# Disabling symbolic-links is recommended to prevent assorted security riskssymbolic-links=0lower_case_table_names=1init_connect='SET collation_connection = utf8_general_ci'init_connect='SET NAMES utf8'character-set-server=utf8collation-server=utf8_general_cimax_connections = 1000EOF
启动 Docker Stack 项目
# 启用 Docker Stack 项目$ docker stack deploy wordpress --compose-file docker-compose.yml$ docker stack lsNAME SERVICES ORCHESTRATORwordpress 2 Swarm# 查看Docker Stack的状态$ docker stack ps wordpressID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTSimh1o7tcgx57 wordpress_db.dracuxro5id7nku0vrn7azgtt mariadb:10.6.4-focal gz-kubesphere-node Running Running 12 seconds agozalthk69hso1 wordpress_web.1 wordpress:latest gz-kubesphere-node Running Running 27 seconds ago# 查看服务的副本状态$ docker service lsID NAME MODE REPLICAS IMAGE PORTSwjax6djbozp4 wordpress_db global 1/1 mariadb:10.6.4-focalrtlbuvua6gak wordpress_web replicated 1/1 wordpress:latest *:10880->80/tcp# 删除 Docker Stack 项目$ docker stack rm wordpress
http://: 10880 后续的操作就是 WordPress 根据引导进行部署即可



9.3 Docker Service 更新
编写Shell脚本一直访问
# 创建一个 Overlay 的网络模式$ docker network create -d overlay demo$ docker network lsNETWORK ID NAME DRIVER SCOPEceb235716540 bridge bridge localmngekyo6uepz demo overlay swarm0e660fabfa96 docker_gwbridge bridge locala40831f989fe host host local610mgoxey5g7 ingress overlay swarmf314686d0f0f none null local# 使用Dockerfile创建相应的web镜像$ vim app.pyfrom flask import Flaskapp = Flask(__name__)@app.route('/')def hello():return "hello docker , version 1.0"if __name__ == '__main__':app.run()$ vim DockerfileFROM python:2.7LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"RUN pip install flask && \mkdir -pv /appWORKDIR /appADD app.py /app/CMD [ "python", "app.py" ]EXPOSE 5000$ docker build -t flask-demo:v1.0 -f Dockerfile .$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEflask-demo v1.0 7c259632347e 5 seconds ago 906MB# Service使用Overlay网络模式创建$ docker service create --name web --publish 8080:5000 --network demo flask-demo:v1.0$ docker service ps webID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTSwkwflwfm9x9t web.1 flask-demo:v1.0 gz-kubespere-docker Running Running about a minute ago# 增加Service的副本数$ docker service scale web=2$ docker service ps webID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTSwkwflwfm9x9t web.1 flask-demo:v1.0 gz-kubespere-docker Running Running 2 minutes agowwhln2hek0mh web.2 flask-demo:v1.0 gz-kubespere-docker Running Running 25 seconds ago# 检查服务运行是否正常$ curl 127.0.0.1:8080hello docker , version 1.0
更新镜像到2.0
sh -c "while true;do curl 127.0.0.1:8080 && sleep 1;done"
中间没有发生中断操作,直接升级成了2.0
更新访问服务的端口
# 使用Dockerfile创建相应的web镜像$ vim app.pyfrom flask import Flaskapp = Flask(__name__)@app.route('/')def hello():return "hello docker , version 2.0"if __name__ == '__main__':app.run()$ vim DockerfileFROM python:2.7LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"RUN pip install flask && \mkdir -pv /appWORKDIR /appADD app.py /app/CMD [ "python", "app.py" ]EXPOSE 5000# 构建2.0镜像$ docker build -t flask-demo:v2.0 -f Dockerfile .# 更新镜像到2.0docker service update --image flask-demo:2.0 web# 1.0已经shutdown了,启动了2.0docker service ps web
端口更新可能存在业务中断的情况
docker service update --publish-rm 8080:5000 --publish-add 8088:5000 webdocker service ps webdocker 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:

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
主要模块:::

:::color5
主要有两种运行模式::::
- Standard 模式。一个Node就是一个Docker Host
- Swarm 模式(beta)。多个Node组成的Swarm Cluster
:::color5 DevOps 流程
:::

10.2 Docker Cloud 之自动 build Docker Images
您可以访问以下链接以开始使用Docker Cloud - https://cloud.docker.com/ > Reference:http://github.com/imooc-course/docker-cloud/flask-demo >
登录后,您将获得以下基本界面 -

10.2.1 连接到云提供商
第一步是连接到现有的云提供商。以下步骤将向您展示如何与Amazon Cloud提供商进行连接。步骤1 - 第一步是确保您拥有正确的AWS密钥。这可以从aws控制台取出。使用以下链接登录您的aws帐户 - https://aws.amazon.com/console/

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

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

步骤4 - 点击“创建自己的策略”,并将策略名称作为dockercloudpolicy和策略定义,如下所示。
{"Version": "2012-10-17","Statement": [ {"Action": ["ec2:*","iam:ListInstanceProfiles"],"Effect": "Allow","Resource": "*"} ]}

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

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

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

步骤8 - 在下一个屏幕上,输入以下详细信息 -
- 在“帐户ID”字段中,输入Docker Cloud服务的ID:689684103426。
- 在外部ID字段中,输入您的Docker Cloud用户名。

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

步骤10 - 最后,在创建角色的最后一个屏幕上,确保复制创建的arn角色。
arn:aws:iam::085363624145:role/dockercloud-role

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



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

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


10.2.3 部署服务
部署节点后的下一步是部署服务。为此,我们需要执行以下步骤。步骤1 - 转到Docker Cloud 的服务部门。单击创建按钮

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

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


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
前提条件
如果您还未创建集群,您需要先创建集群。有关如何创建集群的详细信息,参见创建集群。操作步骤
- 登录容器服务管理控制台。
- 单击左侧导航栏中的应用 并单击右上角的创建应用,如下图所示。

- 输入应用相关信息,单击使用镜像创建。 - 应用名称:要创建的应用的名称。本示例中,应用名称为 nginx。 - 应用版本:所创建应用的版本。默认为 1.0。 - 部署集群:要部署到的集群。 - 默认更新策略:应用更新的方式,您可以选择标准发布 或蓝绿发布,参见 发布策略说明。 - 应用描述:应用的相关信息。该信息将显示在应用列表页面。 - 检查最新 Docker 镜像:选中该选项后,表示当镜像 Tag 不变的情况下,也会去仓库拉取最新的镜像。为了提高效率,容器服务会对镜像进行缓存。部署时,如果发现镜像 Tag 与本地缓存的一致,则会直接复用而不重新拉取。所以,如果您基于上层业务便利性等因素考虑,在做代码和镜像变更时没有同步修改 Tag ,就会导致部署时还是使用本地缓存内旧版本镜像。而勾选该选项后,会忽略缓存,每次部署时重新拉取镜像,确保使用的始终是最新的镜像和代码。
- 单击选择镜像。在搜索框中输入nginx,单击全局搜索。在搜索结果中选择nginx,单击确定。容器服务会默认使用镜像的最新版本。如果您需要使用镜像的其它版本,单击选择镜像版本,单击所需版本并单击确定。


- 在端口映射中配置容器与主机的端口映射。为了能够通过公网访问容器内的 Nginx 服务器,我们还需要配置简单路由配置。
说明 您也可以填写自己的域名,关于如何添加您的自有域名,参见 简单路由-域名配置。关于配置路由的容器端口和 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。 - 单击创建。容器服务根据以上设置创建应用 nginx。
- 单击查看应用列表,返回应用列表 或左侧导航栏中的 应用 返回应用列表。如下图所示,单击应用名称nginx,查看应用详情。

- 在服务列表中,单击服务名称nginx,进入服务 nginx 页面。

- 单击服务 nginx 的访问端点,即可进入 Nginx 服务器的默认欢迎页面。

11.2.2 在阿里云安装 DockerEE
Video Reference:https://www.bilibili.com/video/BV1xe4y1q7fC?p=67
