fix ports
This commit is contained in:
parent
a85b38748f
commit
1fdd0bf5a5
@ -124,7 +124,8 @@ GET /event_stream?uuid=<host_uuid>&task_id=<task_id>
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `entrypoint` | string[] | `[]` | Docker create config 的 `entrypoint`。 |
|
| `entrypoint` | string[] | `[]` | Docker create config 的 `entrypoint`。 |
|
||||||
| `envs` | string[] | `[]` | 环境变量列表,例如 `["A=1"]`,对应 Docker create config 的 `env`。 |
|
| `envs` | string[] | `[]` | 环境变量列表,例如 `["A=1"]`,对应 Docker create config 的 `env`。 |
|
||||||
| `expose` | string[] | `[]` | 容器暴露端口,只表示容器端口,不支持宿主机端口绑定。 |
|
| `expose` | string[] | `[]` | 容器暴露端口,只表示容器端口,不绑定宿主机端口。 |
|
||||||
|
| `ports` | string[] | `[]` | 宿主机到容器的端口映射,格式为 `host_port:container_port`,例如 `["8080:80", "443:443"]`。 |
|
||||||
| `volumes` | string[] | `[]` | volume bind 列表,格式见后文。 |
|
| `volumes` | string[] | `[]` | volume bind 列表,格式见后文。 |
|
||||||
| `networks` | string[] | `[]` | Docker network 名称列表,用于 networking config。 |
|
| `networks` | string[] | `[]` | Docker network 名称列表,用于 networking config。 |
|
||||||
| `network_mode` | string | `""` | Docker host config 的 `network_mode`。 |
|
| `network_mode` | string | `""` | Docker host config 的 `network_mode`。 |
|
||||||
@ -150,10 +151,9 @@ GET /event_stream?uuid=<host_uuid>&task_id=<task_id>
|
|||||||
|
|
||||||
| 字段 | 当前行为 | 说明 |
|
| 字段 | 当前行为 | 说明 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `ports` | 明确拒绝 | 如果传入会返回 `unsupported container config keys: ports`。当前只支持 `expose`,不支持宿主机端口绑定。 |
|
|
||||||
| `container_dir` | 明确拒绝 | 容器目录由 efka 按系统默认规则管理,HTTP 调用方不能指定 efka 主机上的部署目录。 |
|
| `container_dir` | 明确拒绝 | 容器目录由 efka 按系统默认规则管理,HTTP 调用方不能指定 efka 主机上的部署目录。 |
|
||||||
| `env_file` | 忽略 | 当前校验不会识别该字段,后续构造 Docker create options 时也不会使用。 |
|
| `env_file` | 忽略 | 当前校验不会识别该字段,后续构造 Docker create options 时也不会使用。 |
|
||||||
| 其他未知字段 | 忽略 | 除 `ports` 和 `container_dir` 外,未知字段不会报错,也不会进入内部部署参数。 |
|
| 其他未知字段 | 忽略 | 除 `container_dir` 外,未知字段不会报错,也不会进入内部部署参数。 |
|
||||||
|
|
||||||
## 5. 校验规则
|
## 5. 校验规则
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ GET /event_stream?uuid=<host_uuid>&task_id=<task_id>
|
|||||||
|
|
||||||
第二层在 `docker_container_builder:deploy_request/2`:
|
第二层在 `docker_container_builder:deploy_request/2`:
|
||||||
|
|
||||||
- 先拒绝不支持的 `ports` 和 `container_dir` 字段。
|
- 先拒绝不支持的 `container_dir` 字段。
|
||||||
- 检查必填字段是否存在。
|
- 检查必填字段是否存在。
|
||||||
- 检查已知字段类型。
|
- 检查已知字段类型。
|
||||||
- 检查 `healthcheck` 内部字段类型,避免无效嵌套字段进入构造阶段。
|
- 检查 `healthcheck` 内部字段类型,避免无效嵌套字段进入构造阶段。
|
||||||
@ -243,7 +243,7 @@ HTTP handler 最多等待 10 秒。超时返回 HTTP 504,其他参数或执行
|
|||||||
| `user` | `user` | 默认 `""`。 |
|
| `user` | `user` | 默认 `""`。 |
|
||||||
| `working_dir` | `working_dir` | 默认 `""`。 |
|
| `working_dir` | `working_dir` | 默认 `""`。 |
|
||||||
| `hostname` | `hostname` | 默认 `""`。 |
|
| `hostname` | `hostname` | 默认 `""`。 |
|
||||||
| `exposed_ports` | `expose` | 转成 `#{container_port, protocol}` map 列表。 |
|
| `exposed_ports` | `expose` + `ports` | 转成 `#{container_port, protocol}` map 列表;`ports` 中的容器端口会自动补进 `exposed_ports`。 |
|
||||||
| `healthcheck` | `healthcheck` | 未传时为 `undefined`。 |
|
| `healthcheck` | `healthcheck` | 未传时为 `undefined`。 |
|
||||||
|
|
||||||
## 8. Docker host config 映射
|
## 8. Docker host config 映射
|
||||||
@ -263,6 +263,7 @@ HTTP handler 最多等待 10 秒。超时返回 HTTP 504,其他参数或执行
|
|||||||
| `memory_reservation` | `mem_reservation` | 解析成字节数,未传为 `0`。 |
|
| `memory_reservation` | `mem_reservation` | 解析成字节数,未传为 `0`。 |
|
||||||
| `nano_cpus` | `cpus` | `cpus * 1000000000`,未传为 `0`。 |
|
| `nano_cpus` | `cpus` | `cpus * 1000000000`,未传为 `0`。 |
|
||||||
| `cpu_shares` | `cpu_shares` | 未传为 `0`。 |
|
| `cpu_shares` | `cpu_shares` | 未传为 `0`。 |
|
||||||
|
| `port_bindings` | `ports` | 转成 `#{host_ip, host_port, container_port, protocol}` map 列表。 |
|
||||||
| `ulimits` | `ulimits` | 转成 ulimit map 列表。 |
|
| `ulimits` | `ulimits` | 转成 ulimit map 列表。 |
|
||||||
| `tmpfs` | `tmpfs` | 转成 map。 |
|
| `tmpfs` | `tmpfs` | 转成 map。 |
|
||||||
| `sysctls` | `sysctls` | 默认 `{}`。 |
|
| `sysctls` | `sysctls` | 默认 `{}`。 |
|
||||||
@ -339,6 +340,32 @@ HTTP handler 最多等待 10 秒。超时返回 HTTP 504,其他参数或执行
|
|||||||
|
|
||||||
端口必须是无符号整数,且不能超过 `4294967295`。
|
端口必须是无符号整数,且不能超过 `4294967295`。
|
||||||
|
|
||||||
|
### ports
|
||||||
|
|
||||||
|
输入:
|
||||||
|
|
||||||
|
```json
|
||||||
|
["8080:80", "443:443", "8053:53/udp"]
|
||||||
|
```
|
||||||
|
|
||||||
|
转换为 `create.host_config.port_bindings`:
|
||||||
|
|
||||||
|
```erlang
|
||||||
|
[
|
||||||
|
#{<<"host_ip">> => <<>>, <<"host_port">> => 8080, <<"container_port">> => 80, <<"protocol">> => <<"tcp">>},
|
||||||
|
#{<<"host_ip">> => <<>>, <<"host_port">> => 443, <<"container_port">> => 443, <<"protocol">> => <<"tcp">>},
|
||||||
|
#{<<"host_ip">> => <<>>, <<"host_port">> => 8053, <<"container_port">> => 53, <<"protocol">> => <<"udp">>}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
规则:
|
||||||
|
|
||||||
|
- 端口映射之间使用冒号分隔:`host_port:container_port`。
|
||||||
|
- 容器端口可以带协议:`host_port:container_port/protocol`。
|
||||||
|
- 未指定协议时默认为 `tcp`。
|
||||||
|
- host port 和 container port 都不能为空,且必须是 `0..65535` 范围内的无符号整数。
|
||||||
|
- `ports` 中出现的容器端口会自动补进 `create.config.exposed_ports`,因此不需要在 `expose` 里重复声明。
|
||||||
|
|
||||||
### volumes
|
### volumes
|
||||||
|
|
||||||
输入:
|
输入:
|
||||||
@ -599,6 +626,7 @@ HTTP handler 最多等待 10 秒。超时返回 HTTP 504,其他参数或执行
|
|||||||
<<"memory_reservation">> => 0,
|
<<"memory_reservation">> => 0,
|
||||||
<<"nano_cpus">> => 0,
|
<<"nano_cpus">> => 0,
|
||||||
<<"cpu_shares">> => 0,
|
<<"cpu_shares">> => 0,
|
||||||
|
<<"port_bindings">> => [],
|
||||||
<<"ulimits">> => [],
|
<<"ulimits">> => [],
|
||||||
<<"tmpfs">> => #{},
|
<<"tmpfs">> => #{},
|
||||||
<<"sysctls">> => #{},
|
<<"sysctls">> => #{},
|
||||||
@ -628,7 +656,7 @@ HTTP handler 最多等待 10 秒。超时返回 HTTP 504,其他参数或执行
|
|||||||
{
|
{
|
||||||
"error": {
|
"error": {
|
||||||
"code": 400,
|
"code": 400,
|
||||||
"message": "unsupported container config keys: ports"
|
"message": "invalid port binding"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@ -72,7 +72,7 @@ container_ref(ContainerName) when is_binary(ContainerName) ->
|
|||||||
|
|
||||||
-spec ensure_supported_deploy_config(map()) -> ok.
|
-spec ensure_supported_deploy_config(map()) -> ok.
|
||||||
ensure_supported_deploy_config(Config) when is_map(Config) ->
|
ensure_supported_deploy_config(Config) when is_map(Config) ->
|
||||||
UnsupportedKeys = [Key || Key <- [<<"ports">>, <<"container_dir">>], maps:is_key(Key, Config)],
|
UnsupportedKeys = [Key || Key <- [<<"container_dir">>], maps:is_key(Key, Config)],
|
||||||
case UnsupportedKeys of
|
case UnsupportedKeys of
|
||||||
[] ->
|
[] ->
|
||||||
ok;
|
ok;
|
||||||
@ -267,7 +267,7 @@ build_docker_container_config(Config) when is_map(Config) ->
|
|||||||
user => maps:get(<<"user">>, Config, <<>>),
|
user => maps:get(<<"user">>, Config, <<>>),
|
||||||
working_dir => maps:get(<<"working_dir">>, Config, <<>>),
|
working_dir => maps:get(<<"working_dir">>, Config, <<>>),
|
||||||
hostname => maps:get(<<"hostname">>, Config, <<>>),
|
hostname => maps:get(<<"hostname">>, Config, <<>>),
|
||||||
exposed_ports => build_exposed_ports(maps:get(<<"expose">>, Config, [])),
|
exposed_ports => build_exposed_ports(Config),
|
||||||
healthcheck => build_healthcheck(maps:get(<<"healthcheck">>, Config, undefined))
|
healthcheck => build_healthcheck(maps:get(<<"healthcheck">>, Config, undefined))
|
||||||
}.
|
}.
|
||||||
|
|
||||||
@ -285,6 +285,7 @@ build_docker_host_config(Config) when is_map(Config) ->
|
|||||||
memory_reservation => default_uint64(parse_optional_size_bytes(maps:get(<<"mem_reservation">>, Config, undefined), <<"mem_reservation">>)),
|
memory_reservation => default_uint64(parse_optional_size_bytes(maps:get(<<"mem_reservation">>, Config, undefined), <<"mem_reservation">>)),
|
||||||
nano_cpus => default_uint64(parse_optional_nano_cpus(maps:get(<<"cpus">>, Config, undefined))),
|
nano_cpus => default_uint64(parse_optional_nano_cpus(maps:get(<<"cpus">>, Config, undefined))),
|
||||||
cpu_shares => default_uint64(maps:get(<<"cpu_shares">>, Config, undefined)),
|
cpu_shares => default_uint64(maps:get(<<"cpu_shares">>, Config, undefined)),
|
||||||
|
port_bindings => build_port_bindings(maps:get(<<"ports">>, Config, [])),
|
||||||
ulimits => build_ulimits(maps:get(<<"ulimits">>, Config, #{})),
|
ulimits => build_ulimits(maps:get(<<"ulimits">>, Config, #{})),
|
||||||
tmpfs => maps:from_list(build_tmpfs_options(maps:get(<<"tmpfs">>, Config, []))),
|
tmpfs => maps:from_list(build_tmpfs_options(maps:get(<<"tmpfs">>, Config, []))),
|
||||||
sysctls => maps:get(<<"sysctls">>, Config, #{}),
|
sysctls => maps:get(<<"sysctls">>, Config, #{}),
|
||||||
@ -357,9 +358,14 @@ volume_bind(HostPath, ContainerPath, true) when is_binary(HostPath), is_binary(C
|
|||||||
volume_bind(HostPath, ContainerPath, false) when is_binary(HostPath), is_binary(ContainerPath) ->
|
volume_bind(HostPath, ContainerPath, false) when is_binary(HostPath), is_binary(ContainerPath) ->
|
||||||
<<HostPath/binary, ":", ContainerPath/binary>>.
|
<<HostPath/binary, ":", ContainerPath/binary>>.
|
||||||
|
|
||||||
-spec build_exposed_ports([binary()]) -> [map()].
|
-spec build_exposed_ports(map()) -> [map()].
|
||||||
build_exposed_ports(ExposeSpecs) when is_list(ExposeSpecs) ->
|
build_exposed_ports(Config) when is_map(Config) ->
|
||||||
[build_exposed_port(ExposeSpec) || ExposeSpec <- ExposeSpecs].
|
ExposePorts = [build_exposed_port(ExposeSpec) || ExposeSpec <- maps:get(<<"expose">>, Config, [])],
|
||||||
|
BoundPorts = [
|
||||||
|
#{container_port => ContainerPort, protocol => Protocol} ||
|
||||||
|
#{container_port := ContainerPort, protocol := Protocol} <- build_port_bindings(maps:get(<<"ports">>, Config, []))
|
||||||
|
],
|
||||||
|
unique_ports(ExposePorts ++ BoundPorts).
|
||||||
|
|
||||||
-spec build_exposed_port(binary()) -> map().
|
-spec build_exposed_port(binary()) -> map().
|
||||||
build_exposed_port(ExposeSpec) when is_binary(ExposeSpec) ->
|
build_exposed_port(ExposeSpec) when is_binary(ExposeSpec) ->
|
||||||
@ -370,6 +376,52 @@ build_exposed_port(ExposeSpec) when is_binary(ExposeSpec) ->
|
|||||||
#{container_port => parse_uint32(PortBin, <<"expose">>), protocol => Protocol}
|
#{container_port => parse_uint32(PortBin, <<"expose">>), protocol => Protocol}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec build_port_bindings([binary()]) -> [map()].
|
||||||
|
build_port_bindings(PortSpecs) when is_list(PortSpecs) ->
|
||||||
|
[build_port_binding(PortSpec) || PortSpec <- PortSpecs].
|
||||||
|
|
||||||
|
-spec build_port_binding(binary()) -> map().
|
||||||
|
build_port_binding(PortSpec) when is_binary(PortSpec) ->
|
||||||
|
case binary:split(PortSpec, <<":">>, [global]) of
|
||||||
|
[HostPortBin, ContainerPortSpec] when HostPortBin =/= <<>>, ContainerPortSpec =/= <<>> ->
|
||||||
|
{ContainerPort, Protocol} = parse_container_port_spec(ContainerPortSpec, <<"ports">>),
|
||||||
|
#{
|
||||||
|
host_ip => <<>>,
|
||||||
|
host_port => parse_tcp_port(HostPortBin, <<"ports.host_port">>),
|
||||||
|
container_port => ContainerPort,
|
||||||
|
protocol => Protocol
|
||||||
|
};
|
||||||
|
_ ->
|
||||||
|
throw({error, <<"invalid port binding">>})
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec parse_container_port_spec(binary(), binary()) -> {non_neg_integer(), binary()}.
|
||||||
|
parse_container_port_spec(PortSpec, Field) when is_binary(PortSpec), is_binary(Field) ->
|
||||||
|
case binary:split(PortSpec, <<"/">>) of
|
||||||
|
[PortBin] ->
|
||||||
|
{parse_tcp_port(PortBin, Field), <<"tcp">>};
|
||||||
|
[PortBin, Protocol] when Protocol =/= <<>> ->
|
||||||
|
{parse_tcp_port(PortBin, Field), Protocol};
|
||||||
|
_ ->
|
||||||
|
throw({error, <<"invalid port binding">>})
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec unique_ports([map()]) -> [map()].
|
||||||
|
unique_ports(Ports) when is_list(Ports) ->
|
||||||
|
{_Seen, Result} = lists:foldl(
|
||||||
|
fun(Port = #{container_port := ContainerPort, protocol := Protocol}, {Seen, Acc}) ->
|
||||||
|
Key = {ContainerPort, Protocol},
|
||||||
|
case maps:is_key(Key, Seen) of
|
||||||
|
true ->
|
||||||
|
{Seen, Acc};
|
||||||
|
false ->
|
||||||
|
{Seen#{Key => true}, [Port | Acc]}
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{#{}, []},
|
||||||
|
Ports),
|
||||||
|
lists:reverse(Result).
|
||||||
|
|
||||||
-spec build_device_mappings([binary()]) -> [map()].
|
-spec build_device_mappings([binary()]) -> [map()].
|
||||||
build_device_mappings(DeviceSpecs) when is_list(DeviceSpecs) ->
|
build_device_mappings(DeviceSpecs) when is_list(DeviceSpecs) ->
|
||||||
[build_device_mapping(DeviceSpec) || DeviceSpec <- DeviceSpecs].
|
[build_device_mapping(DeviceSpec) || DeviceSpec <- DeviceSpecs].
|
||||||
@ -479,6 +531,16 @@ parse_uint32(Value, Field) when is_binary(Value), is_binary(Field) ->
|
|||||||
throw({error, <<"value overflow for ", Field/binary>>})
|
throw({error, <<"value overflow for ", Field/binary>>})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec parse_tcp_port(binary(), binary()) -> non_neg_integer().
|
||||||
|
parse_tcp_port(Value, Field) when is_binary(Value), is_binary(Field) ->
|
||||||
|
Parsed = parse_uint32(Value, Field),
|
||||||
|
case Parsed =< 65535 of
|
||||||
|
true ->
|
||||||
|
Parsed;
|
||||||
|
false ->
|
||||||
|
throw({error, <<"port out of range for ", Field/binary>>})
|
||||||
|
end.
|
||||||
|
|
||||||
-spec parse_uint64(binary(), binary()) -> non_neg_integer().
|
-spec parse_uint64(binary(), binary()) -> non_neg_integer().
|
||||||
parse_uint64(Value0, Field) when is_binary(Value0), is_binary(Field) ->
|
parse_uint64(Value0, Field) when is_binary(Value0), is_binary(Field) ->
|
||||||
Value = trim_binary(Value0),
|
Value = trim_binary(Value0),
|
||||||
|
|||||||
@ -240,6 +240,7 @@ handle_message_frame(Body, State) ->
|
|||||||
|
|
||||||
-spec handle_event_stream_frame(binary(), map()) -> ok.
|
-spec handle_event_stream_frame(binary(), map()) -> ok.
|
||||||
handle_event_stream_frame(UUID, #{<<"task_id">> := TaskId, <<"type">> := <<"close">>, <<"stream">> := Reason}) ->
|
handle_event_stream_frame(UUID, #{<<"task_id">> := TaskId, <<"type">> := <<"close">>, <<"stream">> := Reason}) ->
|
||||||
|
logger:debug("[ssl_channel] get uuid: ~p, task_id: ~p, close with reason: ~p", [UUID, TaskId, Reason]),
|
||||||
iot_container_task_sup:close(UUID, TaskId, Reason);
|
iot_container_task_sup:close(UUID, TaskId, Reason);
|
||||||
handle_event_stream_frame(UUID, #{<<"task_id">> := TaskId, <<"type">> := Type, <<"stream">> := Stream}) ->
|
handle_event_stream_frame(UUID, #{<<"task_id">> := TaskId, <<"type">> := Type, <<"stream">> := Stream}) ->
|
||||||
logger:debug("[ssl_channel] get uuid: ~p, task_id: ~p, type: ~ts, stream: ~ts", [UUID, TaskId, Type, Stream]),
|
logger:debug("[ssl_channel] get uuid: ~p, task_id: ~p, type: ~ts, stream: ~ts", [UUID, TaskId, Type, Stream]),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user