服务端口

使用虚拟 IP 管理服务端口

可以使用 虚拟地址 (VIP) 简化端口管理工作。VIP 简化了应用间通信,并实施可靠的服务导向型架构。VIP 将流量从单个虚拟地址映射到多个 IP 地址和端口。

定义

containerPort:容器端口指定容器内的端口。只有在使用 BRIDGEUSER 模式构建具有 Docker 容器的网络时,才需要在端口映射中加入该定义。

hostPort:主机端口指定要绑定到的主机上的端口。在使用 BRIDGEUSER 模式构建网络时,您将端口映射从主机端口指定到容器端口。在 HOST 构建网络时,请求的端口默认为主机端口。请注意,只有主机端口可通过环境变量供任务使用。

BRIDGE networking:用于指定 BRIDGE 模式网络的 Docker 应用程序。在这一模式下,容器端口会被映射到主机端口。在这一模式下,应用程序绑定到容器内的指定端口,Docker 网络则被绑定到主机上的指定端口。

USER networking:用于指定 USER 模式网络的 Docker 应用程序。在这一模式下,容器端口会被映射到主机端口。在这一模式下,应用程序绑定到容器内的指定端口,Docker 网络则被绑定到主机上的指定端口。 USER 在与“用户定义”Docker 网络集成时,预计网络模式会很实用。在 Mesos 领域,通常可通过与 Mesos CNI 网络隔离器配合使用的 CNI 插件访问该网络。

HOST networking:用于非 Docker Marathon 应用程序和使用 HOST 模式网络的 Docker 应用程序。在这一模式下,应用程序直接绑定到主机上的一个或多个端口。

portMapping:在 Docker BRIDGE 模式下,能够从容器外访问的所有端口都需要进行端口映射。端口映射是一个包含主机端口、容器端口、服务端口和协议的元组。可为 Marathon 应用指定多端口映射;未指定的 hostPort 默认为 0 (表示 Marathon 会随机分配该值)。在 Docker USER 模式下,hostPort 的语义稍有变化:USER 模式不需要 hostPort,并且如果未指定,Marathon 也不会随机自动分配该值。这样可以将容器部署于 USER 包含 containerPort 和发现信息的网络,但请勿在主机网络上披露这些端口(并且暗示不会占用主机端口资源)。

ports:端口阵列用于定义在 HOST 模式下应被视为包含在资源供应中的端口 。仅在未指定端口映射时才需要端口。一个应用只能定义 ports 和 portDefinitions 两者中的一个。

portDefinitions:portDefinitions 阵列用于定义应被视为资源供应一部分的端口。只有在您正在使用 HOST 网络且未指定端口映射时,才有必要定义这一阵列。此阵列用于替换端口阵列,并且可以指定端口名称、协议和标签。一个应用只能定义 ports 和 portDefinitions 两者中的一个。

protocol:协议指定为端口指定互联网协议(例如,tcpudp 或同时用于两者的 udp,tcp)。只有在使用 BRIDGEUSER 模式构建具有 Docker 容器的网络时,才需要在端口映射中加入该定义。

requirePorts:requirePorts 属性可指定 Marathon 是否应在其收到的资源供应中专门寻找指定端口。这能确保可以将这些端口免费绑定在 Mesos 代理节点上。该属性不适用于 BRIDGEUSER 模式网络。

servicePort:在 Marathon 中(通过 REST API 或前端)创建新应用程序时,可以为它分配一个或多个服务端口。可以指定所有有效的端口数作为服务端口,也可以使用 0 表示 Marathon 应自动分配免费服务端口。如果的确选择了自己的服务端口,就必须确保该端口在所有应用程序中都是唯一的。

随机端口分配

使用 0 值设置任何端口,都会告知 Marathon 您希望获得随机分配的端口。但是,如果 portMapping 中的 containerPort 设置为 0,则将该值设置为与 hostPort 相同的值。

环境变量

每个 host port 值都通过环境变量 $PORT0$PORT1 等披露给正在运行的应用实例。每个 Marathon 应用程序默认获得单个端口,所以 $PORT0 始终可用。在 Marathon 运行的 Docker 容器内也可以使用这些变量。此外,命名为 NAME 的端口也可通过环境变量 $PORT_NAME 进行访问。

