On this page

Swarm 集群管理

Swarm 集群模式

本教程向您介绍 Docker Engine Swarm 模式的功能。

本教程将指导您完成:

  • 以 Swarm 模式初始化 Docker 引擎集群
  • 将节点添加到集群中
  • 将应用程序服务部署到 Swarm
  • 一旦一切都运行起来就可以管理集群

本教程使用在终端窗口的命令行中输入的 Docker 引擎 CLI 命令。

设置

要运行本教程,您需要:

  • 三台可通过网络通信的 Linux 主机,安装了 Docker
  • 管理器机器的IP地址
  • 打开主机之间的端口

三台联网主机

本教程需要三台安装了 Docker 并且可以通过网络进行通信的 Linux 主机。这些可以是物理机、虚拟机、Amazon EC2 实例或以其他方式托管。

其中一台机器是管理者(称为manager1),其中两台机器是工人(worker1worker2)。 >笔记 您也可以按照许多教程步骤来测试单节点 swarm,在这种情况下您只需要一台主机。多节点命令不起作用,但您可以初始化集群、创建服务并扩展它们。

在 Linux 机器上安装 Docker 引擎

如果您使用基于 Linux 的物理计算机或云提供的计算机作为主机,您准备好了。您可以在 Linux 计算机上测试单节点和多节点 swarm 场景。

管理器机器的IP地址

IP 地址必须分配给主机操作系统可用的网络接口。群中的所有节点都需要通过 IP 地址连接到管理器。 由于其他节点通过其 IP 地址联系管理节点,因此您应该使用固定 IP 地址。 您可以在 Linux 或 macOS 上运行ifconfig以查看可用网络接口的列表。 本教程使用manager1192.168.99.100.

开放主机之间的协议和端口

以下端口必须可用。在某些系统上,这些端口默认打开。

  • 2377用于与管理器节点以及管理器节点之间进行通信的端口TCP
  • 7946用于覆盖网络节点发现的端口TCP/UDP
  • 用于覆盖网络流量的端口4789UDP(可配置)

