docker-swarm实战

本文最后更新于 2024年6月17日 凌晨

白嫖阿里服务器

上: https://developer.aliyun.com/plan/grow-up

申请学生认证, 完成俩任务就可以白嫖2周的2核2G阿里云服务器了

步骤

和之前白嫖的Azure服务器一起用

安装docker

1
curl -sSL https://get.daocloud.io/docker | sh

开放端口

根据官方教程, 开放端口

阿里云在云服务ECS/安全组中设置

Azure在设置/网络中设置

创建swarm和manager

阿里云命令行没延迟, 用它当manager

1
docker swarm init --advertise-addr 32.121.74.215

会产生一个token:

1
2
3
4
5
6
7
Swarm initialized: current node (7we8v0yso3js5u56ypk60ffbb) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-3lbmvgaz07xylkgofhukkhmxvescqa8l5b3lasw94ocor5hrp7-b0rtmn323qazz2eidfund4orn 32.121.74.215:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

--advertise-addr <IP>表示将该IP配置为管理者, 产生的token表示其他worker可以用该token加入该集群

可以使用docker info查看当前状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@asdf:~# docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.8.2-docker)
compose: Docker Compose (Docker Inc., v2.6.0)
scan: Docker Scan (Docker Inc., v0.17.0)

Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 20.10.17
...

可以使用docker node ls查看所有节点和信息

加入worker

我们将Azure加入集群:

在manager上运行

1
docker swarm join-token worker

即可查看加入的token和加入命令, 和前面init时一致

1
2
root@moreality:~# docker swarm join --token SWMTKN-1-3lbmvgaz07xylkgofhukkhmxvescqa8l5b3lasw94ocor5hrp7-b0rtmn323qazz2eidfund4orn 32.121.74.215:2377
This node joined a swarm as a worker.

进入worker的机器, 运行:

1
root@asdf:~# docker node ls

即可查看目前的managerworker节点

1
2
3
4
ID                            HOSTNAME                  STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
7we8v0yso3js5u56ypk60ffbb * iZ0jlfl8zktqzybrmxk2s9Z Ready Active Leader 20.10.17
mka9mbeqhivcaxdwqdb29gio3 moreality Ready Active
18.09.7

其中VERSION表示对应机器上docker的版本

创建和加入服务

按照官网输入如下创建服务的命令

1
docker service create --replicas 1 --name helloworld alpine ping docker.com
  • docker service create: 创建服务。
  • --name: 命名服务helloworld
  • --replicas: 指定一个副本运行
  • alpine ping docker.com: 将服务定义为执行命令的 Alpine Linux 容器并运行ping docker.com

然后运行docker service ls就可以查看刚才建立的服务了:

1
2
3
root@asdf:~# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
s119e5qgow4i helloworld replicated 1/1 alpine:latest

查看和监视服务的命令

  • docker service inspect --pretty helloworld: 查看该服务的配置详细信息, 加pretty表示以易读的方式打印, 可以选择不加展示原始的json信息
  • docker service ps <SERVICE-ID>: 查看正在运行该服务的节点
1
2
3
4
5
6
7
8
9
root@asdf:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
7we8v0yso3js5u56ypk60ffbb * asdf Ready Active Leader 20.10.17
mka9mbeqhivcaxdwqdb29gio3 moreality Ready Active
18.09.7

root@asdf:~# docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
mwl78f2p88zi helloworld.1 alpine:latest asdf Running Running 4 minutes ago

则表示该服务证运行在worker节点上(对比NODE和HOSTNAME)

  • 在服务运行的节点上使用docker ps可以查看详细信息

服务扩展 (Scale)

将服务部署后, 可以很轻松的扩展服务的任务数量

在服务(service)中运行的容器(container)称之为任务(task)

运行:

1
docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>

如对于上面的hello world

运行:

1
docker service scale helloworld=5

表示将任务数增加到5个

1
2
3
4
5
6
7
8
9
root@asdf:~# docker service scale helloworld=5
helloworld scaled to 5
overall progress: 5 out of 5 tasks
1/5: running
2/5: running
3/5: running
4/5: running
5/5: running
verify: Service converged

这时我们再在worker上用docker service ps helloworld可以发现:

1
2
3
4
5
6
7
root@asdf:~# docker service ps helloworld;
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
mwl78f2p88zi helloworld.1 alpine:latest asdf Running Running 15 minutes ago
58nn77cngpkk helloworld.2 alpine:latest moreality Running Running 4 minutes ago
ibgir80e5vfc helloworld.3 alpine:latest moreality Running Running 4 minutes ago
vo1de2mmagle helloworld.4 alpine:latest moreality Running Running 4 minutes ago
tg6evmi7uk8u helloworld.5 alpine:latest asdf Running Running 4 minutes ago

任务被均匀地分配到了不同的主机上

服务删除

1
docker service rm helloworld

就把helloworld服务删了

运行

1
2
3
root@asdf:~# docker service inspect helloworld
[]
Status: Error: no such service: helloworld, Code: 1

验证服务被删除

服务滚动升级

在worker上使用:

1
root@asdf:~# docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6

创建3个副本的redis:3.0.6

然后使用:

1
docker service update --image redis:3.0.7 redis

更新redis镜像

一般更新步骤如下:

  • 停止第一个任务。
  • 为已停止的任务安排更新。
  • 启动更新任务的容器。
  • 如果一个任务的更新返回RUNNING,等待指定的延迟时间然后开始下一个任务。
  • 如果在更新期间的任何时间,任务返回FAILED,则暂停更新。

可以使用 docker service inspect --pretty redis查看更新是否失败和错误信息

如果更新失败, 可以直接使用

1
docker service update redis

重新执行更新