使用 BRIDGEUSER 模式网络时,务必将应用程序绑定到 portMapping 中指定的 containerPort。但是,如果已将 containerPort 设置为 0,就与 hostPort 相同,而且可以使用 $PORT 环境变量。

示例配置

主机模式

主机模式网络是 Docker 容器的默认网络模式,也是非 Docker 应用程序的唯一网络模式。请注意,不需要在 Dockerfile 中 EXPOSE (披露)端口。

启用主机模式

容器默认启用主机模式。若要做到明确,也可以通过 network 属性手动指定:

  1. "container": {
  2. "type": "DOCKER",
  3. "docker": {
  4. "image": "my-image:1.0",
  5. "network": "HOST"
  6. }
  7. },

无需为非 Docker 应用程序指定任何内容。

指定端口

可通过 ports 阵列指定可用端口:

  1. "ports": [
  2. 0, 0, 0
  3. ],

或通过 portDefinitions 阵列指定:

  1. "portDefinitions": [
  2. {"port": 0}, {"port": 0}, {"port": 0}
  3. ],

在此示例中,我们指定了三个随机分配的主机端口,制定后即可通过环境变量 $PORT0$PORT1$PORT2 用于我们的命令。除了这三个主机端口外, Marathon 还会随机分配三个服务端口。

还可以指定特定的服务端口:

  1. "ports": [
  2. 2001, 2002, 3000
  3. ],

或:

  1. "portDefinitions": [
  2. {"port": 2001}, {"port": 2002}, {"port": 3000}
  3. ],

此时,主机端口 $PORT0$PORT1$PORT3 继续接受随机分配。然而,此应用程序的三个服务端口现在是 200120023000。与之前的示例一样,必须使用 HAProxy 等服务发现解决方案,从服务端口到主机端口的代理请求。如果您希望应用程序服务端口等同于其主机端口,可以将 requirePorts 设置为 truerequirePorts 默认为 false)。这会告诉 Marathon 仅在有这些端口可用的代理上安排此应用程序:

  1. "ports": [
  2. 2001, 2002, 3000
  3. ],
  4. "requirePorts" : true

服务端口和主机端口(包括环境变量 $PORT0$PORT1$PORT2)现在都是 200120023000。如果不使用服务发现解决方案来从服务端口到主机端口代理请求,则此属性非常有用。

定义 portDefinitions 阵列帮助您为每个端口指定协议、名称和标签。启动新任务时, Marathon 会把这个元数据传递给 Mesos。Mesos 会在任务的 discovery 字段披露这一信息。自定义网络发现解决方案可以占用此字段。

请求动态 tcp 端口的示例,名称为 http,标签 VIP_0 设置为 10.0.0.1:80

  1. "portDefinitions": [
  2. {
  3. "port": 0,
  4. "protocol": "tcp",
  5. "name": "http",
  6. "labels": {"VIP_0": "10.0.0.1:80"}
  7. }
  8. ],

port 字段为必填字段。protocolnamelabels 字段为可选字段。仅设置了port 字段的端口定义相当于 ports 阵列的一个元素。

请注意, 只有 ports 阵列和 portDefinitions 阵列不应同时指定,除非其所有都相等。

引用端口

可以引用 Dockerfile 中的主机端口,用于如下虚拟应用程序:

  1. CMD ./my-app --http-port=$PORT0 --https-port=$PORT1 --monitoring-port=$PORT2

或者,如果在 Marathon 应用定义中不使用 Docker 或已经指定 cmd,则其原理相同:

  1. "cmd": "./my-app --http-port=$PORT0 --https-port=$PORT1 --monitoring-port=$PORT2"

桥接模式

桥接模式网络帮助您将主机端口映射到容器内的端口,并且仅适用于 Docker 容器。如果您使用的容器镜像具有无法修改的固定端口分配,这一模式就会特别有用。请注意,不需要在 Dockerfile 中 EXPOSE (披露)端口。

启用桥接模式

需要通过 network 属性指定桥接模式:

  1. "container": {
  2. "type": "DOCKER",
  3. "docker": {
  4. "image": "my-image:1.0",
  5. "network": "BRIDGE"
  6. }
  7. },

启用用户模式

需要通过 network 属性指定用户模式:

  1. "container": {
  2. "type": "DOCKER",
  3. "docker": {
  4. "image": "my-image:1.0",
  5. "network": "USER"
  6. }
  7. },
  8. "ipAddress": {
  9. "networkName": "someUserNetwork"
  10. }