如果您计划创建具有加密功能的覆盖网络 ( --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 引擎守护进程已在主机上启动。

  1. 打开终端并通过 ssh 连接到要运行管理器节点的计算机。本教程使用名为 的机器manager1
  2. 运行以下命令创建一个新的集群:
    $ 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

  3. 运行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...
    
  4. 执行docker node ls命令查看节点信息:
    $ docker node ls
    ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
    dxn1zf6l61qsb1josjja83ngz *  manager1  Ready   Active        Leader
    

    *节点 ID 旁边的内容表示您当前已连接到该节点。 Docker Engine Swarm 模式会自动使用机器主机名来命名节点。本教程将在后续步骤中介绍其他列。

将节点添加到集群中

创建带有管理节点的 swarm后 ,您就可以添加工作节点了。

  1. 打开终端并通过 ssh 连接到要运行工作节点的计算机。本教程使用名称worker1.
  2. 运行创建 swarmdocker 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
    
  3. 打开终端并通过 ssh 连接到要运行第二个工作节点的计算机。本教程使用名称worker2.
  4. 运行创建 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.
    
  5. 打开终端并 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。在本教程中,您还 添加了工作节点,但这不是部署服务的要求。

  1. 打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机manager1
  2. 运行以下命令:
    $ 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
  3. 运行docker service ls查看正在运行的服务列表:
    $ docker service ls
    ID            NAME        SCALE  IMAGE   COMMAND
    9uk4639qpg7n  helloworld  1/1    alpine  ping docker.com
    

检查 swarm 上的服务

将服务部署到 swarm 后,您可以使用 Docker CLI 查看有关 swarm 中运行的服务的详细信息。

  1. 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机 manager1
  2. 运行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": {}
        }
    }
    ]
    
  3. 运行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,以便您可以查看任务是否根据服务定义运行。

  4. 在运行任务的节点上运行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 来扩展服务中的容器数量。在服务中运行的容器称为任务。

  1. 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机 manager1
  2. 运行以下命令以更改在 swarm 中运行的服务的所需状态:
    $ docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>
    

    例如:

    $ docker service scale helloworld=5
    helloworld scaled to 5
    
  3. 运行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

  4. 运行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 中删除该服务。

  1. 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机 manager1
  2. 运行docker service rm helloworld以删除该helloworld服务。
    $ docker service rm helloworld
    helloworld
    
  3. 运行docker service inspect <SERVICE-ID>以验证 swarm 管理器是否删除了该服务。CLI 返回未找到服务的消息:
    $ docker service inspect helloworld
    []
    Status: Error: no such service: helloworld, Code: 1
    
  4. 即使服务不再存在,任务容器也需要几秒钟的时间来清理。您可以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 容器映像。

  1. 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机 manager1
  2. 将 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 秒。TsTmTh10m30s 默认情况下,调度程序一次更新 1 个任务。您可以通过该 --update-parallelism标志来配置调度程序同时更新的服务任务的最大数量。 默认情况下,当单个任务的更新返回状态 时 RUNNING,调度程序会调度另一个任务进行更新,直到所有任务都更新为止。如果在更新过程中的任何时间任务返回FAILED,调度程序就会暂停更新。您可以使用或 --update-failure-action标志来控制行为 。docker service createdocker service update

  3. 检查服务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
    
  4. 现在您可以更新redis. 群管理器根据UpdateConfig策略将更新应用到节点:
    $ docker service update --image redis:3.0.7 redis
    redis
    

    默认情况下,调度程序按如下方式应用滚动更新:

    • 停止第一个任务。
    • 计划更新已停止的任务。
    • 启动更新任务的容器。
    • 如果任务更新返回RUNNING,则等待指定的延迟时间,然后开始下一个任务。
    • 如果在更新过程中的任何时间有任务返回FAILED,则暂停更新。
  5. 运行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

  6. 运行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 rundocker compose up或 Docker Engine API 创建的容器。节点的状态(包括Drain)仅影响节点调度 swarm 服务工作负载的能力。

  1. 如果您还没有这样做,请打开终端并通过 ssh 连接到运行管理器节点的计算机。例如,本教程使用名为 的计算机 manager1
  2. 验证您的所有节点是否均处于活动状态。
    $ docker node ls
    ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
    1bcef6utixb0l0ca7gxuivsj0    worker2   Ready   Active
    38ciaotwjuritcdtn9npbnkuz    worker1   Ready   Active
    e216jshn25ckzbvmwlnh5jr3g *  manager1  Ready   Active        Leader
    
  3. 如果您尚未运行滚动更新redis教程中的服务 ,请立即启动它:
    $ docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
    c5uo6kdmzpon37mgj9mwglcfw
    
  4. 运行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
    

    在这种情况下,群管理器将一项任务分配给每个节点。您可能会发现任务在环境中的节点之间分布不同。

  5. 运行docker node update --availability drain <NODE-ID>以耗尽分配有任务的节点:
    $ docker node update --availability drain worker1
    worker1
    
  6. 检查节点以检查其可用性:
    $ docker node inspect --pretty worker1
    ID:			38ciaotwjuritcdtn9npbnkuz
    Hostname:		worker1
    Status:
     State:			Ready
     Availability:		Drain
    ...snip...
    

    耗尽的节点显示DrainAvailability

  7. 运行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

  8. 运行docker node update --availability active <NODE-ID>以使耗尽的节点返回活动状态:
    $ docker node update --availability active worker1
    worker1
    
  9. 检查节点以查看更新的状态:
    $ 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键设置为tcpudp

仅 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服务并设置modehost。如果省略该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-modednsrr而不是默认值vip。在这种情况下,不存在单个虚拟IP。相反,Docker 为服务设置 DNS 条目,以便服务名称的 DNS 查询返回 IP 地址列表,并且客户端直接连接到其中之一。 您不能--endpoint-mode dnsrr与 一起使用--publish mode=ingress。您必须在服务前面运行自己的负载均衡器。对 Docker 主机上的服务名称进行 DNS 查询会返回运行该服务的节点的 IP 地址列表。配置负载均衡器以使用此列表并平衡节点之间的流量。