可以使用docker service ps redis查看整个滚动更新:

1
2
3
4
5
6
7
8
9
root@asdf:~# docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
ERROR PORTS
nwub9yrzm9q5 redis.1 redis:3.0.7 moreality Running Running about a minute ago
ptauimv31hx8 \_ redis.1 redis:3.0.6 moreality Shutdown Shutdown about a minute ago
ahzh1kalw2yo redis.2 redis:3.0.7 asdf Running Running about a minute ago
hokzeh28ueaq \_ redis.2 redis:3.0.6 asdf Shutdown Shutdown about a minute ago
8ypuvaxvzorj redis.3 redis:3.0.7 asdf Running Running about a minute ago
g0ddca51aqwy \_ redis.3 redis:3.0.6 moreality Shutdown Shutdown 2 minutes ago

清空(drain)节点

注意drain操作只会影响swarm的负载, 而不会影响到该主机运行的非swarm的容器如使用docker rundocker-compose up创建的容器

使用:

1
docker node update --availability drain <NODE-ID>

即可清空一个节点

NODE-ID信息可以用docker node ls查看

(ps: node-id可以直接使用主机名)

1
docker node update --availability drain asdf

ps: manager节点也是可以drain掉的, 和drain一个worker节点没有区别

然后可以采用docker service ps查看目前任务的运行状况

1
2
3
4
5
6
7
root@asdf:~# docker service ps -f "desired-state=running" redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
nwub9yrzm9q5 redis.1 redis:3.0.7 moreality Running Running 9 minutes ago

tc04mbhfpbgt redis.2 redis:3.0.7 moreality Running Running 3 minutes ago

qjfrb4g4l7jl redis.3 redis:3.0.7 moreality Running Running 3 minutes ago

可以看到, 目前running的节点都是moreality, 说明被drain的asdf节点已经没有任务在运行了

1
2
3
4
5
6
7
8
9
10
11
12
root@asdf:~# docker service ps -f "desired-state=shutdown" redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
ERROR PORTS
ptauimv31hx8 redis.1 redis:3.0.6 moreality Shutdown Shutdown 10 minutes ago

ahzh1kalw2yo redis.2 redis:3.0.7 asdf Shutdown Shutdown 4 minutes ago

hokzeh28ueaq \_ redis.2 redis:3.0.6 asdf Shutdown Shutdown 10 minutes ago

8ypuvaxvzorj redis.3 redis:3.0.7 asdf Shutdown Shutdown 4 minutes ago

g0ddca51aqwy \_ redis.3 redis:3.0.6 moreality Shutdown Shutdown 11 minutes ago

可以采用

1
docker node update --availability active <NODE-ID>

重新激活一个被drain掉的节点

1
docker node update --availability active asdf

注意当一个节点从drain变为active时docker不会为其马上分配任务, 而是等到:

  • 在服务扩展时
  • 在滚动更新时
  • 当另一个节点设置为drain
  • 当任务在另一个active节点上失败时

这个节点会被参与到任务再分配中

端口发布

可以使用

1
2
3
4
docker service create \
--name <SERVICE-NAME> \
--publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<IMAGE>

来绑定一个对外端口和内部端口

如使用

1
2
3
4
5
docker service create \
--name my-web \
--publish published=8080,target=80 \
--replicas 2 \
nginx

所有node的8080端口均被路由到docker内部的80端口, 并参与到swarm内部的负载均衡策略上

可以使用

1
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" my-web

来查看发布端口

升级/降级节点

1
2
docker node promote <node-name> # 升级节点
docker node demote <node-name> # 降级节点

docker stack和docker-compose v3

docker stack和docker compose结合使用可以达到在swarm多节点编排多容器的目的

docker stack practice: https://yeasy.gitbook.io/docker_practice/swarm_mode/stack

docker-compose v3: https://docs.docker.com/compose/compose-file/compose-file-v3/

docker compose v3添加了deploy的相关参数, 可以用于指定swarm集群编排的一些信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
version: "3.9"
services:
redis:
image: redis:alpine
deploy:
replicas: 6
placement:
max_replicas_per_node: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure

部署服务

1
docker stack deploy -c docker-compose.yml <NAME>

查看服务

1
docker stack ls

删除服务

1
docker stack rm <ID>

查看exit的服务日志

1
2
3
4
5
6
# 首先找到对应容器的id
docker ps -a
# 获取对应的日志路径
docker inspect --format='{{.LogPath}}' $INSTANCE_ID
# 直接cat读取就行了
cat <PATH>
1
2
# 或者
cat $(docker inspect --format='{{.LogPath}}' $INSTANCE_ID)

查看服务IP

1
docker inspect --format='{{range .NetworkSettings.Networks}} {{.IPAddress}}{{end}}' e4ebf2177c33

host模式和ingress模式的区别

集群的端口映射有两种模式: hostingress

其中host表示只有服务副本所在的节点可以被外部访问

ingress表示所有节点都可以被外部访问, 节点内部通过负载均衡分配

ingress为默认策略

portainer

1
2
3
4
5
6
7
8
9
docker service create \
--name portainer_agent \
--network rocco \
--mode global \
--constraint 'node.platform.os == linux' \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent

创建网络:

1
docker network create --driver overlay <NAME>

基本信息

Azure

os: ubuntu 16.04

主机名(hostname): asdf

Azure服务器IP: 20.187.212.232

docker版本: Docker version 18.09.7, build 2d0083d

阿里云

os: ubuntu 18.04

主机名(hostname): moreality

阿里服务器IP: 32.121.74.215

docker版本: Docker version 20.10.17, build 100c701


docker-swarm实战
https://moreality.net/posts/51823/
作者
Moreality
发布于
2022年8月24日
许可协议