指定端口

端口映射类似于将 -p 传递到 Docker 命令行,并指定主机上与容器内的端口之间的关系。此时使用portMappings 阵列, 而非在主机模式下使用的 portsportDefinitions 阵列。

portMappings 对象内为 container 容器指定端口映射:

  1. "networks": [
  2. { "mode": "container/bridge" }
  3. ],
  4. "container": {
  5. "type": "DOCKER",
  6. "docker": {
  7. "image": "my-image:1.0",
  8. },
  9. "portMappings": [
  10. { "containerPort": 0, "hostPort": 0 },
  11. { "containerPort": 0, "hostPort": 0 },
  12. { "containerPort": 0, "hostPort": 0 }
  13. ]
  14. }

在本示例中,我们指定了 3 个映射。值为 0 时,会要求 Marathon 为 hostPort 随机分配一个值。此时,将 containerPort 设置为 0 会使其具有与 hostPort 相同的值。这些值可在容器内分别作为 $PORT0$PORT1$PORT2 提供。

另外,如果我们在容器中运行的流程有固定端口,就可能会执行如下操作:

  1. "networks": [
  2. { "mode": "container/bridge" }
  3. ],
  4. "container": {
  5. "type": "DOCKER",
  6. "docker": {
  7. "image": "my-image:1.0"
  8. },
  9. "portMappings": [
  10. { "containerPort": 80, "hostPort": 0 },
  11. { "containerPort": 443, "hostPort": 0 },
  12. { "containerPort": 4000, "hostPort": 0 }
  13. ]
  14. }

此时, Marathon 将随机分配主机端口并将其映射到端口 804434000 。必须注意 $PORT 变量指主机端口。此时, 将为第一次及后续映射设置 $PORT0hostPort

指定协议

也可以为这些端口映射指定协议。默认为 tcp

  1. "networks": [
  2. { "mode": "container/bridge" }
  3. ],
  4. "container": {
  5. "type": "DOCKER",
  6. "docker": {
  7. "image": "my-image:1.0"
  8. },
  9. "portMappings": [
  10. { "containerPort": 80, "hostPort": 0, "protocol": "tcp" },
  11. { "containerPort": 443, "hostPort": 0, "protocol": "tcp" },
  12. { "containerPort": 4000, "hostPort": 0, "protocol": "udp" }
  13. ]
  14. }

指定服务端口

Marathon 将默认为每个端口创建服务端口,并为其分配随机值。服务端口供服务发现解决方案使用,通常建议将这些端口设置为众所周知的值。可以通过为每个映射设置一个 servicePort 来实现:

  1. "networks": [
  2. { "mode": "container/bridge" }
  3. ],
  4. "container": {
  5. "type": "DOCKER",
  6. "docker": {
  7. "image": "my-image:1.0"
  8. },
  9. "portMappings": [
  10. { "containerPort": 80, "hostPort": 0, "protocol": "tcp", "servicePort": 2000 },
  11. { "containerPort": 443, "hostPort": 0, "protocol": "tcp", "servicePort": 2001 },
  12. { "containerPort": 4000, "hostPort": 0, "protocol": "udp", "servicePort": 3000 }
  13. ]
  14. }

在本示例中,主机端口 $PORT0$PORT1$PORT3 继续接受随机分配。但是此应用程序的服务端口现在为 200120023000。HAProxy 等外部代理应配置为从服务端口路由到主机端口。

引用端口

如果将 containerPort 设为 0,就应该在 Dockerfile 中为虚拟应用程序指定如下端口:

  1. CMD ./my-app --http-port=$PORT0 --https-port=$PORT1 --monitoring-port=$PORT2

但是,如果已指定 containerPort 值,则只需在 Dockerfile 中使用相同的值:

  1. CMD ./my-app --http-port=80 --https-port=443 --monitoring-port=4000

或者,可以在 Marathon 应用定义中指定 cmd,其原理和之前相同:

  1. "cmd": "./my-app --http-port=$PORT0 --https-port=$PORT1 --monitoring-port=$PORT2"

或者,如果使用了固定值:

  1. "cmd": "./my-app --http-port=80 --https-port=443 --monitoring-port=4000"