Ports
marathon中应用的端口配置可能被混淆,并有一个悬而未决的问题,需要重新设计 ports API。这个页面试图更清楚地解释它们是如何工作的。
定义
containerPort:在容器内部,是一个容器端口。在使用docker容器的时候,当我们使用BRIDGE网络模式,这是端口映射的一部分,必须设置。
hostPort:主机上的端口。当使用BRIDGE网络模式的时候,你需要指定从主机端口到容器的端口的映射。在HOST网络模式中,默认请求端口是主机端口。
BRIDGE networking:BRIDGE模式的网络使用在docker应用中。在这模式中,容器端口(容器内部的端口)会被映射到主机的端口上,应用在容器内部绑定一个指定端口,docker网络在主机上绑定一个指定端口。
HOST networking:HOST网络使用在非docker的marathon应用和docker应用上。在这种模式下,应用直接绑定一个或多个端口在主机上。
portMapping:对docker应用来说端口映射是必须的,docker应用需要使用BRIDGE网络模式,它包含一组host port、container port、service port和protocol。多个端口映射可能会被一个marathon应用指定。
ports:ports数组用来定义端口。它必须定义成数组,如果你使用的是HOST网络模式,并且没有指定端口映射。ports和portDefinitions可以同时定义。
portDefinitions:portDefinition数组用来定义端口。它必须定义成数组,如果你使用的是HOST网络模式,并且没有指定端口映射。portDefinition这个数组可以替代ports数组,它可以指定端口名称、协议和标签。ports和portDefinitions可以同时定义。
protocol:指定端口的协议(如tcp、udp、或者是tcp和udp)。在docker容器中使用BRIDGE网络模式时,端口映射是必须的。
requirePorts: requirePorts是一个属性,指定marathon是否需要指定端口。这样可以确保在mesos代理上绑定端口。这个属性不支持BRIDGE网络模式。
servicePort:服务端口是一个端口用于描述服务应该可用的端口。marathon不绑定到指定的服务端口,但确保你不能有多个应用程序使用相同的服务端口相同的主机上运行。服务端口通常只使用外部应用程序(例如HAProxy)使应用程序可以在指定的端口。更多请参考服务发现和负载均衡
随机端口分配
设置端口是使用0这个值,marathon会为应用分配随机端口。但是如果在端口映射portMapping中containerPort设置成0,containerPort的端口将会hostPort一样。
环境变量
每个主机的端口号可以通过环境变量$PORT0,$PORT1暴露。默认情况下每个marathon应用分配一个端口,所以$PORT0总是有效的。运行在marathon上运行的docker容器中,这些环境变量也是有效的。
当使用BRIDGE网络模式的时候,确保在portMapping端口映射中设置containerPort容器端口号。但是,如果你设置containerPort为0,那么它和hostPort是一样的,并且你可以使用$PORT环境变量。
配置实例
Host模式
host网络模式是默认的网络模式,docker和非docker容器应用都可以使用。注意在你的Dockerfile中EXPOSE不是必须的。
开启Host模式
对容器来说Host模式是默认开启的。如果希望显示配置,可以通过network属性指定。
1
2
3
4
5
6
7
|
"container": {
"type": "DOCKER",
"docker": {
"image": "my-image:1.0",
"network": "HOST"
}
},
|
对于非docker应用,你不需要指定任何东西。
指定端口
通过ports数组指定端口。
1
2
3
|
"ports": [
0, 0, 0
],
|
或者通过portDefinitions数组指定:
1
2
3
|
"portDefinitions": [
{"port": 0}, {"port": 0}, {"port": 0}
],
|
在这个例子中,我们指定3个随机分配的主机端口号,可以通过环境变量$PORT0,$PORT1,$PORT2使用这个三个端口号。marathon将随机分配三个服务端口号service port。
指定服务端口号service port:
1
2
3
|
"ports": [
2001, 2002, 3000
],
|
或者:
1
2
3
|
"portDefinitions": [
{"port": 2001}, {"port": 2002}, {"port": 3000}
],
|
在这个例子中,主机端口$PORT0,$PORT1,$PORT2任然是随机分配的。但是服务端口号service port是2001,2002,3000。使用一个服务发现的解决方案,如HAProxy,代理请求从服务端口service port到主机端口host port,需要按照上面的方式配置。
如果想让服务端口service port和主机端口host port一样,你需要设置requirePorts为true,默认情况下这个值是false。
1
2
3
4
|
"ports": [
2001, 2002, 3000
],
"requirePorts" : true
|
如果你不适用服务发现方案,这个属性是非常有用的。
定义portDefinitions数组,你可以为每个端口指定协议,名称和标签。当开始一个新任务,marathon向mesos发送元数据。mesos将在任务的discovery字段暴露这个信息。自定义网络发现方案会使用这个字段。
下面是定义portDefinitions的实例:
1
2
3
4
5
6
7
8
|
"portDefinitions": [
{
"port": 0,
"protocol": "tcp",
"name": "http",
"labels": {"VIP_0": "10.0.0.1:80"}
}
],
|
port字段是必填的。protocol,name,labels是可选的。如果portDefinitions数组只设置端口port,那么和设置ports数组是一样的。
注意ports和portDefinitions不能一起使用。
引用端口
你可以在Dockerfile文件中引用主机的端口:
1
|
CMD ./my-app --http-port=$PORT0 --https-port=$PORT1 --monitoring-port=$PORT2
|
另外,如果你不使用docker或者使用在你的marathon应用中定义cmd,方式都是一样的:
1
|
"cmd": "./my-app --http-port=$PORT0 --https-port=$PORT1 --monitoring-port=$PORT2"
|
Bridge模式
Bridge网络模式可以映射主机端口到容器内部端口,目前只支持docker容器。如果你使用容器镜像并且端口是固定的,这个模式是非常有用的。注意在Dockerfile中EXPOSE端口不是必须的。
开启Bridge模式
通过network属性指定bridge模式:
1
2
3
4
5
6
7
|
"container": {
"type": "DOCKER",
"docker": {
"image": "my-image:1.0",
"network": "BRIDGE"
}
},
|
指定端口
端口映射类似于docker命令中的参数-p。它指定在容器内的主机和端口的映射管理。
在container中配置端口映射portMappings:
1
2
3
4
5
6
7
8
9
10
11
12
|
"container": {
"type": "DOCKER",
"docker": {
"image": "my-image:1.0",
"network": "BRIDGE",
"portMappings": [
{ "containerPort": 0, "hostPort": 0 },
{ "containerPort": 0, "hostPort": 0 },
{ "containerPort": 0, "hostPort": 0 }
]
}
},
|
这个实例中,主机端口是随机的,并且容器端口号和主机端口号是一致的。此处定义了三个端口映射,在容器内部可以使用环境变量$PORT0、$PORT1、$PORT2引用端口号。
另外,固定容器端口号,配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
"container": {
"type": "DOCKER",
"docker": {
"image": "my-image:1.0",
"network": "BRIDGE",
"portMappings": [
{ "containerPort": 80, "hostPort": 0 },
{ "containerPort": 443, "hostPort": 0 },
{ "containerPort": 4000, "hostPort": 0 }
]
}
},
|
在这个例子中,marathon会随机分配主机端口映射到80,443,4000端口。环境变量$PORT是很重要的,在上面的例子中,$PORT0表示第一个映射中的hostPort值。
指定协议
你也可以为端口指定协议,默认为tcp:
1
2
3
4
5
6
7
8
9
10
11
12
|
"container": {
"type": "DOCKER",
"docker": {
"image": "my-image:1.0",
"network": "BRIDGE",
"portMappings": [
{ "containerPort": 80, "hostPort": 0, "protocol": "tcp" },
{ "containerPort": 443, "hostPort": 0, "protocol": "tcp" },
{ "containerPort": 4000, "hostPort": 0, "protocol": "udp" }
]
}
},
|
指定服务端口
默认情况下,marathon随机创建服务端口service port。服务端口用做服务发现,将服务端口设置成常用端口是一个可取的方案。使用servicePort设置服务端口:
1
2
3
4
5
6
7
8
9
10
11
12
|
"container": {
"type": "DOCKER",
"docker": {
"image": "my-image:1.0",
"network": "BRIDGE",
"portMappings": [
{ "containerPort": 80, "hostPort": 0, "protocol": "tcp", "servicePort": 2000 },
{ "containerPort": 443, "hostPort": 0, "protocol": "tcp", "servicePort": 2001 },
{ "containerPort": 4000, "hostPort": 0, "protocol": "udp", "servicePort": 3000}
]
}
},
|
在这个例子中$PORT0、$PORT1、$PORT2任然是随机分配的。但是服务端口后被设置为2001、2002和3000。外部代理,如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"
|