fix
This commit is contained in:
parent
863156667c
commit
576ccb2b10
@ -8,10 +8,11 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(docker_commands).
|
-module(docker_commands).
|
||||||
-author("anlicheng").
|
-author("anlicheng").
|
||||||
|
-include("message_pb.hrl").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([pull_image/2, check_image_exist/1]).
|
-export([pull_image/2, check_image_exist/1]).
|
||||||
-export([create_container/3, check_container_exist/1, is_container_running/1,
|
-export([create_container/2, check_container_exist/1, is_container_running/1,
|
||||||
start_container/1, stop_container/1, stop_container/2, remove_container/1, remove_container/3, kill_container/1, kill_container/2,
|
start_container/1, stop_container/1, stop_container/2, remove_container/1, remove_container/3, kill_container/1, kill_container/2,
|
||||||
get_containers/0]).
|
get_containers/0]).
|
||||||
|
|
||||||
@ -31,18 +32,22 @@ check_image_exist(Image) when is_binary(Image) ->
|
|||||||
false
|
false
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec create_container(ContainerName :: binary(), ContainerDir :: string(), Config :: map()) -> {ok, ContainerId :: binary()} | {error, Reason :: any()}.
|
-spec create_container(ContainerDir :: string(), Params :: message_pb:'ContainerDeployParams'()) ->
|
||||||
create_container(ContainerName, ContainerDir, Config) when is_binary(ContainerName), is_list(ContainerDir), is_map(Config) ->
|
{ok, ContainerId :: binary()} | {error, Reason :: any()}.
|
||||||
|
create_container(ContainerDir, #'ContainerDeployParams'{
|
||||||
|
container_name = ContainerName,
|
||||||
|
spec = Spec0
|
||||||
|
}) when is_binary(ContainerName), is_list(ContainerDir), is_record(Spec0, 'ContainerSpec') ->
|
||||||
Url = lists:flatten(io_lib:format("/containers/create?name=~s", [binary_to_list(ContainerName)])),
|
Url = lists:flatten(io_lib:format("/containers/create?name=~s", [binary_to_list(ContainerName)])),
|
||||||
%% 挂载预留的目录,用来作为配置文件的存放
|
%% 挂载预留的目录,用来作为配置文件的存放
|
||||||
ConfigFile = list_to_binary(docker_helper:get_config_file(ContainerDir)),
|
ConfigFile = list_to_binary(docker_helper:get_config_file(ContainerDir)),
|
||||||
|
ConfigVolume = #'VolumeBind'{
|
||||||
%% 增加自定义的用来放配置文件的目录
|
host_path = ConfigFile,
|
||||||
Volumes0 = maps:get(<<"volumes">>, Config, []),
|
container_path = <<"/usr/local/etc/service.conf">>,
|
||||||
Volumes = [<<ConfigFile/binary, ":/usr/local/etc/service.conf">>|Volumes0],
|
read_only = false
|
||||||
NewConfig = Config#{<<"volumes">> => Volumes},
|
},
|
||||||
|
Spec = Spec0#'ContainerSpec'{volumes = [ConfigVolume | Spec0#'ContainerSpec'.volumes]},
|
||||||
Options = build_options(ContainerName, NewConfig),
|
Options = build_options(ContainerName, Spec),
|
||||||
display_options(Options),
|
display_options(Options),
|
||||||
|
|
||||||
Body = iolist_to_binary(jiffy:encode(Options, [force_utf8])),
|
Body = iolist_to_binary(jiffy:encode(Options, [force_utf8])),
|
||||||
@ -234,36 +239,35 @@ inspect_container(ContainerId) when is_binary(ContainerId) ->
|
|||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
%% 构建最终 JSON Map
|
%% 构建最终 JSON Map
|
||||||
build_options(ContainerName, Config) when is_binary(ContainerName), is_map(Config) ->
|
build_options(ContainerName, #'ContainerSpec'{} = Spec) when is_binary(ContainerName) ->
|
||||||
%% 容器名称作为环境变量,注入到运行时环境中
|
%% 容器名称作为环境变量,注入到运行时环境中
|
||||||
Envs0 = maps:get(<<"envs">>, Config, []),
|
Envs0 = [to_binary(Env) || Env <- Spec#'ContainerSpec'.env],
|
||||||
Envs = [<<"CONTAINER_NAME=", ContainerName/binary>>|Envs0],
|
Envs = [<<"CONTAINER_NAME=", ContainerName/binary>>|Envs0],
|
||||||
#{
|
#{
|
||||||
<<"Image">> => maps:get(<<"image">>, Config, <<>>),
|
<<"Image">> => to_binary(Spec#'ContainerSpec'.image),
|
||||||
<<"Cmd">> => maps:get(<<"command">>, Config, []),
|
<<"Cmd">> => [to_binary(Command) || Command <- Spec#'ContainerSpec'.command],
|
||||||
<<"Entrypoint">> => maps:get(<<"entrypoint">>, Config, []),
|
<<"Entrypoint">> => [to_binary(Entrypoint) || Entrypoint <- Spec#'ContainerSpec'.entrypoint],
|
||||||
<<"Env">> => Envs,
|
<<"Env">> => Envs,
|
||||||
<<"Labels">> => maps:get(<<"labels">>, Config, #{}),
|
<<"Labels">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Spec#'ContainerSpec'.labels]),
|
||||||
<<"Volumes">> => build_volumes(Config),
|
<<"Volumes">> => build_volumes(Spec),
|
||||||
<<"User">> => maps:get(<<"user">>, Config, <<>>),
|
<<"User">> => to_binary(Spec#'ContainerSpec'.user),
|
||||||
<<"WorkingDir">> => maps:get(<<"working_dir">>, Config, <<>>),
|
<<"WorkingDir">> => to_binary(Spec#'ContainerSpec'.working_dir),
|
||||||
<<"Hostname">> => maps:get(<<"hostname">>, Config, <<>>),
|
<<"Hostname">> => to_binary(Spec#'ContainerSpec'.hostname),
|
||||||
<<"ExposedPorts">> => build_expose(Config),
|
<<"ExposedPorts">> => build_expose(Spec),
|
||||||
<<"NetworkingConfig">> => build_networks(Config),
|
<<"NetworkingConfig">> => build_networks(Spec),
|
||||||
<<"Healthcheck">> => build_healthcheck(Config),
|
<<"Healthcheck">> => build_healthcheck(Spec),
|
||||||
<<"HostConfig">> => fold_merge([
|
<<"HostConfig">> => fold_merge([
|
||||||
build_network_mode(Config),
|
build_network_mode(Spec),
|
||||||
build_binds(Config),
|
build_binds(Spec),
|
||||||
build_restart(Config),
|
build_restart(Spec),
|
||||||
build_privileged(Config),
|
build_privileged(Spec),
|
||||||
build_cap_add_drop(Config),
|
build_cap_add_drop(Spec),
|
||||||
build_devices(Config),
|
build_devices(Spec),
|
||||||
build_memory(Config),
|
build_resources(Spec),
|
||||||
build_cpu(Config),
|
build_ulimits(Spec),
|
||||||
build_ulimits(Config),
|
build_tmpfs(Spec),
|
||||||
build_tmpfs(Config),
|
build_sysctls(Spec),
|
||||||
build_sysctls(Config),
|
build_extra_hosts(Spec)
|
||||||
build_extra_hosts(Config)
|
|
||||||
])
|
])
|
||||||
}.
|
}.
|
||||||
|
|
||||||
@ -272,221 +276,180 @@ fold_merge(List) ->
|
|||||||
lists:foldl(fun maps:merge/2, #{}, List).
|
lists:foldl(fun maps:merge/2, #{}, List).
|
||||||
|
|
||||||
%% --- 构建子字段 ---
|
%% --- 构建子字段 ---
|
||||||
build_expose(Config) ->
|
build_expose(#'ContainerSpec'{expose = Ports}) ->
|
||||||
Ports = maps:get(<<"expose">>, Config, []),
|
|
||||||
case Ports of
|
case Ports of
|
||||||
[] -> #{};
|
[] -> #{};
|
||||||
_ ->
|
_ ->
|
||||||
maps:from_list([{normalize_expose_port(P), #{}} || P <- Ports])
|
maps:from_list([{normalize_expose_port(P), #{}} || P <- Ports])
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_volumes(Config) ->
|
build_volumes(#'ContainerSpec'{volumes = Vols}) ->
|
||||||
Vols = maps:get(<<"volumes">>, Config, []),
|
|
||||||
case Vols of
|
case Vols of
|
||||||
[] ->
|
[] ->
|
||||||
#{};
|
#{};
|
||||||
_ ->
|
_ ->
|
||||||
maps:from_list(lists:map(fun(V) ->
|
maps:from_list([{to_binary(Cont), #{}} || #'VolumeBind'{container_path = Cont} <- Vols])
|
||||||
[_Host, Cont | _Modes] = binary:split(V, <<":">>, [global]),
|
|
||||||
{Cont, #{}}
|
|
||||||
end, Vols))
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_binds(Config) ->
|
build_binds(#'ContainerSpec'{volumes = Vols}) ->
|
||||||
Vols = maps:get(<<"volumes">>, Config, []),
|
|
||||||
case Vols of
|
case Vols of
|
||||||
[] ->
|
[] ->
|
||||||
#{};
|
#{};
|
||||||
_ ->
|
_ ->
|
||||||
#{<<"Binds">> => Vols}
|
#{<<"Binds">> => [volume_bind(Vol) || Vol <- Vols]}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_networks(Config) ->
|
build_networks(#'ContainerSpec'{networks = Nets}) ->
|
||||||
Nets = maps:get(<<"networks">>, Config, []),
|
|
||||||
case Nets of
|
case Nets of
|
||||||
[] -> #{};
|
[] -> #{};
|
||||||
_ ->
|
_ ->
|
||||||
NetCfg = maps:from_list([{N, #{}} || N <- Nets]),
|
NetCfg = maps:from_list([{to_binary(N), #{}} || N <- Nets]),
|
||||||
#{<<"EndpointsConfig">> => NetCfg}
|
#{<<"EndpointsConfig">> => NetCfg}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_network_mode(Config) ->
|
build_network_mode(#'ContainerSpec'{network_mode = <<>>}) ->
|
||||||
NetworkMode = maps:get(<<"network_mode">>, Config, <<"bridge">>),
|
#{};
|
||||||
#{<<"NetworkMode">> => NetworkMode}.
|
build_network_mode(#'ContainerSpec'{network_mode = NetworkMode}) ->
|
||||||
|
#{<<"NetworkMode">> => to_binary(NetworkMode)}.
|
||||||
|
|
||||||
parse_mem(Val) ->
|
build_healthcheck(#'ContainerSpec'{healthcheck = undefined}) ->
|
||||||
case binary:last(Val) of
|
#{};
|
||||||
$m ->
|
build_healthcheck(#'ContainerSpec'{healthcheck = #'Healthcheck'{
|
||||||
N = binary:part(Val, {0, byte_size(Val)-1}),
|
test = Test,
|
||||||
list_to_integer(binary_to_list(N)) * 1024 * 1024;
|
interval_ns = IntervalNs,
|
||||||
$g ->
|
timeout_ns = TimeoutNs,
|
||||||
N = binary:part(Val, {0, byte_size(Val)-1}),
|
retries = Retries
|
||||||
list_to_integer(binary_to_list(N)) * 1024 * 1024 * 1024;
|
}}) ->
|
||||||
_ ->
|
#{
|
||||||
list_to_integer(binary_to_list(Val))
|
<<"Test">> => [to_binary(Item) || Item <- Test],
|
||||||
end.
|
<<"Interval">> => IntervalNs,
|
||||||
|
<<"Timeout">> => TimeoutNs,
|
||||||
|
<<"Retries">> => Retries
|
||||||
|
}.
|
||||||
|
|
||||||
build_healthcheck(Config) ->
|
build_restart(#'ContainerSpec'{restart = undefined}) ->
|
||||||
HC = maps:get(<<"healthcheck">>, Config, #{}),
|
#{};
|
||||||
case maps:size(HC) of
|
build_restart(#'ContainerSpec'{restart = #'RestartPolicy'{
|
||||||
|
name = Name,
|
||||||
|
maximum_retry_count = RetryCount
|
||||||
|
}}) ->
|
||||||
|
RestartPolicy = #{
|
||||||
|
<<"Name">> => to_binary(Name)
|
||||||
|
},
|
||||||
|
case RetryCount of
|
||||||
0 ->
|
0 ->
|
||||||
#{};
|
#{<<"RestartPolicy">> => RestartPolicy};
|
||||||
_ ->
|
_ ->
|
||||||
#{
|
#{<<"RestartPolicy">> => RestartPolicy#{
|
||||||
<<"Test">> => maps:get(<<"test">>, HC, []),
|
<<"MaximumRetryCount">> => RetryCount
|
||||||
<<"Interval">> => parse_duration(maps:get(<<"interval">>, HC, <<"0s">>)),
|
}}
|
||||||
<<"Timeout">> => parse_duration(maps:get(<<"timeout">>, HC, <<"0s">>)),
|
|
||||||
<<"Retries">> => maps:get(<<"retries">>, HC, 0)
|
|
||||||
}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
parse_duration(Bin) ->
|
build_privileged(#'ContainerSpec'{privileged = Privileged}) ->
|
||||||
case re:run(Bin, <<"^(\\d+)(ns|us|ms|s|m|h)?$">>, [{capture, all_but_first, binary}]) of
|
case to_bool(Privileged) of
|
||||||
{match, [NumberBin, Unit]} ->
|
|
||||||
Number = binary_to_integer(NumberBin),
|
|
||||||
case Unit of
|
|
||||||
<<"ns">> ->
|
|
||||||
Number;
|
|
||||||
<<"us">> ->
|
|
||||||
Number * 1000;
|
|
||||||
<<"ms">> ->
|
|
||||||
Number * 1000000;
|
|
||||||
<<"s">> ->
|
|
||||||
Number * 1000000000;
|
|
||||||
<<"m">> ->
|
|
||||||
Number * 60000000000;
|
|
||||||
<<"h">> ->
|
|
||||||
Number * 3600000000000
|
|
||||||
end;
|
|
||||||
{match, [NumberBin]} ->
|
|
||||||
binary_to_integer(NumberBin)
|
|
||||||
end.
|
|
||||||
|
|
||||||
%% --- 构建子字段 ---
|
|
||||||
|
|
||||||
build_restart(Config) ->
|
|
||||||
case maps:get(<<"restart">>, Config, undefined) of
|
|
||||||
undefined ->
|
|
||||||
#{};
|
|
||||||
Policy ->
|
|
||||||
case binary:split(Policy, <<":">>) of
|
|
||||||
[Name, RetryCountBin] ->
|
|
||||||
#{<<"RestartPolicy">> => #{
|
|
||||||
<<"Name">> => Name,
|
|
||||||
<<"MaximumRetryCount">> => binary_to_integer(RetryCountBin)
|
|
||||||
}};
|
|
||||||
[Name] ->
|
|
||||||
#{<<"RestartPolicy">> => #{<<"Name">> => Name}}
|
|
||||||
end
|
|
||||||
end.
|
|
||||||
|
|
||||||
build_privileged(Config) ->
|
|
||||||
case maps:get(<<"privileged">>, Config, false) of
|
|
||||||
true ->
|
true ->
|
||||||
#{<<"Privileged">> => true};
|
#{<<"Privileged">> => true};
|
||||||
_ ->
|
_ ->
|
||||||
#{}
|
#{}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_cap_add_drop(Config) ->
|
build_cap_add_drop(#'ContainerSpec'{cap_add = Add, cap_drop = Drop}) ->
|
||||||
Add = maps:get(<<"cap_add">>, Config, []),
|
|
||||||
Drop = maps:get(<<"cap_drop">>, Config, []),
|
|
||||||
case {Add, Drop} of
|
case {Add, Drop} of
|
||||||
{[], []} ->
|
{[], []} ->
|
||||||
#{};
|
#{};
|
||||||
_ ->
|
_ ->
|
||||||
#{<<"CapAdd">> => Add, <<"CapDrop">> => Drop}
|
#{
|
||||||
|
<<"CapAdd">> => [to_binary(Item) || Item <- Add],
|
||||||
|
<<"CapDrop">> => [to_binary(Item) || Item <- Drop]
|
||||||
|
}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_devices(Config) ->
|
build_devices(#'ContainerSpec'{devices = Devs}) ->
|
||||||
Devs = maps:get(<<"devices">>, Config, []),
|
|
||||||
case Devs of
|
case Devs of
|
||||||
[] ->
|
[] ->
|
||||||
#{};
|
#{};
|
||||||
_ ->
|
_ ->
|
||||||
DevObjs = [#{<<"PathOnHost">> => H, <<"PathInContainer">> => C,
|
DevObjs = [#{
|
||||||
<<"CgroupPermissions">> => P}
|
<<"PathOnHost">> => to_binary(HostPath),
|
||||||
|| D <- Devs,
|
<<"PathInContainer">> => to_binary(ContainerPath),
|
||||||
{H, C, P} <- [parse_device_mapping(D)]],
|
<<"CgroupPermissions">> => device_permissions(Permissions)
|
||||||
|
} || #'DeviceMapping'{
|
||||||
|
host_path = HostPath,
|
||||||
|
container_path = ContainerPath,
|
||||||
|
cgroup_permissions = Permissions
|
||||||
|
} <- Devs],
|
||||||
#{<<"Devices">> => DevObjs}
|
#{<<"Devices">> => DevObjs}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_memory(Config) ->
|
build_resources(#'ContainerSpec'{resources = undefined}) ->
|
||||||
Mem = maps:get(<<"mem_limit">>, Config, undefined),
|
#{};
|
||||||
MemRes = maps:get(<<"mem_reservation">>, Config, undefined),
|
build_resources(#'ContainerSpec'{resources = #'ResourceLimits'{
|
||||||
HCfg = #{},
|
memory_bytes = MemoryBytes,
|
||||||
HCfg1 = if
|
memory_reservation_bytes = ReservationBytes,
|
||||||
Mem /= undefined ->
|
nano_cpus = NanoCpus,
|
||||||
maps:put(<<"Memory">>, parse_mem(Mem), HCfg);
|
cpu_shares = CpuShares
|
||||||
true ->
|
}}) ->
|
||||||
HCfg
|
HostConfig0 = #{},
|
||||||
end,
|
HostConfig1 = case MemoryBytes of
|
||||||
if
|
|
||||||
MemRes /= undefined ->
|
|
||||||
maps:put(<<"MemoryReservation">>, parse_mem(MemRes), HCfg1);
|
|
||||||
true ->
|
|
||||||
HCfg1
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
build_cpu(Config) ->
|
|
||||||
CPU = maps:get(<<"cpus">>, Config, undefined),
|
|
||||||
Shares = maps:get(<<"cpu_shares">>, Config, undefined),
|
|
||||||
HCfg = #{},
|
|
||||||
HCfg1 = if
|
|
||||||
CPU /= undefined ->
|
|
||||||
maps:put(<<"NanoCpus">>, trunc(CPU * 1000000000), HCfg);
|
|
||||||
true ->
|
|
||||||
HCfg
|
|
||||||
end,
|
|
||||||
if
|
|
||||||
Shares /= undefined ->
|
|
||||||
maps:put(<<"CpuShares">>, Shares, HCfg1);
|
|
||||||
true ->
|
|
||||||
HCfg1
|
|
||||||
end.
|
|
||||||
|
|
||||||
build_ulimits(Config) ->
|
|
||||||
UL = maps:get(<<"ulimits">>, Config, #{}),
|
|
||||||
case maps:size(UL) of
|
|
||||||
0 ->
|
0 ->
|
||||||
#{};
|
HostConfig0;
|
||||||
_ ->
|
_ ->
|
||||||
ULList = lists:map(fun({K, V}) ->
|
HostConfig0#{<<"Memory">> => MemoryBytes}
|
||||||
[S1, H1] = binary:split(V, <<":">>, []),
|
end,
|
||||||
S = list_to_integer(binary_to_list(S1)),
|
HostConfig2 = case ReservationBytes of
|
||||||
H = list_to_integer(binary_to_list(H1)),
|
|
||||||
#{<<"Name">> => K, <<"Soft">> => S, <<"Hard">> => H}
|
|
||||||
end, maps:to_list(UL)),
|
|
||||||
|
|
||||||
#{<<"Ulimits">> => ULList}
|
|
||||||
end.
|
|
||||||
|
|
||||||
build_sysctls(Config) ->
|
|
||||||
SC = maps:get(<<"sysctls">>, Config, #{}),
|
|
||||||
case maps:size(SC) of
|
|
||||||
0 ->
|
0 ->
|
||||||
#{};
|
HostConfig1;
|
||||||
_ ->
|
_ ->
|
||||||
#{<<"Sysctls">> => SC}
|
HostConfig1#{<<"MemoryReservation">> => ReservationBytes}
|
||||||
|
end,
|
||||||
|
HostConfig3 = case NanoCpus of
|
||||||
|
0 ->
|
||||||
|
HostConfig2;
|
||||||
|
_ ->
|
||||||
|
HostConfig2#{<<"NanoCpus">> => NanoCpus}
|
||||||
|
end,
|
||||||
|
case CpuShares of
|
||||||
|
0 ->
|
||||||
|
HostConfig3;
|
||||||
|
_ ->
|
||||||
|
HostConfig3#{<<"CpuShares">> => CpuShares}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_tmpfs(Config) ->
|
build_ulimits(#'ContainerSpec'{ulimits = Ulimits}) ->
|
||||||
Tmp = maps:get(<<"tmpfs">>, Config, []),
|
case Ulimits of
|
||||||
case Tmp of
|
|
||||||
[] ->
|
[] ->
|
||||||
#{};
|
#{};
|
||||||
_ ->
|
_ ->
|
||||||
#{<<"Tmpfs">> => maps:from_list([parse_tmpfs_mount(T) || T <- Tmp])}
|
#{<<"Ulimits">> => [#{
|
||||||
|
<<"Name">> => to_binary(Name),
|
||||||
|
<<"Soft">> => Soft,
|
||||||
|
<<"Hard">> => Hard
|
||||||
|
} || #'Ulimit'{name = Name, soft = Soft, hard = Hard} <- Ulimits]}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_extra_hosts(Config) ->
|
build_sysctls(#'ContainerSpec'{sysctls = Sysctls}) ->
|
||||||
Hosts = maps:get(<<"extra_hosts">>, Config, []),
|
case Sysctls of
|
||||||
|
[] ->
|
||||||
|
#{};
|
||||||
|
_ ->
|
||||||
|
#{<<"Sysctls">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Sysctls])}
|
||||||
|
end.
|
||||||
|
|
||||||
|
build_tmpfs(#'ContainerSpec'{tmpfs = Tmpfs}) ->
|
||||||
|
case Tmpfs of
|
||||||
|
[] ->
|
||||||
|
#{};
|
||||||
|
_ ->
|
||||||
|
#{<<"Tmpfs">> => maps:from_list([{to_binary(Path), to_binary(Options)} ||
|
||||||
|
#'TmpfsMount'{path = Path, options = Options} <- Tmpfs])}
|
||||||
|
end.
|
||||||
|
|
||||||
|
build_extra_hosts(#'ContainerSpec'{extra_hosts = Hosts}) ->
|
||||||
case Hosts of
|
case Hosts of
|
||||||
[] ->
|
[] ->
|
||||||
#{};
|
#{};
|
||||||
_ ->
|
_ ->
|
||||||
#{<<"ExtraHosts">> => Hosts}
|
#{<<"ExtraHosts">> => [to_binary(Host) || Host <- Hosts]}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec display_options(Options :: map()) -> no_return().
|
-spec display_options(Options :: map()) -> no_return().
|
||||||
@ -494,28 +457,31 @@ display_options(Options) when is_map(Options) ->
|
|||||||
logger:debug("deploy options: ~p", [jiffy:encode(Options, [force_utf8])]),
|
logger:debug("deploy options: ~p", [jiffy:encode(Options, [force_utf8])]),
|
||||||
lists:foreach(fun({K, V}) -> logger:debug("~p => ~p", [K, V]) end, maps:to_list(Options)).
|
lists:foreach(fun({K, V}) -> logger:debug("~p => ~p", [K, V]) end, maps:to_list(Options)).
|
||||||
|
|
||||||
normalize_expose_port(Port) when is_binary(Port) ->
|
normalize_expose_port(#'PortExpose'{container_port = Port, protocol = Protocol}) ->
|
||||||
case binary:match(Port, <<"/">>) of
|
PortBin = integer_to_binary(Port),
|
||||||
nomatch ->
|
ProtocolBin = to_binary(Protocol),
|
||||||
<<Port/binary, "/tcp">>;
|
case ProtocolBin of
|
||||||
|
<<>> ->
|
||||||
|
<<PortBin/binary, "/tcp">>;
|
||||||
|
<<"tcp">> ->
|
||||||
|
<<PortBin/binary, "/tcp">>;
|
||||||
_ ->
|
_ ->
|
||||||
Port
|
<<PortBin/binary, "/", ProtocolBin/binary>>
|
||||||
end.
|
end.
|
||||||
|
|
||||||
parse_device_mapping(Device) when is_binary(Device) ->
|
device_permissions(<<>>) ->
|
||||||
case binary:split(Device, <<":">>, [global]) of
|
<<"rwm">>;
|
||||||
[HostPath, ContainerPath] ->
|
device_permissions(Permissions) ->
|
||||||
{HostPath, ContainerPath, <<"rwm">>};
|
to_binary(Permissions).
|
||||||
[HostPath, ContainerPath, Permissions] ->
|
|
||||||
{HostPath, ContainerPath, Permissions}
|
|
||||||
end.
|
|
||||||
|
|
||||||
parse_tmpfs_mount(Tmpfs) when is_binary(Tmpfs) ->
|
volume_bind(#'VolumeBind'{host_path = HostPath, container_path = ContainerPath, read_only = ReadOnly}) ->
|
||||||
case binary:split(Tmpfs, <<":">>) of
|
HostPathBin = to_binary(HostPath),
|
||||||
[Path] ->
|
ContainerPathBin = to_binary(ContainerPath),
|
||||||
{Path, <<>>};
|
case to_bool(ReadOnly) of
|
||||||
[Path, Options] ->
|
true ->
|
||||||
{Path, Options}
|
<<HostPathBin/binary, ":", ContainerPathBin/binary, ":ro">>;
|
||||||
|
false ->
|
||||||
|
<<HostPathBin/binary, ":", ContainerPathBin/binary>>
|
||||||
end.
|
end.
|
||||||
|
|
||||||
build_stop_container_url(ContainerName, 0) ->
|
build_stop_container_url(ContainerName, 0) ->
|
||||||
@ -541,3 +507,17 @@ boolean_to_query_value(true) ->
|
|||||||
"true";
|
"true";
|
||||||
boolean_to_query_value(false) ->
|
boolean_to_query_value(false) ->
|
||||||
"false".
|
"false".
|
||||||
|
|
||||||
|
to_binary(Value) when is_binary(Value) ->
|
||||||
|
Value;
|
||||||
|
to_binary(Value) when is_list(Value) ->
|
||||||
|
unicode:characters_to_binary(Value).
|
||||||
|
|
||||||
|
to_bool(true) ->
|
||||||
|
true;
|
||||||
|
to_bool(1) ->
|
||||||
|
true;
|
||||||
|
to_bool(false) ->
|
||||||
|
false;
|
||||||
|
to_bool(0) ->
|
||||||
|
false.
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(docker_deployer).
|
-module(docker_deployer).
|
||||||
-author("anlicheng").
|
-author("anlicheng").
|
||||||
|
-include("message_pb.hrl").
|
||||||
-dialyzer([{nowarn_function, normalize_image/1}]).
|
-dialyzer([{nowarn_function, normalize_image/1}]).
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
@ -22,9 +23,11 @@
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
%% @doc Spawns the server and registers the local name (unique)
|
%% @doc Spawns the server and registers the local name (unique)
|
||||||
-spec(start_monitor(TaskId :: integer(), ContainerDir :: string(), Config :: map()) -> {ok, {Pid :: pid(), MRef :: reference()}}).
|
-spec(start_monitor(TaskId :: integer(), ContainerDir :: string(), Params :: message_pb:'ContainerDeployParams'()) ->
|
||||||
start_monitor(TaskId, ContainerDir, Config) when is_integer(TaskId), is_list(ContainerDir), is_map(Config) ->
|
{ok, {Pid :: pid(), MRef :: reference()}}).
|
||||||
{ok, spawn_monitor(?MODULE, deploy, [TaskId, ContainerDir, Config])}.
|
start_monitor(TaskId, ContainerDir, Params)
|
||||||
|
when is_integer(TaskId), is_list(ContainerDir), is_record(Params, 'ContainerDeployParams') ->
|
||||||
|
{ok, spawn_monitor(?MODULE, deploy, [TaskId, ContainerDir, Params])}.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
@ -40,10 +43,12 @@ start_monitor(TaskId, ContainerDir, Config) when is_integer(TaskId), is_list(Con
|
|||||||
% "command": ["nginx", "-g", "daemon off;"],
|
% "command": ["nginx", "-g", "daemon off;"],
|
||||||
% "restart": "always"
|
% "restart": "always"
|
||||||
%}
|
%}
|
||||||
-spec deploy(TaskId :: integer(), ContainerDir :: string(), Config :: map()) -> no_return().
|
-spec deploy(TaskId :: integer(), ContainerDir :: string(), Params :: message_pb:'ContainerDeployParams'()) -> no_return().
|
||||||
deploy(TaskId, ContainerDir, Config) when is_integer(TaskId), is_list(ContainerDir), is_map(Config) ->
|
deploy(TaskId, ContainerDir, Params = #'ContainerDeployParams'{
|
||||||
|
container_name = ContainerName,
|
||||||
|
spec = #'ContainerSpec'{image = Image0}
|
||||||
|
}) when is_integer(TaskId), is_list(ContainerDir) ->
|
||||||
%% 尝试拉取镜像
|
%% 尝试拉取镜像
|
||||||
ContainerName = maps:get(<<"container_name">>, Config),
|
|
||||||
trace_log(TaskId, <<"info">>, <<"开始部署容器:"/utf8, ContainerName/binary>>),
|
trace_log(TaskId, <<"info">>, <<"开始部署容器:"/utf8, ContainerName/binary>>),
|
||||||
|
|
||||||
case docker_commands:check_container_exist(ContainerName) of
|
case docker_commands:check_container_exist(ContainerName) of
|
||||||
@ -51,7 +56,6 @@ deploy(TaskId, ContainerDir, Config) when is_integer(TaskId), is_list(ContainerD
|
|||||||
trace_log(TaskId, <<"info">>, <<"本地容器已经存在:"/utf8, ContainerName/binary>>),
|
trace_log(TaskId, <<"info">>, <<"本地容器已经存在:"/utf8, ContainerName/binary>>),
|
||||||
efka_remote_agent:close_task_event_stream(TaskId, ?TASK_FAIL);
|
efka_remote_agent:close_task_event_stream(TaskId, ?TASK_FAIL);
|
||||||
false ->
|
false ->
|
||||||
Image0 = maps:get(<<"image">>, Config),
|
|
||||||
Image = normalize_image(Image0),
|
Image = normalize_image(Image0),
|
||||||
|
|
||||||
trace_log(TaskId, <<"info">>, <<"使用镜像:"/utf8, Image/binary>>),
|
trace_log(TaskId, <<"info">>, <<"使用镜像:"/utf8, Image/binary>>),
|
||||||
@ -73,7 +77,7 @@ deploy(TaskId, ContainerDir, Config) when is_integer(TaskId), is_list(ContainerD
|
|||||||
case PullResult of
|
case PullResult of
|
||||||
ok ->
|
ok ->
|
||||||
trace_log(TaskId, <<"info">>, <<"开始创建容器: "/utf8, ContainerName/binary>>),
|
trace_log(TaskId, <<"info">>, <<"开始创建容器: "/utf8, ContainerName/binary>>),
|
||||||
case docker_commands:create_container(ContainerName, ContainerDir, Config) of
|
case docker_commands:create_container(ContainerDir, Params) of
|
||||||
{ok, ContainerId} ->
|
{ok, ContainerId} ->
|
||||||
%% 创建容器对应的配置文件
|
%% 创建容器对应的配置文件
|
||||||
ConfigFile = docker_helper:get_config_file(ContainerDir),
|
ConfigFile = docker_helper:get_config_file(ContainerDir),
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(docker_manager).
|
-module(docker_manager).
|
||||||
-author("anlicheng").
|
-author("anlicheng").
|
||||||
|
-include("message_pb.hrl").
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
|
|
||||||
@ -37,9 +38,9 @@
|
|||||||
get_containers() ->
|
get_containers() ->
|
||||||
gen_server:call(?SERVER, get_containers).
|
gen_server:call(?SERVER, get_containers).
|
||||||
|
|
||||||
-spec deploy(TaskId :: integer(), Config :: map()) -> ok | {error, Reason :: binary()}.
|
-spec deploy(TaskId :: integer(), Params :: message_pb:'ContainerDeployParams'()) -> ok | {error, Reason :: binary()}.
|
||||||
deploy(TaskId, Config) when is_integer(TaskId), is_map(Config) ->
|
deploy(TaskId, Params) when is_integer(TaskId), is_record(Params, 'ContainerDeployParams') ->
|
||||||
gen_server:call(?SERVER, {deploy, TaskId, Config}).
|
gen_server:call(?SERVER, {deploy, TaskId, Params}).
|
||||||
|
|
||||||
-spec config_container(ContainerName :: binary(), Config :: binary()) -> ok | {error, Reason :: binary()}.
|
-spec config_container(ContainerName :: binary(), Config :: binary()) -> ok | {error, Reason :: binary()}.
|
||||||
config_container(ContainerName, Config) when is_binary(ContainerName), is_binary(Config) ->
|
config_container(ContainerName, Config) when is_binary(ContainerName), is_binary(Config) ->
|
||||||
@ -104,12 +105,14 @@ init([]) ->
|
|||||||
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
{noreply, NewState :: #state{}, timeout() | hibernate} |
|
||||||
{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
|
{stop, Reason :: term(), Reply :: term(), NewState :: #state{}} |
|
||||||
{stop, Reason :: term(), NewState :: #state{}}).
|
{stop, Reason :: term(), NewState :: #state{}}).
|
||||||
handle_call({deploy, TaskId, Config = #{<<"container_name">> := ContainerName}}, _From, State = #state{root_dir = RootDir, task_map = TaskMap}) ->
|
handle_call({deploy, TaskId, Params = #'ContainerDeployParams'{
|
||||||
|
container_name = ContainerName,
|
||||||
|
container_dir = ContainerDir0
|
||||||
|
}}, _From, State = #state{root_dir = RootDir, task_map = TaskMap}) ->
|
||||||
%% 创建目录
|
%% 创建目录
|
||||||
ContainerDir0 = maps:get(<<"container_dir">>, Config, <<>>),
|
|
||||||
{ok, ContainerDir} = docker_helper:ensure_container_dir(RootDir, ContainerName, ContainerDir0),
|
{ok, ContainerDir} = docker_helper:ensure_container_dir(RootDir, ContainerName, ContainerDir0),
|
||||||
{ok, {TaskPid, _Ref}} = docker_deployer:start_monitor(TaskId, ContainerDir, Config),
|
{ok, {TaskPid, _Ref}} = docker_deployer:start_monitor(TaskId, ContainerDir, Params),
|
||||||
logger:debug("[docker_manager] start deploy task_id: ~p, config: ~p", [TaskId, Config]),
|
logger:debug("[docker_manager] start deploy task_id: ~p, params: ~p", [TaskId, Params]),
|
||||||
{reply, ok, State#state{task_map = maps:put(TaskPid, TaskId, TaskMap)}};
|
{reply, ok, State#state{task_map = maps:put(TaskPid, TaskId, TaskMap)}};
|
||||||
|
|
||||||
%% 处理容器关联的配置文件
|
%% 处理容器关联的配置文件
|
||||||
|
|||||||
@ -254,8 +254,7 @@ handle_event(info, {container_request, PacketId, #'ContainerRequest'{action = {d
|
|||||||
task_id = TaskId,
|
task_id = TaskId,
|
||||||
params = Params
|
params = Params
|
||||||
}}}}, ?STATE_ACTIVATED, State = #state{transport_pid = TransportPid}) ->
|
}}}}, ?STATE_ACTIVATED, State = #state{transport_pid = TransportPid}) ->
|
||||||
Config = container_deploy_config(Params),
|
case docker_manager:deploy(TaskId, Params) of
|
||||||
case docker_manager:deploy(TaskId, Config) of
|
|
||||||
ok ->
|
ok ->
|
||||||
Packet = message_pb:encode_msg(#'ResponseFrame'{
|
Packet = message_pb:encode_msg(#'ResponseFrame'{
|
||||||
packet_id = PacketId,
|
packet_id = PacketId,
|
||||||
@ -530,75 +529,6 @@ auth_packet() ->
|
|||||||
encode_rpc_payload(Payload) ->
|
encode_rpc_payload(Payload) ->
|
||||||
jiffy:encode(Payload, [force_utf8]).
|
jiffy:encode(Payload, [force_utf8]).
|
||||||
|
|
||||||
-spec container_deploy_config(message_pb:'ContainerDeployParams'()) -> map().
|
|
||||||
container_deploy_config(#'ContainerDeployParams'{
|
|
||||||
container_name = ContainerName,
|
|
||||||
container_dir = ContainerDir,
|
|
||||||
spec = #'ContainerSpec'{
|
|
||||||
image = Image,
|
|
||||||
command = Command,
|
|
||||||
entrypoint = Entrypoint,
|
|
||||||
env = Env,
|
|
||||||
labels = Labels,
|
|
||||||
volumes = Volumes,
|
|
||||||
user = User,
|
|
||||||
working_dir = WorkingDir,
|
|
||||||
hostname = Hostname,
|
|
||||||
expose = Expose,
|
|
||||||
networks = Networks,
|
|
||||||
network_mode = NetworkMode,
|
|
||||||
healthcheck = Healthcheck,
|
|
||||||
restart = Restart,
|
|
||||||
privileged = Privileged,
|
|
||||||
cap_add = CapAdd,
|
|
||||||
cap_drop = CapDrop,
|
|
||||||
devices = Devices,
|
|
||||||
resources = Resources,
|
|
||||||
ulimits = Ulimits,
|
|
||||||
tmpfs = Tmpfs,
|
|
||||||
sysctls = Sysctls,
|
|
||||||
extra_hosts = ExtraHosts
|
|
||||||
}
|
|
||||||
}) ->
|
|
||||||
BaseConfig = #{
|
|
||||||
<<"container_name">> => to_binary(ContainerName),
|
|
||||||
<<"container_dir">> => to_binary(ContainerDir),
|
|
||||||
<<"image">> => to_binary(Image),
|
|
||||||
<<"command">> => [to_binary(Item) || Item <- Command],
|
|
||||||
<<"entrypoint">> => [to_binary(Item) || Item <- Entrypoint],
|
|
||||||
<<"envs">> => [to_binary(Item) || Item <- Env],
|
|
||||||
<<"labels">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Labels]),
|
|
||||||
<<"volumes">> => [volume_bind(Volume) || Volume <- Volumes],
|
|
||||||
<<"user">> => to_binary(User),
|
|
||||||
<<"working_dir">> => to_binary(WorkingDir),
|
|
||||||
<<"hostname">> => to_binary(Hostname),
|
|
||||||
<<"expose">> => [port_expose(Port) || Port <- Expose],
|
|
||||||
<<"networks">> => [to_binary(Network) || Network <- Networks],
|
|
||||||
<<"network_mode">> => to_binary(NetworkMode),
|
|
||||||
<<"restart">> => restart_policy(Restart),
|
|
||||||
<<"privileged">> => to_bool(Privileged),
|
|
||||||
<<"cap_add">> => [to_binary(Item) || Item <- CapAdd],
|
|
||||||
<<"cap_drop">> => [to_binary(Item) || Item <- CapDrop],
|
|
||||||
<<"devices">> => [device_mapping(Device) || Device <- Devices],
|
|
||||||
<<"ulimits">> => maps:from_list([{to_binary(Name), ulimit_spec(Ulimit)} || Ulimit = #'Ulimit'{name = Name} <- Ulimits]),
|
|
||||||
<<"tmpfs">> => [tmpfs_mount(Mount) || Mount <- Tmpfs],
|
|
||||||
<<"sysctls">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Sysctls]),
|
|
||||||
<<"extra_hosts">> => [to_binary(Host) || Host <- ExtraHosts]
|
|
||||||
},
|
|
||||||
HealthcheckConfig = case Healthcheck of
|
|
||||||
undefined ->
|
|
||||||
#{};
|
|
||||||
_ ->
|
|
||||||
#{<<"healthcheck">> => healthcheck_config(Healthcheck)}
|
|
||||||
end,
|
|
||||||
ResourceConfig = case Resources of
|
|
||||||
undefined ->
|
|
||||||
#{};
|
|
||||||
_ ->
|
|
||||||
resource_limits_config(Resources)
|
|
||||||
end,
|
|
||||||
maps:merge(BaseConfig, maps:merge(HealthcheckConfig, ResourceConfig)).
|
|
||||||
|
|
||||||
container_target(#'ContainerRef'{name = Name, id = Id}) ->
|
container_target(#'ContainerRef'{name = Name, id = Id}) ->
|
||||||
NameBin = to_binary(Name),
|
NameBin = to_binary(Name),
|
||||||
IdBin = to_binary(Id),
|
IdBin = to_binary(Id),
|
||||||
@ -610,102 +540,6 @@ container_target(#'ContainerRef'{name = Name, id = Id}) ->
|
|||||||
NameBin
|
NameBin
|
||||||
end.
|
end.
|
||||||
|
|
||||||
healthcheck_config(#'Healthcheck'{test = Test, interval_ns = IntervalNs, timeout_ns = TimeoutNs, retries = Retries}) ->
|
|
||||||
#{
|
|
||||||
<<"test">> => [to_binary(Item) || Item <- Test],
|
|
||||||
<<"interval">> => integer_to_binary(IntervalNs),
|
|
||||||
<<"timeout">> => integer_to_binary(TimeoutNs),
|
|
||||||
<<"retries">> => Retries
|
|
||||||
}.
|
|
||||||
|
|
||||||
resource_limits_config(#'ResourceLimits'{
|
|
||||||
memory_bytes = MemoryBytes,
|
|
||||||
memory_reservation_bytes = ReservationBytes,
|
|
||||||
nano_cpus = NanoCpus,
|
|
||||||
cpu_shares = CpuShares
|
|
||||||
}) ->
|
|
||||||
Config0 = #{},
|
|
||||||
Config1 = case MemoryBytes of
|
|
||||||
0 ->
|
|
||||||
Config0;
|
|
||||||
_ ->
|
|
||||||
Config0#{<<"mem_limit">> => integer_to_binary(MemoryBytes)}
|
|
||||||
end,
|
|
||||||
Config2 = case ReservationBytes of
|
|
||||||
0 ->
|
|
||||||
Config1;
|
|
||||||
_ ->
|
|
||||||
Config1#{<<"mem_reservation">> => integer_to_binary(ReservationBytes)}
|
|
||||||
end,
|
|
||||||
Config3 = case NanoCpus of
|
|
||||||
0 ->
|
|
||||||
Config2;
|
|
||||||
_ ->
|
|
||||||
Config2#{<<"cpus">> => nano_cpus_to_cpus(NanoCpus)}
|
|
||||||
end,
|
|
||||||
case CpuShares of
|
|
||||||
0 ->
|
|
||||||
Config3;
|
|
||||||
_ ->
|
|
||||||
Config3#{<<"cpu_shares">> => CpuShares}
|
|
||||||
end.
|
|
||||||
|
|
||||||
restart_policy(#'RestartPolicy'{name = Name, maximum_retry_count = 0}) ->
|
|
||||||
to_binary(Name);
|
|
||||||
restart_policy(#'RestartPolicy'{name = Name, maximum_retry_count = RetryCount}) ->
|
|
||||||
NameBin = to_binary(Name),
|
|
||||||
RetryCountBin = integer_to_binary(RetryCount),
|
|
||||||
<<NameBin/binary, ":", RetryCountBin/binary>>.
|
|
||||||
|
|
||||||
volume_bind(#'VolumeBind'{host_path = HostPath, container_path = ContainerPath, read_only = true}) ->
|
|
||||||
HostPathBin = to_binary(HostPath),
|
|
||||||
ContainerPathBin = to_binary(ContainerPath),
|
|
||||||
<<HostPathBin/binary, ":", ContainerPathBin/binary, ":ro">>;
|
|
||||||
volume_bind(#'VolumeBind'{host_path = HostPath, container_path = ContainerPath, read_only = ReadOnly}) ->
|
|
||||||
false = to_bool(ReadOnly),
|
|
||||||
HostPathBin = to_binary(HostPath),
|
|
||||||
ContainerPathBin = to_binary(ContainerPath),
|
|
||||||
<<HostPathBin/binary, ":", ContainerPathBin/binary>>.
|
|
||||||
|
|
||||||
port_expose(#'PortExpose'{container_port = ContainerPort, protocol = Protocol}) ->
|
|
||||||
PortBin = integer_to_binary(ContainerPort),
|
|
||||||
ProtocolBin = to_binary(Protocol),
|
|
||||||
case ProtocolBin of
|
|
||||||
<<>> ->
|
|
||||||
PortBin;
|
|
||||||
<<"tcp">> ->
|
|
||||||
PortBin;
|
|
||||||
_ ->
|
|
||||||
<<PortBin/binary, "/", ProtocolBin/binary>>
|
|
||||||
end.
|
|
||||||
|
|
||||||
device_mapping(#'DeviceMapping'{host_path = HostPath, container_path = ContainerPath, cgroup_permissions = <<"rwm">>}) ->
|
|
||||||
HostPathBin = to_binary(HostPath),
|
|
||||||
ContainerPathBin = to_binary(ContainerPath),
|
|
||||||
<<HostPathBin/binary, ":", ContainerPathBin/binary>>;
|
|
||||||
device_mapping(#'DeviceMapping'{host_path = HostPath, container_path = ContainerPath, cgroup_permissions = Permissions}) ->
|
|
||||||
HostPathBin = to_binary(HostPath),
|
|
||||||
ContainerPathBin = to_binary(ContainerPath),
|
|
||||||
PermissionsBin = to_binary(Permissions),
|
|
||||||
<<HostPathBin/binary, ":", ContainerPathBin/binary, ":", PermissionsBin/binary>>.
|
|
||||||
|
|
||||||
ulimit_spec(#'Ulimit'{soft = Soft, hard = Hard}) ->
|
|
||||||
SoftBin = integer_to_binary(Soft),
|
|
||||||
HardBin = integer_to_binary(Hard),
|
|
||||||
<<SoftBin/binary, ":", HardBin/binary>>.
|
|
||||||
|
|
||||||
tmpfs_mount(#'TmpfsMount'{path = Path, options = <<>>}) ->
|
|
||||||
to_binary(Path);
|
|
||||||
tmpfs_mount(#'TmpfsMount'{path = Path, options = Options}) ->
|
|
||||||
PathBin = to_binary(Path),
|
|
||||||
OptionsBin = to_binary(Options),
|
|
||||||
<<PathBin/binary, ":", OptionsBin/binary>>.
|
|
||||||
|
|
||||||
nano_cpus_to_cpus(NanoCpus) when NanoCpus rem 1000000000 =:= 0 ->
|
|
||||||
NanoCpus div 1000000000;
|
|
||||||
nano_cpus_to_cpus(NanoCpus) ->
|
|
||||||
NanoCpus / 1000000000.
|
|
||||||
|
|
||||||
to_binary(Value) when is_binary(Value) ->
|
to_binary(Value) when is_binary(Value) ->
|
||||||
Value;
|
Value;
|
||||||
to_binary(Value) when is_list(Value) ->
|
to_binary(Value) when is_list(Value) ->
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(docker_commands_tests).
|
-module(docker_commands_tests).
|
||||||
-author("anlicheng").
|
-author("anlicheng").
|
||||||
|
-include("message_pb.hrl").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([test_pull/0, test_commands/0, test_create_container/0]).
|
-export([test_pull/0, test_commands/0, test_create_container/0]).
|
||||||
@ -24,81 +25,78 @@ test_commands() ->
|
|||||||
logger:debug("start res: ~p", [StartRes]).
|
logger:debug("start res: ~p", [StartRes]).
|
||||||
|
|
||||||
test_create_container() ->
|
test_create_container() ->
|
||||||
M = #{
|
Params = #'ContainerDeployParams'{
|
||||||
<<"image">> => <<"docker.1ms.run/library/nginx:latest">>,
|
container_name = <<"my_nginx_new1">>,
|
||||||
<<"container_name">> => <<"my_nginx_new1">>,
|
spec = #'ContainerSpec'{
|
||||||
<<"command">> => [
|
image = <<"docker.1ms.run/library/nginx:latest">>,
|
||||||
|
command = [
|
||||||
<<"nginx">>,
|
<<"nginx">>,
|
||||||
<<"-g">>,
|
<<"-g">>,
|
||||||
<<"daemon off;">>
|
<<"daemon off;">>
|
||||||
],
|
],
|
||||||
<<"entrypoint">> => [
|
entrypoint = [
|
||||||
<<"/docker-entrypoint.sh">>
|
<<"/docker-entrypoint.sh">>
|
||||||
],
|
],
|
||||||
<<"envs">> => [
|
env = [
|
||||||
<<"ENV1=val1">>,
|
<<"ENV1=val1">>,
|
||||||
<<"ENV2=val2">>
|
<<"ENV2=val2">>
|
||||||
],
|
],
|
||||||
<<"env_file">> => [
|
expose = [
|
||||||
<<"./env.list">>
|
#'PortExpose'{container_port = 80, protocol = <<"tcp">>},
|
||||||
|
#'PortExpose'{container_port = 443, protocol = <<"tcp">>}
|
||||||
],
|
],
|
||||||
<<"ports">> => [
|
volumes = [
|
||||||
<<"8080:80">>,
|
#'VolumeBind'{host_path = <<"/host/data">>, container_path = <<"/data">>},
|
||||||
<<"443:443">>
|
#'VolumeBind'{host_path = <<"/host/log">>, container_path = <<"/var/log">>}
|
||||||
],
|
],
|
||||||
<<"expose">> => [
|
networks = [
|
||||||
<<"80">>,
|
<<"mynet">>
|
||||||
<<"443">>
|
|
||||||
],
|
],
|
||||||
<<"volumes">> => [
|
labels = [
|
||||||
<<"/host/data:/data">>,
|
{<<"role">>, <<"web">>},
|
||||||
<<"/host/log:/var/log">>
|
{<<"env">>, <<"prod">>}
|
||||||
],
|
],
|
||||||
<<"networks">> => [
|
restart = #'RestartPolicy'{name = <<"always">>},
|
||||||
<<"mynet">>
|
user = <<"www-data">>,
|
||||||
],
|
working_dir = <<"/app">>,
|
||||||
<<"labels">> => #{
|
hostname = <<"myhost">>,
|
||||||
<<"role">> => <<"web">>,
|
privileged = true,
|
||||||
<<"env">> => <<"prod">>
|
cap_add = [
|
||||||
},
|
<<"NET_ADMIN">>
|
||||||
<<"restart">> => <<"always">>,
|
],
|
||||||
<<"user">> => <<"www-data">>,
|
cap_drop = [
|
||||||
<<"working_dir">> => <<"/app">>,
|
<<"MKNOD">>
|
||||||
<<"hostname">> => <<"myhost">>,
|
],
|
||||||
<<"privileged">> => true,
|
devices = [
|
||||||
<<"cap_add">> => [
|
#'DeviceMapping'{host_path = <<"/dev/snd">>, container_path = <<"/dev/snd">>}
|
||||||
<<"NET_ADMIN">>
|
],
|
||||||
],
|
resources = #'ResourceLimits'{
|
||||||
<<"cap_drop">> => [
|
memory_bytes = 512 * 1024 * 1024,
|
||||||
<<"MKNOD">>
|
memory_reservation_bytes = 256 * 1024 * 1024,
|
||||||
],
|
cpu_shares = 512,
|
||||||
<<"devices">> => [
|
nano_cpus = 1500000000
|
||||||
<<"/dev/snd:/dev/snd">>
|
},
|
||||||
],
|
ulimits = [
|
||||||
<<"mem_limit">> => <<"512m">>,
|
#'Ulimit'{name = <<"nofile">>, soft = 1024, hard = 2048}
|
||||||
<<"mem_reservation">> => <<"256m">>,
|
],
|
||||||
<<"cpu_shares">> => 512,
|
sysctls = [
|
||||||
<<"cpus">> => 1.5,
|
{<<"net.ipv4.ip_forward">>, <<"1">>}
|
||||||
<<"ulimits">> => #{
|
],
|
||||||
<<"nofile">> => <<"1024:2048">>
|
tmpfs = [
|
||||||
},
|
#'TmpfsMount'{path = <<"/tmp">>}
|
||||||
<<"sysctls">> => #{
|
],
|
||||||
<<"net.ipv4.ip_forward">> => <<"1">>
|
extra_hosts = [
|
||||||
},
|
<<"host1:192.168.0.1">>
|
||||||
<<"tmpfs">> => [
|
],
|
||||||
<<"/tmp">>
|
healthcheck = #'Healthcheck'{
|
||||||
],
|
test = [
|
||||||
<<"extra_hosts">> => [
|
|
||||||
<<"host1:192.168.0.1">>
|
|
||||||
],
|
|
||||||
<<"healthcheck">> => #{
|
|
||||||
<<"test">> => [
|
|
||||||
<<"CMD-SHELL">>,
|
<<"CMD-SHELL">>,
|
||||||
<<"curl -f http://localhost || exit 1">>
|
<<"curl -f http://localhost || exit 1">>
|
||||||
],
|
],
|
||||||
<<"interval">> => <<"30s">>,
|
interval_ns = 30000000000,
|
||||||
<<"timeout">> => <<"10s">>,
|
timeout_ns = 10000000000,
|
||||||
<<"retries">> => 3
|
retries = 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
docker_commands:create_container(<<"my_nginx_xx3">>, "/usr/local/code/efka/", M).
|
docker_commands:create_container("/usr/local/code/efka/", Params).
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user