Swarm 集群管理
Swarm 集群模式
本教程向您介绍 Docker Engine Swarm 模式的功能。
本教程将指导您完成:
- 以 Swarm 模式初始化 Docker 引擎集群
- 将节点添加到集群中
- 将应用程序服务部署到 Swarm
- 一旦一切都运行起来就可以管理集群
本教程使用在终端窗口的命令行中输入的 Docker 引擎 CLI 命令。
设置
要运行本教程,您需要:
- 三台可通过网络通信的 Linux 主机,安装了 Docker
- 管理器机器的IP地址
- 打开主机之间的端口
三台联网主机
本教程需要三台安装了 Docker 并且可以通过网络进行通信的 Linux 主机。这些可以是物理机、虚拟机、Amazon EC2 实例或以其他方式托管。
其中一台机器是管理者(称为manager1
),其中两台机器是工人(worker1
和worker2
)。
>笔记
您也可以按照许多教程步骤来测试单节点 swarm,在这种情况下您只需要一台主机。多节点命令不起作用,但您可以初始化集群、创建服务并扩展它们。
在 Linux 机器上安装 Docker 引擎
如果您使用基于 Linux 的物理计算机或云提供的计算机作为主机,您准备好了。您可以在 Linux 计算机上测试单节点和多节点 swarm 场景。
管理器机器的IP地址
IP 地址必须分配给主机操作系统可用的网络接口。群中的所有节点都需要通过 IP 地址连接到管理器。
由于其他节点通过其 IP 地址联系管理节点,因此您应该使用固定 IP 地址。
您可以在 Linux 或 macOS 上运行ifconfig
以查看可用网络接口的列表。
本教程使用manager1
:192.168.99.100
.
开放主机之间的协议和端口
以下端口必须可用。在某些系统上,这些端口默认打开。
2377
用于与管理器节点以及管理器节点之间进行通信的端口TCP7946
用于覆盖网络节点发现的端口TCP/UDP- 用于覆盖网络流量的端口
4789
UDP(可配置)
如果您计划创建具有加密功能的覆盖网络 ( --opt encrypted
),则还需要确保允许 IP 协议 50 (IPSec ESP) 流量。
端口4789
是 Swarm 数据路径端口的默认值,也称为 VXLAN 端口。防止任何不受信任的流量到达此端口非常重要,因为 VXLAN 不提供身份验证。此端口只能向受信任的网络开放,而不能在外围防火墙处开放。
如果 Swarm 流量所经过的网络不完全可信,强烈建议使用加密的覆盖网络。如果加密的覆盖网络是专用的,建议进行一些额外的强化:
- 自定义默认入口网络以使用加密
- 仅接受数据路径端口上的加密数据包:
# Example iptables rule (order and other tools may require customization)
iptables -I INPUT -m udp --dport 4789 -m policy --dir in --pol none -j DROP
创建一个群
完成设置步骤后,您就可以创建集群了。确保 Docker 引擎守护进程已在主机上启动。
- 打开终端并通过 ssh 连接到要运行管理器节点的计算机。本教程使用名为 的机器
manager1
。 - 运行以下命令创建一个新的集群:
$ docker swarm init --advertise-addr <MANAGER-IP>
在本教程中,以下命令在
manager1
计算机上创建一个 swarm:$ docker swarm init --advertise-addr 192.168.99.100 Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager. To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \ 192.168.99.100:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
该
--advertise-addr
标志将管理器节点配置为将其地址发布为192.168.99.100
。群中的其他节点必须能够通过该 IP 地址访问管理器。 输出包括将新节点加入群的命令。节点将根据标志的值作为管理者或工作人员加入--token
。 - 运行
docker info
查看swarm当前状态:$ docker info Containers: 2 Running: 0 Paused: 0 Stopped: 2 ...snip... Swarm: active NodeID: dxn1zf6l61qsb1josjja83ngz Is Manager: true Managers: 1 Nodes: 1 ...snip...
- 执行
docker node ls
命令查看节点信息:$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS dxn1zf6l61qsb1josjja83ngz * manager1 Ready Active Leader
*
节点 ID 旁边的内容表示您当前已连接到该节点。 Docker Engine Swarm 模式会自动使用机器主机名来命名节点。本教程将在后续步骤中介绍其他列。
将节点添加到集群中
创建带有管理节点的 swarm后 ,您就可以添加工作节点了。
- 打开终端并通过 ssh 连接到要运行工作节点的计算机。本教程使用名称
worker1
. - 运行创建 swarm
docker swarm init
教程步骤的输出生成 的命令,以创建加入到现有 swarm 的工作节点:$ docker swarm join \ --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \ 192.168.99.100:2377 This node joined a swarm as a worker.
如果您没有可用的命令,您可以在管理节点上运行以下命令来检索工作线程的加入命令:
$ docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join \ --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \ 192.168.99.100:2377
- 打开终端并通过 ssh 连接到要运行第二个工作节点的计算机。本教程使用名称
worker2
. - 运行创建 swarm
docker swarm init
教程步骤的输出生成 的命令,以创建加入现有 swarm 的第二个工作节点:$ docker swarm join \ --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \ 192.168.99.100:2377 This node joined a swarm as a worker.
打开终端并 ssh 进入管理节点运行的计算机,然后运行命令
docker node ls
以查看工作节点:$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 03g1y59jwfg7cf99w4lt0f662 worker2 Ready Active 9j68exjopxe7wfl6yuxml7a7j worker1 Ready Active dxn1zf6l61qsb1josjja83ngz * manager1 Ready Active Leader
该
MANAGER
列标识群中的管理器节点。此列中的空状态将它们worker1
标识worker2
为工作节点。 Swarm 管理命令docker node ls
仅适用于管理节点。
向 swarm 部署服务
创建 swarm后 ,您可以将服务部署到 swarm。在本教程中,您还 添加了工作节点,但这不是部署服务的要求。
- 打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机
manager1
。 - 运行以下命令:
$ docker service create --replicas 1 --name helloworld alpine ping docker.com 9uk4639qpg7npwf3fn2aasksr
- 该
docker service create
命令创建服务。 - 该
--name
标志为服务命名helloworld
。 - 该
--replicas
标志指定 1 个正在运行的实例的所需状态。 - 这些参数
alpine ping docker.com
将服务定义为执行命令的 Alpine Linux 容器ping docker.com
。
- 该
- 运行
docker service ls
查看正在运行的服务列表:$ docker service ls ID NAME SCALE IMAGE COMMAND 9uk4639qpg7n helloworld 1/1 alpine ping docker.com
检查 swarm 上的服务
将服务部署到 swarm 后,您可以使用 Docker CLI 查看有关 swarm 中运行的服务的详细信息。
- 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机
manager1
。 - 运行
docker service inspect --pretty <SERVICE-ID>
以易于阅读的格式显示有关服务的详细信息。 要查看该服务的详细信息helloworld
:[manager1]$ docker service inspect --pretty helloworld ID: 9uk4639qpg7npwf3fn2aasksr Name: helloworld Service Mode: REPLICATED Replicas: 1 Placement: UpdateConfig: Parallelism: 1 ContainerSpec: Image: alpine Args: ping docker.com Resources: Endpoint Mode: vip
>提示 要以 json 格式返回服务详细信息,请运行不带该
--pretty
标志的相同命令。[manager1]$ docker service inspect helloworld [ { "ID": "9uk4639qpg7npwf3fn2aasksr", "Version": { "Index": 418 }, "CreatedAt": "2016-06-16T21:57:11.622222327Z", "UpdatedAt": "2016-06-16T21:57:11.622222327Z", "Spec": { "Name": "helloworld", "TaskTemplate": { "ContainerSpec": { "Image": "alpine", "Args": [ "ping", "docker.com" ] }, "Resources": { "Limits": {}, "Reservations": {} }, "RestartPolicy": { "Condition": "any", "MaxAttempts": 0 }, "Placement": {} }, "Mode": { "Replicated": { "Replicas": 1 } }, "UpdateConfig": { "Parallelism": 1 }, "EndpointSpec": { "Mode": "vip" } }, "Endpoint": { "Spec": {} } } ]
- 运行
docker service ps <SERVICE-ID>
查看哪些节点正在运行该服务:[manager1]$ docker service ps helloworld NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS helloworld.1.8p1vev3fq5zm0mi8g0as41w35 alpine worker2 Running Running 3 minutes
在这种情况下,该
helloworld
服务的一个实例正在该worker2
节点上运行。您可能会看到该服务在您的管理器节点上运行。默认情况下,群中的管理节点可以像工作节点一样执行任务。 Swarm 还向您显示服务任务的DESIRED STATE
情况CURRENT STATE
,以便您可以查看任务是否根据服务定义运行。 - 在运行任务的节点上运行
docker ps
以查看有关任务容器的详细信息。 >提示 如果helloworld
在管理器节点以外的节点上运行,则必须通过 ssh 连接到该节点。[worker2]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e609dde94e47 alpine:latest "ping docker.com" 3 minutes ago Up 3 minutes helloworld.1.8p1vev3fq5zm0mi8g0as41w35
扩展集群中的服务
将服务部署到集群后,您就可以使用 Docker CLI 来扩展服务中的容器数量。在服务中运行的容器称为任务。
- 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机
manager1
。 - 运行以下命令以更改在 swarm 中运行的服务的所需状态:
$ docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>
例如:
$ docker service scale helloworld=5 helloworld scaled to 5
- 运行
docker service ps <SERVICE-ID>
查看更新后的任务列表:$ docker service ps helloworld NAME IMAGE NODE DESIRED STATE CURRENT STATE helloworld.1.8p1vev3fq5zm0mi8g0as41w35 alpine worker2 Running Running 7 minutes helloworld.2.c7a7tcdq5s0uk3qr88mf8xco6 alpine worker1 Running Running 24 seconds helloworld.3.6crl09vdcalvtfehfh69ogfb1 alpine worker1 Running Running 24 seconds helloworld.4.auky6trawmdlcne8ad8phb0f1 alpine manager1 Running Running 24 seconds helloworld.5.ba19kca06l18zujfwxyc5lkyn alpine worker2 Running Running 24 seconds
您可以看到 swarm 创建了 4 个新任务,以扩展到总共 5 个运行的 Alpine Linux 实例。任务分布在集群的三个节点之间。其中一个正在运行
manager1
。 - 运行
docker ps
以查看在您连接的节点上运行的容器。以下示例显示了在 上运行的任务manager1
:$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 528d68040f95 alpine:latest "ping docker.com" About a minute ago Up About a minute helloworld.4.auky6trawmdlcne8ad8phb0f1
如果您想查看其他节点上运行的容器,请通过 ssh 进入这些节点并运行命令
docker ps
。
删除 swarm 上运行的服务
本教程中的其余步骤不使用该helloworld
服务,因此现在您可以从 swarm 中删除该服务。
- 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机
manager1
。 - 运行
docker service rm helloworld
以删除该helloworld
服务。$ docker service rm helloworld helloworld
- 运行
docker service inspect <SERVICE-ID>
以验证 swarm 管理器是否删除了该服务。CLI 返回未找到服务的消息:$ docker service inspect helloworld [] Status: Error: no such service: helloworld, Code: 1
- 即使服务不再存在,任务容器也需要几秒钟的时间来清理。您可以
docker ps
在节点上使用来验证任务何时被删除。$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES db1651f50347 alpine:latest "ping docker.com" 44 minutes ago Up 46 seconds helloworld.5.9lkmos2beppihw95vdwxy1j3w 43bf6e532a92 alpine:latest "ping docker.com" 44 minutes ago Up 46 seconds helloworld.3.a71i8rp6fua79ad43ycocl4t2 5a0fb65d8fa7 alpine:latest "ping docker.com" 44 minutes ago Up 45 seconds helloworld.2.2jpgensh7d935qdc857pxulfr afb0ba67076f alpine:latest "ping docker.com" 44 minutes ago Up 46 seconds helloworld.4.1c47o7tluz7drve4vkm2m5olx 688172d3bfaa alpine:latest "ping docker.com" 45 minutes ago Up About a minute helloworld.1.74nbhb3fhud8jfrhigd7s29we $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
将滚动更新应用于服务
在本教程的上一步中,您扩展了服务的实例数量。在本教程的这一部分中,您将部署基于 Redis 3.0.6 容器标签的服务。然后,通过滚动更新将服务升级为使用 Redis 3.0.7 容器映像。
- 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机
manager1
。 - 将 Redis 标签部署到 swarm 并为 swarm 配置 10 秒更新延迟。请注意,以下示例显示了较旧的 Redis 标记:
$ docker service create \ --replicas 3 \ --name redis \ --update-delay 10s \ redis:3.0.6 0u6a4s31ybk7yw2wyvtikmu50
您可以在服务部署时配置滚动更新策略。 该
--update-delay
标志配置服务任务或任务集更新之间的时间延迟。您可以将时间描述为秒数、分钟数或小时T
数的组合。因此 表示延迟 10 分 30 秒。Ts
Tm
Th
10m30s
默认情况下,调度程序一次更新 1 个任务。您可以通过该--update-parallelism
标志来配置调度程序同时更新的服务任务的最大数量。 默认情况下,当单个任务的更新返回状态 时RUNNING
,调度程序会调度另一个任务进行更新,直到所有任务都更新为止。如果在更新过程中的任何时间任务返回FAILED
,调度程序就会暂停更新。您可以使用或--update-failure-action
标志来控制行为 。docker service create
docker service update
- 检查服务
redis
:$ docker service inspect --pretty redis ID: 0u6a4s31ybk7yw2wyvtikmu50 Name: redis Service Mode: Replicated Replicas: 3 Placement: Strategy: Spread UpdateConfig: Parallelism: 1 Delay: 10s ContainerSpec: Image: redis:3.0.6 Resources: Endpoint Mode: vip
- 现在您可以更新
redis
. 群管理器根据UpdateConfig
策略将更新应用到节点:$ docker service update --image redis:3.0.7 redis redis
默认情况下,调度程序按如下方式应用滚动更新:
- 停止第一个任务。
- 计划更新已停止的任务。
- 启动更新任务的容器。
- 如果任务更新返回
RUNNING
,则等待指定的延迟时间,然后开始下一个任务。 - 如果在更新过程中的任何时间有任务返回
FAILED
,则暂停更新。
- 运行
docker service inspect --pretty redis
以查看处于所需状态的新图像:$ docker service inspect --pretty redis ID: 0u6a4s31ybk7yw2wyvtikmu50 Name: redis Service Mode: Replicated Replicas: 3 Placement: Strategy: Spread UpdateConfig: Parallelism: 1 Delay: 10s ContainerSpec: Image: redis:3.0.7 Resources: Endpoint Mode: vip
的输出
service inspect
显示您的更新是否因失败而暂停:$ docker service inspect --pretty redis ID: 0u6a4s31ybk7yw2wyvtikmu50 Name: redis ...snip... Update status: State: paused Started: 11 seconds ago Message: update paused due to failure or early termination of task 9p7ith557h8ndf0ui9s0q951b ...snip...
要重新启动暂停的更新运行
docker service update <SERVICE-ID>
。例如:$ docker service update redis
为了避免重复某些更新失败,您可能需要通过将标志传递给 来重新配置服务
docker service update
。 - 运行
docker service ps <SERVICE-ID>
查看滚动更新:$ docker service ps redis NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR redis.1.dos1zffgeofhagnve8w864fco redis:3.0.7 worker1 Running Running 37 seconds \_ redis.1.88rdo6pa52ki8oqx6dogf04fh redis:3.0.6 worker2 Shutdown Shutdown 56 seconds ago redis.2.9l3i4j85517skba5o7tn5m8g0 redis:3.0.7 worker2 Running Running About a minute \_ redis.2.66k185wilg8ele7ntu8f6nj6i redis:3.0.6 worker1 Shutdown Shutdown 2 minutes ago redis.3.egiuiqpzrdbxks3wxgn8qib1g redis:3.0.7 worker1 Running Running 48 seconds \_ redis.3.ctzktfddb2tepkr45qcmqln04 redis:3.0.6 mmanager1 Shutdown Shutdown 2 minutes ago
在 Swarm 更新所有任务之前,您可以看到有些任务正在运行,
redis:3.0.6
而另一些任务正在运行redis:3.0.7
。上面的输出显示了滚动更新完成后的状态。
Drain swarm 上的节点
在本教程的前面步骤中,所有节点都已Active
可用性地运行。Swarm管理器可以将任务分配给任何Active
节点,因此到目前为止所有节点都可以接收任务。
有时,例如计划的维护时间,您需要将节点设置为Drain
可用性。Drain
可用性阻止节点从 Swarm 管理器接收新任务。这也意味着管理器停止在节点上运行的任务,并在Active
可用的节点上启动副本任务。
>重要的:
将节点设置为Drain
不会从该节点删除独立容器,例如使用docker run
、docker compose up
或 Docker Engine API 创建的容器。节点的状态(包括Drain
)仅影响节点调度 swarm 服务工作负载的能力。
- 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机
manager1
。 - 验证您的所有节点是否均处于活动状态。
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 1bcef6utixb0l0ca7gxuivsj0 worker2 Ready Active 38ciaotwjuritcdtn9npbnkuz worker1 Ready Active e216jshn25ckzbvmwlnh5jr3g * manager1 Ready Active Leader
- 如果您尚未运行滚动更新
redis
教程中的服务 ,请立即启动它:$ docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6 c5uo6kdmzpon37mgj9mwglcfw
- 运行
docker service ps redis
看看 swarm manager 如何将任务分配给不同的节点:$ docker service ps redis NAME IMAGE NODE DESIRED STATE CURRENT STATE redis.1.7q92v0nr1hcgts2amcjyqg3pq redis:3.0.6 manager1 Running Running 26 seconds redis.2.7h2l8h3q3wqy5f66hlv9ddmi6 redis:3.0.6 worker1 Running Running 26 seconds redis.3.9bg7cezvedmkgg6c8yzvbhwsd redis:3.0.6 worker2 Running Running 26 seconds
在这种情况下,群管理器将一项任务分配给每个节点。您可能会发现任务在环境中的节点之间分布不同。
- 运行
docker node update --availability drain <NODE-ID>
以耗尽分配有任务的节点:$ docker node update --availability drain worker1 worker1
- 检查节点以检查其可用性:
$ docker node inspect --pretty worker1 ID: 38ciaotwjuritcdtn9npbnkuz Hostname: worker1 Status: State: Ready Availability: Drain ...snip...
耗尽的节点显示
Drain
为Availability
。 - 运行
docker service ps redis
以查看 swarm 管理器如何更新服务的任务分配redis
:$ docker service ps redis NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR redis.1.7q92v0nr1hcgts2amcjyqg3pq redis:3.0.6 manager1 Running Running 4 minutes redis.2.b4hovzed7id8irg1to42egue8 redis:3.0.6 worker2 Running Running About a minute \_ redis.2.7h2l8h3q3wqy5f66hlv9ddmi6 redis:3.0.6 worker1 Shutdown Shutdown 2 minutes ago redis.3.9bg7cezvedmkgg6c8yzvbhwsd redis:3.0.6 worker2 Running Running 4 minutes
群管理器通过结束具有可用性的节点上的任务
Drain
并在具有可用性的节点上创建新任务来维持所需的状态Active
。 - 运行
docker node update --availability active <NODE-ID>
以使耗尽的节点返回活动状态:$ docker node update --availability active worker1 worker1
- 检查节点以查看更新的状态:
$ docker node inspect --pretty worker1 ID: 38ciaotwjuritcdtn9npbnkuz Hostname: worker1 Status: State: Ready Availability: Active ...snip...
当您将节点设置回
Active
可用性时,它可以接收新任务:- 在服务更新期间进行扩展
- 在滚动更新期间
- 当您将另一个节点设置为
Drain
可用时 - 当任务在另一个活动节点上失败时
使用 Swarm 模式路由
Docker Engine Swarm 模式可以轻松发布服务端口,使它们可供 Swarm 外部的资源使用。所有节点都参与入口路由网格。路由网格使集群中的每个节点都可以接受集群中运行的任何服务的已发布端口上的连接,即使该节点上没有运行任何任务。路由网格将所有传入请求路由到可用节点上已发布端口的活动容器。 要在 Swarm 中使用入口网络,您需要在启用 Swarm 模式之前在 Swarm 节点之间打开以下端口:
7946
用于容器网络发现的 TCP/UDP端口。4789
容器入口网络的端口UDP(可配置)。
在 Swarm 中建立网络时,应特别小心。 您还必须打开 swarm 节点与需要访问该端口的任何外部资源(例如外部负载均衡器)之间的已发布端口。
为服务发布端口
创建服务时使用该--publish
标志来发布端口。target
用于指定容器内部的端口,published
用于指定在路由网格上绑定的端口。如果您保留published
端口,则会为每个服务任务绑定一个随机的高编号端口。您需要检查任务以确定端口。
$ docker service create \
--name <SERVICE-NAME> \
--publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
IMAGE
>笔记
此语法的旧形式是用冒号分隔的字符串,其中发布的端口是第一个,目标端口是第二个,例如 -p 8080:80
。新语法是首选,因为它更易于阅读并且具有更大的灵活性。
这<PUBLISHED-PORT>
是 Swarm 提供服务的端口。如果省略它,则会绑定随机的高编号端口。这<CONTAINER-PORT>
是容器侦听的端口。此参数是必需的。
例如,以下命令将 nginx 容器中的端口 80 发布到 swarm 中任何节点的端口 8080:
$ docker service create \
--name my-web \
--publish published=8080,target=80 \
--replicas 2 \
nginx
当您访问任何节点上的 8080 端口时,Docker 会将您的请求路由到活动容器。在 swarm 节点本身上,端口 8080 实际上可能并未绑定,但路由网格知道如何路由流量并防止发生任何端口冲突。 路由网格在已发布的端口上侦听分配给该节点的任何 IP 地址。对于外部可路由 IP 地址,该端口可从主机外部使用。对于所有其他 IP 地址,只能从主机内部进行访问。
您可以使用以下命令为现有服务发布端口:
$ docker service update \
--publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
SERVICE
您可以用来docker service inspect
查看服务的已发布端口。例如:
$ docker service inspect --format="{{json .Endpoint.Spec.Ports}}" my-web
[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080}]
输出显示容器中的 <CONTAINER-PORT>
(标记为)和节点侦听服务请求的(标记为)。TargetPort
<PUBLISHED-PORT>
PublishedPort
仅发布 TCP 或 UDP 端口
默认情况下,当您发布端口时,它是 TCP 端口。您可以专门发布 UDP 端口来代替 TCP 端口或除了 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
绕过网格路由
默认情况下,发布端口的 Swarm 服务使用路由网格来发布端口。当您连接到任何 swarm 节点上的已发布端口(无论它是否正在运行给定服务)时,您都会被透明地重定向到正在运行该服务的工作线程。实际上,Docker 充当集群服务的负载均衡器。
您可以绕过路由网格,以便当您访问给定节点上的绑定端口时,您始终访问在该节点上运行的服务的实例。这称为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
配置外部负载均衡器
您可以与路由网格结合使用或根本不使用路由网格,为群服务配置外部负载均衡器。
使用路由网格
您可以配置外部负载均衡器以将请求路由到 swarm 服务。例如,您可以配置 HAProxy以平衡对发布到端口 8080 的 nginx 服务的请求。
在这种情况下,负载均衡器和 swarm 中的节点之间的端口 8080 必须打开。群节点可以驻留在代理服务器可访问的专用网络上,但不可公开访问。
您可以配置负载均衡器来平衡 swarm 中每个节点之间的请求,即使该节点上没有计划任务也是如此。例如,您可以在 中具有以下 HAProxy 配置/etc/haproxy/haproxy.cfg
:
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 node1 192.168.99.100:8080 check
server node2 192.168.99.101:8080 check
server node3 192.168.99.102:8080 check
当您在端口 80 上访问 HAProxy 负载均衡器时,它会将请求转发到 swarm 中的节点。群路由网格将请求路由到活动任务。如果出于任何原因 swarm 调度程序将任务分派到不同的节点,您无需重新配置负载均衡器。 您可以配置任何类型的负载均衡器以将请求路由到 Swarm 节点。
没有路由网格
要在没有路由网格的情况下使用外部负载均衡器,请设置--endpoint-mode
为dnsrr
而不是默认值vip
。在这种情况下,不存在单个虚拟IP。相反,Docker 为服务设置 DNS 条目,以便服务名称的 DNS 查询返回 IP 地址列表,并且客户端直接连接到其中之一。
您不能--endpoint-mode dnsrr
与 一起使用--publish mode=ingress
。您必须在服务前面运行自己的负载均衡器。对 Docker 主机上的服务名称进行 DNS 查询会返回运行该服务的节点的 IP 地址列表。配置负载均衡器以使用此列表并平衡节点之间的流量。