2023跟我一起学docker-swarm 教程:部署篇「下」
停止Swarm集群上的一个节点
目前我们所有的节点都 ACTIVE
的状态运行的,master
可以将任务分配给任何节点,所以所有的节点都可以接收到任务。
很多时候我们需要维护应用的时候,您需要将节点设置为DRAIN
可用性。DRAIN
状态的节点Maser 阻止此类型的节点接收新任务。这也意味着停止在节点上运行的任务,并在具有ACTIVE
可用性的节点上启动副本任务。
注意: 将节点设置为DRAIN
不会从该节点中删除独立容器,例如使用docker run
、docker-compose up
或Docker Engine API创建的容器。节点的状态,包括DRAIN
,只影响节点调度群服务工作负载的能力。
1 、我们在 master 节点的机器上查看集群中节点的可用性:
root@master:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
57mvxsdn9qg2tq6aiz17et7ot * master Ready Active Leader 24.0.5
lqv1e6oa2hle33ff4xgxfslz3 node1 Ready Active 24.0.5
wwb5rc9nypj1e98wwr5qw99ye node2 Ready Active 24.0.5
查看任务分配的信息:
root@master:~# docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
01wlu8r8z0jx redis.1 redis:6.0.20-alpine node2 Running Running 16 minutes ago
w630bshgl3ga \_ redis.1 redis:6.0-alpine node2 Shutdown Shutdown 16 minutes ago
mkm0o152ns3e redis.2 redis:6.0.20-alpine master Running Running 16 minutes ago
sqmmetgn9mqy \_ redis.2 redis:6.0-alpine master Shutdown Shutdown 16 minutes ago
ezwkml7u8gih redis.3 redis:6.0.20-alpine node1 Running Running 16 minutes ago
qgvbqgmcmu7i \_ redis.3 redis:6.0-alpine node1 Shutdown Shutdown 17 minutes ago
2 、运行docker node update --availability drain <NODE-ID>
以耗尽已分配任务的节点:
docker node update --availability drain node2
我们将 node2 节点停掉,并查看当前服务以及节点信息:
从图中看到node2 的节点状态已经是 Drain
并且分配在 node2 上的服务状态已经是 Shutdown
管理器通过在具有 drain
状态的节点上结束任务,并在Active
状态的节点上创建新的任务来保持所需要的状态。
3 、启用节点的可用性
docker node update --availability active node2
如图所示, 节点 Node2 的状态 已经更新为 Active
。
当节点设置回Active
可用性时,它可以接收新任务:
- 在服务更新期间进行扩展
- 在滚动更新期间
- 将另一个节点设置为
Drain
可用性时 - 当任务在另一个活动节点上失败时
使用swarm模式路由网格
Docker Engine集群模式可以轻松发布服务端口,以使其可用于集群之外的资源。所有节点都参与入口路由网格。路由网格使群中的每个节点能够接受群中运行的任何服务在已发布端口上的连接,即使节点上没有运行的任务。路由网格将所有传入的请求路由到可用节点上的已发布端口到活动容器。
要在集群中使用网络,在启用群模式之前,我们需要在群节点之间打开以下端口:
- Port
7946
TCP/UDP 用于容器网络发现。 - Port
4789
UDP 可为容器入口网络配置。
我们还必须在集群的节点和任何需要访问端口的外部资源(如外部负载平衡器)之间打开已发布的端口。
发布服务端口
创建服务时,使用--publish
标识指定要对外发布端口。target
用于指定容器内的端口,而published
用于指定在路由网格上绑定的端口。如果没有配置published`端口,则每个服务任务都会绑定一个随机的高编号端口。
docker service create --replicas 3 --name redis --publish published=63790,target=6379 --update-delay 5s redis:6.0.20-alpine
root@master:~# docker service create --replicas 3 --name redis --publish published=63790,target=6379 --update-delay 5s re
dis:6.0.20-alpine
vmmg8v0zr26os5johw7187mla
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
root@master:~# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
vmmg8v0zr26o redis replicated 3/3 redis:6.0.20-alpine *:63790->6379/tcp
如图我们已经看到了端口为 *:63790->6379/tcp
<PUBLISHED-PORT>
是swarm
提供服务的端口。如果省略它,将绑定一个随机的高编号端口。<CONTAINER-PORT>
是容器侦听的端口。此参数是必需的。
例如,以下命令将nginx容器中的端口80发布到群中任何节点的端口8080:
docker service create \
--name web \
--publish published=8080,target=80 \
--replicas 2 \
nginx
当访问任何节点上的端口8080时,Docker会将请求路由到活动容器。在群节点本身上,端口8080实际上可能没有绑定,但路由网格知道如何路由流量并防止任何端口冲突的发生。
路由网格在已发布的端口上监听分配给节点的任何IP地址。对于外部可路由的IP地址,该端口可从主机外部获得。对于所有其他IP地址,只能从主机内部访问。
部署完成后我们在宿主机上面访问对应的地址和端口:
如果所示,服务正常访问。并且我们访问部署了的服务节点都可以访问到 nginx 服务。
同样对于已经部署的 service,我们也可以重新给他发布端口:
docker service update \
--publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<SERVICE>
您可以使用docker service inspect
来查看服务的已发布端口。例如:
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" web
[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080}]
输出显示来自容器的
<CONTAINER-PORT>
(标记为TargetPort
)和<PUBLISHED-PORT>
(标记为PublishedPort
),其中节点侦听对服务的请求。
使用上面的命令我们查看部署的 nginx web 服务:
root@master:~# docker service inspect --format="{{json .Endpoint.Spec.Ports}}" web
[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080,"PublishMode":"ingress"}]
仅为TCP或仅UDP发布端口
默认情况下,当您发布端口时,它是一个TCP端口。您可以专门发布UDP端口,而不是或除了TCP端口。当您同时发布TCP和UDP端口时,如果您省略协议说明符,该端口将作为TCP端口发布。如果您使用较长的语法(推荐),请将protocol
密钥设置为tcp
或udp
。
仅限TCP
长语法:
docker service create --name dns-cache \
--publish published=53,target=53 \
dns-cache
简短的语法:
docker service create --name dns-cache \
-p 53:53 \
dns-cache
TCP和UDP
长语法:
docker service create --name dns-cache \
--publish published=53,target=53 \
--publish published=53,target=53,protocol=udp \
dns-cache
简短的语法:
docker service create --name dns-cache \
-p 53:53 \
-p 53:53/udp \
dns-cache
仅限UDP
长语法:
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp \
dns-cache
简短的语法:
docker service create --name dns-cache \
-p 53:53/udp \
dns-cache
绕过路由网格
我们可以绕过路由网格,这样当访问给定节点上的绑定端口时,我们总是访问该节点上运行的服务实例。这被称为host
模式。这种情况下需要注意:
- 如果访问未运行服务任务的节点,则该服务不会监听该端口。有可能什么都没有,或者访问到了一个完全不同的应用程序。
- 如果希望在每个节点上运行多个服务任务(例如,当您有5个节点但运行10个副本时),则无法指定静态目标端口。要么允许Docker分配一个随机的高编号端口(通过关闭
published
端口),要么通过使用全局服务而不是复制服务,或使用放置约束,确保服务仅在给定节点上运行。
要绕过路由,必须使用长--publish
服务并将mode
设置为host
。如果省略mode
或将其设置为ingress
,则使用路由网格。以下命令使用host
模式并绕过路由网格创建全局服务。
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp,mode=host \
--mode global \
dns-cache
配置外部负载均衡器
我们可以为集群服务配置外部负载平衡器,要么与路由网格结合使用,要么根本不使用路由网格。
使用路由网格
我们可以配置外部负载均衡器将请求路由到集群服务。可以配置HAProxy来均衡对发布到端口8080
的nginx
服务的请求。
上图的 来源于网络,仅供参考
在这种情况下,端口8080必须在负载平衡器和集群中的节点之间打开。集群节点可以在代理服务器可以访问的专用网络上,但不能公开访问。
可以配置负载平衡器,以均衡集群中每个节点之间的请求,即使节点上没有安排任务。例如,我们可以在/etc/haproxy/haproxy.cfg
中拥有以下HAProxy配置:
global
log /dev/log local0
log /dev/log local1 notice
...snip...
# Configure HAProxy to listen on port 80
frontend http_front
bind *:80
stats uri /haproxy?stats
default_backend http_back
# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
balance roundrobin
server master 172.16.95.137:8080 check
server node2 172.16.95.138:8080 check
server node3 172.16.95.139:8080 check
当访问端口80上的HAProxy负载均衡器时,它会将请求转发到群中的节点。群路由网格将请求路由到活动任务。集群调度器将任务发送到不同的节点,则无需重新配置负载均衡器。
不使用路由网格
要使用没有路由网格的外部负载均衡器,请将--endpoint-mode
设置为dnsrr
,而不是vip
的默认值。在这种情况下,没有一个虚拟IP。相反,Docker为服务设置DNS条目,使服务名称的DNS查询返回IP地址列表,客户端直接连接到其中一个地址。