docker swarm network

Docker Engine集群模式可以轻松发布服务端口,以使其可用于集群之外的资源。

所有节点都参与入口路由网格。路由网格使群中的每个节点能够接受群中运行的任何服务在已发布端口上的连接,即使节点上没有运行的任务。

路由网格将所有传入的请求路由到可用节点上的已发布端口到活动容器。

要在集群中使用网格,在启用群模式之前,我们需要在群节点之间打开以下端口:

Port 7946 TCP/UDP for container network discovery.容器网络自动发现
Port 4789 UDP (configurable) for the container ingress network.容器ingress网络

在swarm中建立网络时,应特别小心。

我们还必须在集群的节点和任何需要访问端口的外部资源(如外部负载平衡器)之间打开已发布的端口。

网络结构

建立外部8080到容器内部80的端口映射,访问任一Node节点的8080端口,再由VIP LB(虚拟IP的负载均衡)自动路由到Nginx的容器中处理。

可以再通过External LB对8080端口进行外部负载均衡(如:LVS、API Gateway、Haproxy)。

swarm ingress

基于容器内部网络互通和容器DNS,将tomcat服解析到对应的内部VIP进行负载均衡访问。link方式只在swarm内部可访问。

swarm ingress + link

连接到同一网络的容器,都可以通过容器名互通,然后通过VIP LB方式进行负载均衡,不需要开启端口publish(仅限内部容器之间通信)。

#创建自定义网络
docker network create --driver=overlay --attachable mynet
#创建服务
docker service create -p 80:80 --network=mynet --name nginx nginx

swarm network

示例redis

docker service create \
--replicas 3 \
--name myredis \
--publish published=63790,target=6379 \
--update-delay 5s \
redis:6.0.20-alpine

# --publish published=63790,target=6379
# published=63790,<PUBLISHED-PORT>,swarm绑定的外部服务端口,如果不指定,则每个任务都会绑定个随机的高编号端口
# target=6379,<CONTAINER-PORT>容器内的服务侦听端口
image redis:6.0.20-alpine could not be accessed on a registry to record its digest. 
Each node will access redis:6.0.20-alpine independently,
possibly leading to different nodes running different versions of the image.
创建service时未指定registry地址(这样主节点也可以创建成功,这因为主节点本地存在该镜像),
但是会导致子节点获取的镜像时也使用本地缓存,也就有可能导致使用的镜像不一致,或者获取不到image。
指定registry地址可避免该问题。

qf0dl5oyujzgqexk8j673slgr
overall progress: 3 out of 3 tasks
1/3: running   [==================================================>]
2/3: running   [==================================================>]
3/3: running   [==================================================>]
verify: Service converged

# service ls中可以看到PORTS信息:*:63790->6379/tcp:
docker service ls
ID             NAME      MODE         REPLICAS   IMAGE                 PORTS
qf0dl5oyujzg   myredis   replicated   3/3        redis:6.0.20-alpine   *:63790->6379/tcp

# 节点netstat中也可以看到63790端口绑定到了dockerd服务上:
netstat -lntup|grep -E 'PID|6379'
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp6       0      0 :::63790                :::*                    LISTEN      746/dockerd

# telnet任一节点上的对应端口,可正常连接、交互:
telnet 192.168.31.42 63790
Trying 192.168.31.42...
Connected to 192.168.31.42.
Escape character is '^]'.
GET /
$-1
quit
+OK
Connection closed by foreign host.

示例nginx

将nginx容器中的端口80发布到群中任何节点的端口8080。当访问任何节点的8080端口时,docker会将请求路由到活动的容器。

docker service create \
  --name mynginx \
  --publish published=8080,target=80 \
  --replicas 2 \
  nginx

部署后,我们用 http://192.168.31.42:8080/ 可以访问到nginx服务。

修改发布端口

同样对于已经部署的 service,我们也可以重新给他发布端口。

您可以使用docker service inspect来查看服务的已发布端口。

# update发部端口设置:
docker service update \
  --publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <SERVICE>

# 查看已发布的端口信息:
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" mynginx

[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080}]

指定TCP/UDP协议

发布端口时不指定协议,默认为TCP端口。

# 未指定,默认为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

host模式

省略mode参数、或mode=ingress都会使用路由网格。

如果我们希望访问给定节点上的绑定端口时,总是访问该节点上运行的服务实例,则需要使用长--publish方式,设置mode=host模式来绕过路由。

这种情况下需要注意:

docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp,mode=host \
  --mode global \
  dns-cache

外部负载均衡

可以为集群服务配置外部负载平衡器,要么与路由网格结合使用,要么根本不使用路由网格。

配置外部负载均衡器将请求路由到集群服务。例如,可以配置HAProxy来均衡对发布到端口8080的nginx服务的请求。

带有外部负载均衡器图像的入口

自定义网络

默认的网络Ingress中,容器之间、同一服务的不同实例之间网络无法互通?

自定义的overlay网络中,swarm为每个service都创建一个dnsadress,网络可以互通。

docker网络--多机通信--4--ingress笔记:https://blog.csdn.net/weixin_43501172/article/details/123819075

# 创建网络
docker network create -d overlay mytest-overlay
docker network ls

# 创建指定网络的service
docker service create --network mytest-overlay --name testnginx -p 8081:80 nginx
docker service create --network mytest-overlay --name testalpine alpine ping www.baidu.com
# 创建默认网络的service
docker service create --name testalpine2 alpine ping www.baidu.com
docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
5e24d2f32213   bridge            bridge    local
c7c7164df6a6   docker_gwbridge   bridge    local
edc2b127d60d   host              host      local
0xmdmgmcwdr4   ingress           overlay   swarm #默认的网络
u1txwklso3lu   mytest-overlay    overlay   swarm #新建的网络
cc14e216cbdb   none              null      local

docker service ls
ID             NAME          MODE         REPLICAS   IMAGE                 PORTS
a8fcefi6ybi5   mynginx       replicated   2/2        nginx:latest          *:8080->80/tcp
qf0dl5oyujzg   myredis       replicated   3/3        redis:6.0.20-alpine   *:63790->6379/tcp

lzal5dqms1xh   testalpine2   replicated   1/1        alpine:latest

wdanrvsl9y9b   testalpine    replicated   1/1        alpine:latest
qtdlb7658k2d   testnginx     replicated   1/1        nginx:latest          *:8081->80/tcp

docker service ps testalpine testalpine2
ID             NAME            IMAGE           NODE            DESIRED STATE   CURRENT STATE            ERROR     PORTS
j5iruwdqn6s1   testalpine2.1   alpine:latest   swarm-node1     Running         Running 2 minutes ago
qgv09gh8cvy5   testalpine.1    alpine:latest   swarm-manager   Running         Running 23 minutes ago

# 查看网络接入信息
docker network inspect mytest-overlay

查看testalpine、testalpine2服务所在节点,在对应节点上进入容器主机:

dnsrr模式

endpoint-mode有两种模式:VIP、dnsrr。

默认为VIP模式,通过端口映射方式被外部访问。

dnsrr方式与端口发布冲突,不能发布端口、服务无法直接通过端口被外部访问,只能通过名称访问。如果不加入overlay网络它就是独立的。

若需要被访问,可以对这个service增加overlay网络。

docker service create --name nginx-b --endpoint-mode dnsrr -p  8090:80 nginx

docker service updata --network-add mytest-overlay nginx-b