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/bash
DOCKER_VERSION="20.10.10"
#UBUNTU_DOCKER_VERSION="5:${DOCKER_VERSION}~3-0~`lsb_release -si`-`lsb_release -cs`"
DOCKER_COMPOSE_VERSION=1.29.2
DOCKER_COMPOSE_FILE=docker-compose-Linux-x86_64
COLOR_SUCCESS="echo -e \\033[1;32m"
COLOR_FAILURE="echo -e \\033[1;31m"
END="\033[m"
. /etc/os-release
color () {
RES_COL=60
MOVE_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_COL
echo -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" ];then
if [ $VERSION_ID = "7" ];then
cat > /etc/yum.repos.d/docker.repo <<EOF
[docker]
name=docker
gpgcheck=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/
EOF
else
cat > /etc/yum.repos.d/docker.repo <<EOF
[docker]
name=docker
gpgcheck=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/
EOF
fi
yum 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 5
yum -y install docker-ce-$DOCKER_VERSION docker-ce-cli-$DOCKER_VERSION \
|| { color "Base,Extras的yum源失败,请检查yum源配置" 1;exit; }
else
dpkg -s docker-ce &> /dev/null && $COLOR"Docker已安装,退出" 1 && exit
apt 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 5
apt -y install docker-ce=${UBUNTU_DOCKER_VERSION} docker-ce-cli=${UBUNTU_DOCKER_VERSION}
fi
if [ $? -eq 0 ];then
color "安装软件包成功" 0
else
color "安装软件包失败,请检查网络配置" 1
exit
fi
mkdir -p /etc/docker
tee /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"]
}
EOF
systemctl daemon-reload
systemctl enable docker
systemctl restart docker
docker version && color "Docker 安装成功" 0 || color "Docker 安装失败" 1
echo 'alias rmi="docker images -qa|xargs docker rmi -f"' >> ~/.bashrc
echo '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 1
if [ ! -e ${DOCKER_COMPOSE_FILE} ];then
curl -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-compose
else
mv ${DOCKER_COMPOSE_FILE} /usr/bin/docker-compose
fi
chmod +x /usr/bin/docker-compose
else
apt -y install docker-compose
fi
if docker-compose --version ;then
${COLOR_SUCCESS}"Docker Compose 安装完成"${END}
else
${COLOR_FAILURE}"Docker compose 安装失败"${END}
exit
fi
}
install_docker
install_docker_compose
初始化 Docker Swarm
# 初始化 Master 节点
$ docker swarm init --advertise-addr 10.0.0.101
Swarm 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:2377
To 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 ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
kdl65arb5xhld1s1ogc78gur7 * docker-node01 Ready Active Leader 19.03.11
pzubdmyszq0or4rtk45lzihts docker-node02 Ready Active 19.03.11
dvl2e5upon3bklq77ijzkp100 docker-node03 Ready Active 20.10.10
(可以使用 Docker-Machine 来创建三个节点)
# 创建Master节点(一个节点)
docker-machine create swarm-manager
# 创建Worker节点(两个节点)
docker-machine create swarm-node01
docker-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 ls
ID NAME MODE REPLICAS IMAGE PORTS
dyenfcor78te busybox-node replicated 1/1 busybox:latest
# 查看Service详细信息
$ docker service ps busybox-node
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running about a minute ago
# 在 docker-node03 查看Docker进程信息
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3cb69e5b3cc5 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 ls
ID NAME MODE REPLICAS IMAGE PORTS
dyenfcor78te busybox-node replicated 3/3 busybox:latest
# 平均分配到各个节点中运行
$ docker service ps busybox-node
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running 7 minutes ago
q3w8bdvu9141 busybox-node.2 busybox:latest docker-node02 Running Running 47 seconds ago
pyhxitis9kr3 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 ls
ID NAME MODE REPLICAS IMAGE PORTS
dyenfcor78te busybox-node replicated 2/3 busybox:latest
# 其Docker Service具有自恢复能力
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
dyenfcor78te busybox-node replicated 3/3 busybox:latest
$ docker service ps busybox-node
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
7jfml4o5yklf busybox-node.1 busybox:latest docker-node03 Running Running 10 minutes ago
xtl92syb8d01 busybox-node.2 busybox:latest docker-node02 Running Running about a minute ago
q3w8bdvu9141 \_ 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 ls
NETWORK ID NAME DRIVER SCOPE
d0ba97d9a9e1 bridge bridge local
1u4udx1r0c6p demo overlay swarm
458e32a2a13c docker_gwbridge bridge local
0959653f62aa host host local
j59uwl8alp6o ingress overlay swarm
891c07cd5918 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 ls
ID NAME MODE REPLICAS IMAGE PORTS
vqcbgslbbewv db replicated 1/1 mariadb:10.6.4-focal
$ docker service ps db
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
y1fw949ohrb7 db.1 mariadb:10.6.4-focal docker-node01 Running Running 24 seconds ago
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ece3013b7150 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 ls
ID NAME MODE REPLICAS IMAGE PORTS
vqcbgslbbewv db replicated 1/1 mariadb:10.6.4-focal
zowojzszkrub wordpress replicated 1/1 wordpress:latest *:80->80/tcp
$ docker service ps wordpress
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
azileh6g4kjl wordpress.1 wordpress:latest docker-node02 Running Running about a minute ago
# 在Docker Node 查看Docker 进程
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f283b8b2d6a1 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 ls
ID NAME MODE REPLICAS IMAGE PORTS
lyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp
# 测试效果
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c244936d3a7b jwilder/whoami:latest "/app/http" 8 seconds ago Up 6 seconds 8000/tcp whoami.1.ib70al0738hsu3idmoxqpd658
$ curl 127.0.0.1:8000
I'm c244936d3a7b
# 创建第二个Service
$ docker service create --name client -d --network demo busybox sh -c "while true;do sleep 3600;done"
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
2q0kyr5r8zg5 client replicated 1/1 busybox:latest
lyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp
# 进入到 client 容器中ping whoami容器
$ docker exec -it client.1.e42t62lhm64oq4bw9onhzsonu sh
/ # ping -c1 -W1 whoami
PING whoami (10.0.1.7): 56 data bytes
64 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 loss
round-trip min/avg/max = 0.094/0.094/0.094 ms
# 将 whoami 容器的副本数提高
$ docker service scale whoami=2
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
2q0kyr5r8zg5 client replicated 1/1 busybox:latest
lyufxfn8i71j 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 whoami
PING whoami (10.0.1.7): 56 data bytes
64 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 loss
round-trip min/avg/max = 0.094/0.094/0.094 ms
/ # nslookup whoami
Server: 127.0.0.11
Address: 127.0.0.11:53
Name: whoami
Address 1: 10.0.1.7
# 访问实际的后端的容器IP地址
/ # ping -c1 -W1 tasks.whoami
PING tasks.whoami (10.0.1.8): 56 data bytes
64 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 loss
round-trip min/avg/max = 0.097/0.097/0.097 ms
/ # ping -c1 -W1 tasks.whoami
PING tasks.whoami (10.0.1.11): 56 data bytes
64 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 loss
round-trip min/avg/max = 0.075/0.075/0.075 ms
/ # nslookup tasks.whoami
/ # wget whoami:8000
Connecting 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.html
I'm' 5dcb2d2d44b4
/ # rm -f index.html
/ # wget whoami:8000
Connecting 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.html
I'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 ls
ID NAME MODE REPLICAS IMAGE PORTS
lyufxfn8i71j whoami replicated 1/1 jwilder/whoami:latest *:8000->8000/tcp
# 测试效果
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c244936d3a7b jwilder/whoami:latest "/app/http" 8 seconds ago Up 6 seconds 8000/tcp whoami.1.ib70al0738hsu3idmoxqpd658
$ docker service scale whoami=2
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
lyufxfn8i71j whoami replicated 2/2 jwilder/whoami:latest *:8000->8000/tcp
$ curl 127.0.0.1:8000
I'm' 5dcb2d2d44b4
$ curl 127.0.0.1:8000
I'm' c244936d3a7b
# 查看 iptables 转发规则
$ iptables -vnL -t nat
Chain DOCKER-INGRESS (2 references)
pkts bytes target prot opt in out source destination
12 624 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 to:172.28.0.2:8000
9767 455K RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
# 查看本机的网卡配置
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.64/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0
valid_lft 78847sec preferred_lft 78847sec
inet6 fe80::f816:3eff:fe6b:c203/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:c5ff:fe3b:4b05/64 scope link
valid_lft forever preferred_lft forever
266: docker_gwbridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ce:ad:01:2d brd ff:ff:ff:ff:ff:ff
inet 172.28.0.1/16 brd 172.28.255.255 scope global docker_gwbridge
valid_lft forever preferred_lft forever
inet6 fe80::42:ceff:fead:12d/64 scope link
valid_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 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
264: eth0@if265: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.0.0.2/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet 10.0.0.5/32 scope global eth0
valid_lft forever preferred_lft forever
267: eth1@if268: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:1c:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 172.28.0.2/16 brd 172.28.255.255 scope global eth1
valid_lft forever preferred_lft forever
# 查看 ingress_sbox 的网络名称空间流量走向
$ iptables -vnL -t mangle
Chain PREROUTING (policy ACCEPT 78 packets, 4999 bytes)
pkts bytes target prot opt in out source destination
54 3130 MARK tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 MARK set 0x104
Chain INPUT (policy ACCEPT 48 packets, 2732 bytes)
pkts bytes target prot opt in out source destination
0 0 MARK all -- * * 0.0.0.0/0 10.0.0.5 MARK set 0x104
Chain FORWARD (policy ACCEPT 30 packets, 2267 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 48 packets, 2732 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 78 packets, 4999 bytes)
pkts bytes target prot opt in out source destination
$ ipvsadm -l
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
FWM 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.yml
version: "3.9"
services:
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10.6.4-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.27
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
- 33060
networks:
- my-networks
deploy:
mode: global
placement:
constraints:
- "node.role==manager"
web:
image: wordpress:latest
ports:
- 80:80
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
networks:
- my-networks
depends_on:
- db
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
order: stop-first
volumes:
db_data:
networks:
my-networks:
driver: overlay
# 启动Docker Stack项目
$ docker stack deploy wordpress --compose-file docker-compose.yml
Creating network wordpress_my-networks
Creating service wordpress_db
Creating service wordpress_web
# 查看Docker Stack项目
$ docker stack ls
NAME SERVICES ORCHESTRATOR
wordpress 2 Swarm
$ docker stack ps wordpress
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
jzt5ip9zkiix wordpress_db.dracuxro5id7nku0vrn7azgtt mariadb:10.6.4-focal gz-kubesphere-node Running Running 2 minutes ago
tt6bwucxisb3 wordpress_web.1 wordpress:latest gz-kubesphere-node Running Running 2 minutes ago
ocd5up0c2kfr wordpress_web.2 wordpress:latest gz-kubesphere-node Running Running 2 minutes ago
up5u96qrwa7m 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.yml
version: "3"
services:
redis:
image: redis:alpine
networks:
- frontend
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
db:
image: postgres:9.4
environment:
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "postgres"
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- 5000:80
networks:
- frontend
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
restart_policy:
condition: on-failure
result:
image: dockersamples/examplevotingapp_result:before
ports:
- 5001:80
networks:
- backend
depends_on:
- db
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
depends_on:
- db
- redis
deploy:
mode: replicated
replicas: 1
labels: [APP=VOTING]
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints: [node.role == manager]
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/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 vote
Creating network vote_frontend
Creating network vote_backend
Creating network vote_default
Creating service vote_vote
Creating service vote_result
Creating service vote_worker
Creating service vote_visualizer
Creating service vote_redis
Creating service vote_db
$ docker stack ls
NAME SERVICES ORCHESTRATOR
vote 6 Swarm
# 需要等待所有的容器启动成功
$ docker stack services vote
ID NAME MODE REPLICAS IMAGE PORTS
5fbyhua4lrcc vote_db replicated 1/1 postgres:9.4
1mryq3wt80f1 vote_redis replicated 1/1 redis:alpine
c47lnwxyb5ua vote_result replicated 1/1 dockersamples/examplevotingapp_result:before *:5001->80/tcp
qcm0mjkfaetv vote_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcp
t8ulyhamy1kt vote_vote replicated 2/2 dockersamples/examplevotingapp_vote:before *:5000->80/tcp
lubk1ee2fxc2 vote_worker replicated 1/1 dockersamples/examplevotingapp_worker:latest
$ docker stack ps vote
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
i7uyw26p4kht vote_db.1 postgres:9.4 gz-kubesphere-node Running Running 32 seconds ago
kuvghwnalv3w vote_redis.1 redis:alpine gz-kubesphere-node Running Running 2 minutes ago
3v1gar3ixljt vote_result.1 dockersamples/examplevotingapp_result:before gz-kubesphere-node Running Running 7 minutes ago
tckb1qxa9t9v vote_visualizer.1 dockersamples/visualizer:stable gz-kubesphere-node Running Running 2 minutes ago
louvev5676x7 vote_vote.1 dockersamples/examplevotingapp_vote:before gz-kubesphere-node Running Running 9 minutes ago
xxd8264mka54 vote_vote.2 dockersamples/examplevotingapp_vote:before gz-kubesphere-node Running Running 9 minutes ago
ibus8q5i6f2y 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位,随便你写)
:::




bash
$ docker system df
# Stack 是docker-compose
### 8.3.2 相关报错
在启动Docker 容器时,会出现报错:Error response from daemon: driver failed programming external connectivity on endpoint XXX(端口映射或启动容器时报错)




- 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 password
Admin@h3c
# 创建一个Docker Secret
$ docker secret create my-pwd password
pej64bng7hfo6d25ve3wqtsuh
# 创建完毕后将 password 文件删除
# 查看Docker Secret的列表
$ docker secret ls
ID NAME DRIVER CREATED UPDATED
pej64bng7hfo6d25ve3wqtsuh my-pwd 7 minutes ago 7 minutes ago
使用管道符创建Docker Secret
$ echo "adminadmin" | docker secret create my-passwd -
4ytq5cy4ph4r39h9w20ynj8ep
$ docker secret ls
ID NAME DRIVER CREATED UPDATED
4ytq5cy4ph4r39h9w20ynj8ep my-passwd 3 minutes ago 3 minutes ago
pej64bng7hfo6d25ve3wqtsuh 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 ls
ID NAME MODE REPLICAS IMAGE PORTS
xi4qklnu2afm client replicated 1/1 busybox:latest
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce98fc881bac 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 -l
total 4
-r--r--r-- 1 root root 10 Nov 11 09:00 my-pwd
/run/secrets # cat my-pwd
Admin@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 ls
ID NAME MODE REPLICAS IMAGE PORTS
4yqgzc70q73w db replicated 1/1 mysql:5.7.40
# 查看容器状态
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0f1012d87066 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 bash
bash-4.2# ls -l /run/secrets/my-pwd
-r--r--r-- 1 root root 10 Nov 11 09:06 /run/secrets/my-pwd
bash-4.2# cat /run/secrets/my-pwd
Admin@h3c
bash-4.2# mysql -uroot -pAdmin@h3c
mysql: [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 2
Server 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 its
affiliates. Other names may be trademarks of their respective
owners.
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: wordpress
secrets:
- my-pass
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pass
...
eg: docker-compose.yml,这种方式是password secrets先创建好,然后在使用
version: '3.1'
services:
db:
image: mysql:5.7.27
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_root_password
- db_password
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8888:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: password.txt
db_root_password:
file: password.txt
volumes:
db_data:
version: '3.1'
services:
db:
image: mysql:5.7.27
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/db_password
secrets:
- my-pw
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8888:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- my-pw
volumes:
db_data:
Docker Secret 在 Docker Stack 实例:
cat > docker-compose.yml <<EOF
version: '3.9'
services:
web:
image: wordpress:latest
ports:
- 10880:80
secrets:
- my-pwd
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: "root"
WORDPRESS_DB_NAME: "wordpress"
# WORDPRESS_DB_PASSWORD: "/run/secrets/my-pwd"
WORDPRESS_DB_PASSWORD_FILE: "/run/secrets/my-pwd"
networks:
- my-network
volumes:
- wordpress_config:/var/www/html
depends_on:
- db
deploy:
mode: replicated
# 一个副本数
replicas: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
db:
image: mariadb:10.6.4-focal
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
- db_config:/etc/mysql
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD_FILE: "/run/secrets/my-pwd"
MYSQL_DATABASE: "wordpress"
MYSQL_USER: "wordpress"
MYSQL_PASSWORD_FILE: "/run/secrets/my-pwd"
secrets:
- my-pwd
networks:
- my-network
deploy:
mode: global
placement:
constraints:
- "node.role==manager"
volumes:
db_data: {}
db_config: {}
wordpress_config: {}
networks:
my-network:
driver: overlay
secrets:
my-pwd:
file: ./password.txt
EOF
cat > password.txt <<EOF
admin123
EOF
# MySQL配置文件(可选择)
cat > mysql.cnf <<EOF
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
skip-grant-tables
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /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 risks
symbolic-links=0
lower_case_table_names=1
init_connect='SET collation_connection = utf8_general_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_general_ci
max_connections = 1000
EOF
启动 Docker Stack 项目
# 启用 Docker Stack 项目
$ docker stack deploy wordpress --compose-file docker-compose.yml
$ docker stack ls
NAME SERVICES ORCHESTRATOR
wordpress 2 Swarm
# 查看Docker Stack的状态
$ docker stack ps wordpress
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
imh1o7tcgx57 wordpress_db.dracuxro5id7nku0vrn7azgtt mariadb:10.6.4-focal gz-kubesphere-node Running Running 12 seconds ago
zalthk69hso1 wordpress_web.1 wordpress:latest gz-kubesphere-node Running Running 27 seconds ago
# 查看服务的副本状态
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
wjax6djbozp4 wordpress_db global 1/1 mariadb:10.6.4-focal
rtlbuvua6gak 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 ls
NETWORK ID NAME DRIVER SCOPE
ceb235716540 bridge bridge local
mngekyo6uepz demo overlay swarm
0e660fabfa96 docker_gwbridge bridge local
a40831f989fe host host local
610mgoxey5g7 ingress overlay swarm
f314686d0f0f none null local
# 使用Dockerfile创建相应的web镜像
$ vim app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "hello docker , version 1.0"
if __name__ == '__main__':
app.run()
$ vim Dockerfile
FROM python:2.7
LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"
RUN pip install flask && \
mkdir -pv /app
WORKDIR /app
ADD app.py /app/
CMD [ "python", "app.py" ]
EXPOSE 5000
$ docker build -t flask-demo:v1.0 -f Dockerfile .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-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 web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
wkwflwfm9x9t web.1 flask-demo:v1.0 gz-kubespere-docker Running Running about a minute ago
# 增加Service的副本数
$ docker service scale web=2
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
wkwflwfm9x9t web.1 flask-demo:v1.0 gz-kubespere-docker Running Running 2 minutes ago
wwhln2hek0mh web.2 flask-demo:v1.0 gz-kubespere-docker Running Running 25 seconds ago
# 检查服务运行是否正常
$ curl 127.0.0.1:8080
hello 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.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "hello docker , version 2.0"
if __name__ == '__main__':
app.run()
$ vim Dockerfile
FROM python:2.7
LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"
RUN pip install flask && \
mkdir -pv /app
WORKDIR /app
ADD app.py /app/
CMD [ "python", "app.py" ]
EXPOSE 5000
# 构建2.0镜像
$ docker build -t flask-demo:v2.0 -f Dockerfile .
# 更新镜像到2.0
docker service update --image flask-demo:2.0 web
# 1.0已经shutdown了,启动了2.0
docker service ps web
端口更新可能存在业务中断的情况
docker service update --publish-rm 8080:5000 --publish-add 8088:5000 web
docker service ps web
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:
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