简化docker容器的创建逻辑

This commit is contained in:
anlicheng 2026-04-21 11:21:35 +08:00
parent dae690b20e
commit 8a108ec34d
6 changed files with 1590 additions and 1523 deletions

View File

@ -121,51 +121,74 @@
-record('ContainerDeployParams', -record('ContainerDeployParams',
{container_name = <<>> :: unicode:chardata() | undefined, % = 1, optional {container_name = <<>> :: unicode:chardata() | undefined, % = 1, optional
container_dir = <<>> :: unicode:chardata() | undefined, % = 2, optional container_dir = <<>> :: unicode:chardata() | undefined, % = 2, optional
spec = undefined :: message_pb:'ContainerSpec'() | undefined % = 3, optional create = undefined :: message_pb:'DockerCreateOptions'() | undefined % = 3, optional
}). }).
-endif. -endif.
-ifndef('CONTAINERSPEC_PB_H'). -ifndef('DOCKERCREATEOPTIONS_PB_H').
-define('CONTAINERSPEC_PB_H', true). -define('DOCKERCREATEOPTIONS_PB_H', true).
-record('ContainerSpec', -record('DockerCreateOptions',
{config = undefined :: message_pb:'DockerContainerConfig'() | undefined, % = 1, optional
host_config = undefined :: message_pb:'DockerHostConfig'() | undefined, % = 2, optional
networking_config = undefined :: message_pb:'DockerNetworkingConfig'() | undefined % = 3, optional
}).
-endif.
-ifndef('DOCKERCONTAINERCONFIG_PB_H').
-define('DOCKERCONTAINERCONFIG_PB_H', true).
-record('DockerContainerConfig',
{image = <<>> :: unicode:chardata() | undefined, % = 1, optional {image = <<>> :: unicode:chardata() | undefined, % = 1, optional
command = [] :: [unicode:chardata()] | undefined, % = 2, repeated cmd = [] :: [unicode:chardata()] | undefined, % = 2, repeated
entrypoint = [] :: [unicode:chardata()] | undefined, % = 3, repeated entrypoint = [] :: [unicode:chardata()] | undefined, % = 3, repeated
env = [] :: [unicode:chardata()] | undefined, % = 4, repeated env = [] :: [unicode:chardata()] | undefined, % = 4, repeated
labels = [] :: [{unicode:chardata(), unicode:chardata()}] | undefined, % = 5 labels = [] :: [{unicode:chardata(), unicode:chardata()}] | undefined, % = 5
volumes = [] :: [message_pb:'VolumeBind'()] | undefined, % = 6, repeated volumes = [] :: [unicode:chardata()] | undefined, % = 6, repeated
user = <<>> :: unicode:chardata() | undefined, % = 7, optional user = <<>> :: unicode:chardata() | undefined, % = 7, optional
working_dir = <<>> :: unicode:chardata() | undefined, % = 8, optional working_dir = <<>> :: unicode:chardata() | undefined, % = 8, optional
hostname = <<>> :: unicode:chardata() | undefined, % = 9, optional hostname = <<>> :: unicode:chardata() | undefined, % = 9, optional
expose = [] :: [message_pb:'PortExpose'()] | undefined, % = 10, repeated exposed_ports = [] :: [message_pb:'DockerExposedPort'()] | undefined, % = 10, repeated
networks = [] :: [unicode:chardata()] | undefined, % = 11, repeated healthcheck = undefined :: message_pb:'Healthcheck'() | undefined % = 11, optional
network_mode = <<>> :: unicode:chardata() | undefined, % = 12, optional
healthcheck = undefined :: message_pb:'Healthcheck'() | undefined, % = 13, optional
restart = undefined :: message_pb:'RestartPolicy'() | undefined, % = 14, optional
privileged = false :: boolean() | 0 | 1 | undefined, % = 15, optional
cap_add = [] :: [unicode:chardata()] | undefined, % = 16, repeated
cap_drop = [] :: [unicode:chardata()] | undefined, % = 17, repeated
devices = [] :: [message_pb:'DeviceMapping'()] | undefined, % = 18, repeated
resources = undefined :: message_pb:'ResourceLimits'() | undefined, % = 19, optional
ulimits = [] :: [message_pb:'Ulimit'()] | undefined, % = 20, repeated
tmpfs = [] :: [message_pb:'TmpfsMount'()] | undefined, % = 21, repeated
sysctls = [] :: [{unicode:chardata(), unicode:chardata()}] | undefined, % = 22
extra_hosts = [] :: [unicode:chardata()] | undefined % = 23, repeated
}). }).
-endif. -endif.
-ifndef('VOLUMEBIND_PB_H'). -ifndef('DOCKERHOSTCONFIG_PB_H').
-define('VOLUMEBIND_PB_H', true). -define('DOCKERHOSTCONFIG_PB_H', true).
-record('VolumeBind', -record('DockerHostConfig',
{host_path = <<>> :: unicode:chardata() | undefined, % = 1, optional {binds = [] :: [unicode:chardata()] | undefined, % = 1, repeated
container_path = <<>> :: unicode:chardata() | undefined, % = 2, optional network_mode = <<>> :: unicode:chardata() | undefined, % = 2, optional
read_only = false :: boolean() | 0 | 1 | undefined % = 3, optional restart_policy = undefined :: message_pb:'RestartPolicy'() | undefined, % = 3, optional
privileged = false :: boolean() | 0 | 1 | undefined, % = 4, optional
cap_add = [] :: [unicode:chardata()] | undefined, % = 5, repeated
cap_drop = [] :: [unicode:chardata()] | undefined, % = 6, repeated
devices = [] :: [message_pb:'DeviceMapping'()] | undefined, % = 7, repeated
memory = 0 :: non_neg_integer() | undefined, % = 8, optional, 64 bits
memory_reservation = 0 :: non_neg_integer() | undefined, % = 9, optional, 64 bits
nano_cpus = 0 :: non_neg_integer() | undefined, % = 10, optional, 64 bits
cpu_shares = 0 :: non_neg_integer() | undefined, % = 11, optional, 64 bits
ulimits = [] :: [message_pb:'Ulimit'()] | undefined, % = 12, repeated
tmpfs = [] :: [{unicode:chardata(), unicode:chardata()}] | undefined, % = 13
sysctls = [] :: [{unicode:chardata(), unicode:chardata()}] | undefined, % = 14
extra_hosts = [] :: [unicode:chardata()] | undefined % = 15, repeated
}). }).
-endif. -endif.
-ifndef('PORTEXPOSE_PB_H'). -ifndef('DOCKERNETWORKINGCONFIG_PB_H').
-define('PORTEXPOSE_PB_H', true). -define('DOCKERNETWORKINGCONFIG_PB_H', true).
-record('PortExpose', -record('DockerNetworkingConfig',
{endpoints = [] :: [message_pb:'DockerNetworkEndpoint'()] | undefined % = 1, repeated
}).
-endif.
-ifndef('DOCKERNETWORKENDPOINT_PB_H').
-define('DOCKERNETWORKENDPOINT_PB_H', true).
-record('DockerNetworkEndpoint',
{name = <<>> :: unicode:chardata() | undefined % = 1, optional
}).
-endif.
-ifndef('DOCKEREXPOSEDPORT_PB_H').
-define('DOCKEREXPOSEDPORT_PB_H', true).
-record('DockerExposedPort',
{container_port = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits {container_port = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits
protocol = <<>> :: unicode:chardata() | undefined % = 2, optional protocol = <<>> :: unicode:chardata() | undefined % = 2, optional
}). }).
@ -198,16 +221,6 @@
}). }).
-endif. -endif.
-ifndef('RESOURCELIMITS_PB_H').
-define('RESOURCELIMITS_PB_H', true).
-record('ResourceLimits',
{memory_bytes = 0 :: non_neg_integer() | undefined, % = 1, optional, 64 bits
memory_reservation_bytes = 0 :: non_neg_integer() | undefined, % = 2, optional, 64 bits
nano_cpus = 0 :: non_neg_integer() | undefined, % = 3, optional, 64 bits
cpu_shares = 0 :: non_neg_integer() | undefined % = 4, optional, 64 bits
}).
-endif.
-ifndef('ULIMIT_PB_H'). -ifndef('ULIMIT_PB_H').
-define('ULIMIT_PB_H', true). -define('ULIMIT_PB_H', true).
-record('Ulimit', -record('Ulimit',
@ -217,14 +230,6 @@
}). }).
-endif. -endif.
-ifndef('TMPFSMOUNT_PB_H').
-define('TMPFSMOUNT_PB_H', true).
-record('TmpfsMount',
{path = <<>> :: unicode:chardata() | undefined, % = 1, optional
options = <<>> :: unicode:chardata() | undefined % = 2, optional
}).
-endif.
-ifndef('AUTHREQUEST_PB_H'). -ifndef('AUTHREQUEST_PB_H').
-define('AUTHREQUEST_PB_H', true). -define('AUTHREQUEST_PB_H', true).
-record('AuthRequest', -record('AuthRequest',

View File

@ -91,48 +91,57 @@ message ContainerRequest {
message ContainerDeployParams { message ContainerDeployParams {
string container_name = 1; string container_name = 1;
string container_dir = 2; string container_dir = 2;
ContainerSpec spec = 3; DockerCreateOptions create = 3;
} }
message ContainerSpec { message DockerCreateOptions {
DockerContainerConfig config = 1;
DockerHostConfig host_config = 2;
DockerNetworkingConfig networking_config = 3;
}
message DockerContainerConfig {
string image = 1; string image = 1;
repeated string command = 2; repeated string cmd = 2;
repeated string entrypoint = 3; repeated string entrypoint = 3;
repeated string env = 4; repeated string env = 4;
map<string, string> labels = 5; map<string, string> labels = 5;
repeated string volumes = 6;
repeated VolumeBind volumes = 6;
string user = 7; string user = 7;
string working_dir = 8; string working_dir = 8;
string hostname = 9; string hostname = 9;
repeated DockerExposedPort exposed_ports = 10;
repeated PortExpose expose = 10; Healthcheck healthcheck = 11;
repeated string networks = 11;
string network_mode = 12;
Healthcheck healthcheck = 13;
RestartPolicy restart = 14;
bool privileged = 15;
repeated string cap_add = 16;
repeated string cap_drop = 17;
repeated DeviceMapping devices = 18;
ResourceLimits resources = 19;
repeated Ulimit ulimits = 20;
repeated TmpfsMount tmpfs = 21;
map<string, string> sysctls = 22;
repeated string extra_hosts = 23;
} }
message VolumeBind { message DockerHostConfig {
string host_path = 1; repeated string binds = 1;
string container_path = 2; string network_mode = 2;
bool read_only = 3; RestartPolicy restart_policy = 3;
bool privileged = 4;
repeated string cap_add = 5;
repeated string cap_drop = 6;
repeated DeviceMapping devices = 7;
uint64 memory = 8;
uint64 memory_reservation = 9;
uint64 nano_cpus = 10;
uint64 cpu_shares = 11;
repeated Ulimit ulimits = 12;
map<string, string> tmpfs = 13;
map<string, string> sysctls = 14;
repeated string extra_hosts = 15;
} }
message PortExpose { message DockerNetworkingConfig {
repeated DockerNetworkEndpoint endpoints = 1;
}
message DockerNetworkEndpoint {
string name = 1;
}
message DockerExposedPort {
uint32 container_port = 1; uint32 container_port = 1;
string protocol = 2; // tcp / udp string protocol = 2; // tcp / udp
} }
@ -155,24 +164,12 @@ message DeviceMapping {
string cgroup_permissions = 3; // rwm string cgroup_permissions = 3; // rwm
} }
message ResourceLimits {
uint64 memory_bytes = 1;
uint64 memory_reservation_bytes = 2;
uint64 nano_cpus = 3;
uint64 cpu_shares = 4;
}
message Ulimit { message Ulimit {
string name = 1; string name = 1;
uint64 soft = 2; uint64 soft = 2;
uint64 hard = 3; uint64 hard = 3;
} }
message TmpfsMount {
string path = 1;
string options = 2;
}
message AuthRequest { message AuthRequest {
bytes uuid = 1; bytes uuid = 1;
bytes username = 2; bytes username = 2;
@ -201,4 +198,4 @@ message TaskEventStream {
int32 task_id = 1; int32 task_id = 1;
bytes type = 2; bytes type = 2;
bytes stream = 3; bytes stream = 3;
} }

View File

@ -36,19 +36,14 @@ check_image_exist(Image) when is_binary(Image) ->
{ok, ContainerId :: binary()} | {error, Reason :: any()}. {ok, ContainerId :: binary()} | {error, Reason :: any()}.
create_container(ContainerDir, #'ContainerDeployParams'{ create_container(ContainerDir, #'ContainerDeployParams'{
container_name = ContainerName, container_name = ContainerName,
spec = Spec0 = #'ContainerSpec'{volumes = Volumes0} create = Create0
}) when is_binary(ContainerName), is_list(ContainerDir) -> }) when is_binary(ContainerName), is_list(ContainerDir) ->
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'{ Create = patch_create_options(ContainerName, ConfigFile, Create0),
host_path = ConfigFile, Options = build_options(Create),
container_path = <<"/usr/local/etc/service.conf">>,
read_only = false
},
Spec = Spec0#'ContainerSpec'{volumes = [ConfigVolume | Volumes0]},
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])),
@ -239,45 +234,100 @@ inspect_container(ContainerId) when is_binary(ContainerId) ->
%%% helper methods %%% helper methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
patch_create_options(ContainerName, ConfigFile, undefined) ->
patch_create_options(ContainerName, ConfigFile, #'DockerCreateOptions'{});
patch_create_options(ContainerName, ConfigFile, Create = #'DockerCreateOptions'{
config = Config0,
host_config = HostConfig0
}) when is_binary(ContainerName), is_binary(ConfigFile) ->
Config = patch_container_config(ContainerName, ensure_container_config(Config0)),
HostConfig = patch_host_config(ConfigFile, ensure_host_config(HostConfig0)),
Create#'DockerCreateOptions'{config = Config, host_config = HostConfig}.
patch_container_config(ContainerName, Config = #'DockerContainerConfig'{env = Env0, volumes = Volumes0})
when is_binary(ContainerName) ->
ConfigVolume = <<"/usr/local/etc/service.conf">>,
Envs0 = [<<"CONTAINER_NAME=", ContainerName/binary>>],
Envs = add_unique_front(Envs0, [to_binary(EnvItem) || EnvItem <- Env0]),
Volumes = add_unique_front([ConfigVolume], [to_binary(Volume) || Volume <- Volumes0]),
Config#'DockerContainerConfig'{env = Envs, volumes = Volumes}.
patch_host_config(ConfigFile, HostConfig = #'DockerHostConfig'{binds = Binds0}) when is_binary(ConfigFile) ->
ConfigBind = <<ConfigFile/binary, ":/usr/local/etc/service.conf">>,
Binds = add_unique_front([ConfigBind], [to_binary(Bind) || Bind <- Binds0]),
HostConfig#'DockerHostConfig'{binds = Binds}.
ensure_container_config(undefined) ->
#'DockerContainerConfig'{};
ensure_container_config(Config = #'DockerContainerConfig'{}) ->
Config.
ensure_host_config(undefined) ->
#'DockerHostConfig'{};
ensure_host_config(HostConfig = #'DockerHostConfig'{}) ->
HostConfig.
%% JSON Map %% JSON Map
build_options(ContainerName, Spec = #'ContainerSpec'{ build_options(#'DockerCreateOptions'{
image = Image, config = #'DockerContainerConfig'{
command = Command, image = Image,
entrypoint = Entrypoint, cmd = Cmd,
env = Env, entrypoint = Entrypoint,
labels = Labels, env = Env,
user = User, labels = Labels,
working_dir = WorkingDir, volumes = Volumes,
hostname = Hostname user = User,
}) when is_binary(ContainerName) -> working_dir = WorkingDir,
%% hostname = Hostname,
Envs0 = [to_binary(EnvItem) || EnvItem <- Env], exposed_ports = ExposedPorts,
Envs = [<<"CONTAINER_NAME=", ContainerName/binary>>|Envs0], healthcheck = Healthcheck
},
host_config = #'DockerHostConfig'{
binds = Binds,
network_mode = NetworkMode,
restart_policy = RestartPolicy,
privileged = Privileged,
cap_add = CapAdd,
cap_drop = CapDrop,
devices = Devices,
memory = Memory,
memory_reservation = MemoryReservation,
nano_cpus = NanoCpus,
cpu_shares = CpuShares,
ulimits = Ulimits,
tmpfs = Tmpfs,
sysctls = Sysctls,
extra_hosts = ExtraHosts
},
networking_config = #'DockerNetworkingConfig'{
endpoints = Endpoints
}
}) ->
#{ #{
<<"Image">> => to_binary(Image), <<"Image">> => to_binary(Image),
<<"Cmd">> => [to_binary(CommandItem) || CommandItem <- Command], <<"Cmd">> => [to_binary(CommandItem) || CommandItem <- Cmd],
<<"Entrypoint">> => [to_binary(EntrypointItem) || EntrypointItem <- Entrypoint], <<"Entrypoint">> => [to_binary(EntrypointItem) || EntrypointItem <- Entrypoint],
<<"Env">> => Envs, <<"Env">> => [to_binary(EnvItem) || EnvItem <- Env],
<<"Labels">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Labels]), <<"Labels">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Labels]),
<<"Volumes">> => build_volumes(Spec), <<"Volumes">> => build_volumes(Volumes),
<<"User">> => to_binary(User), <<"User">> => to_binary(User),
<<"WorkingDir">> => to_binary(WorkingDir), <<"WorkingDir">> => to_binary(WorkingDir),
<<"Hostname">> => to_binary(Hostname), <<"Hostname">> => to_binary(Hostname),
<<"ExposedPorts">> => build_expose(Spec), <<"ExposedPorts">> => build_expose(ExposedPorts),
<<"NetworkingConfig">> => build_networks(Spec), <<"NetworkingConfig">> => build_networking_config(Endpoints),
<<"Healthcheck">> => build_healthcheck(Spec), <<"Healthcheck">> => build_healthcheck(Healthcheck),
<<"HostConfig">> => fold_merge([ <<"HostConfig">> => fold_merge([
build_network_mode(Spec), build_binds(Binds),
build_binds(Spec), build_network_mode(NetworkMode),
build_restart(Spec), build_restart(RestartPolicy),
build_privileged(Spec), build_privileged(Privileged),
build_cap_add_drop(Spec), build_cap_add_drop(CapAdd, CapDrop),
build_devices(Spec), build_devices(Devices),
build_resources(Spec), build_resources(Memory, MemoryReservation, NanoCpus, CpuShares),
build_ulimits(Spec), build_ulimits(Ulimits),
build_tmpfs(Spec), build_tmpfs(Tmpfs),
build_sysctls(Spec), build_sysctls(Sysctls),
build_extra_hosts(Spec) build_extra_hosts(ExtraHosts)
]) ])
}. }.
@ -286,50 +336,50 @@ fold_merge(List) ->
lists:foldl(fun maps:merge/2, #{}, List). lists:foldl(fun maps:merge/2, #{}, List).
%% --- --- %% --- ---
build_expose(#'ContainerSpec'{expose = Ports}) -> build_expose(Ports) when is_list(Ports) ->
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(#'ContainerSpec'{volumes = Vols}) -> build_volumes(Vols) when is_list(Vols) ->
case Vols of case Vols of
[] -> [] ->
#{}; #{};
_ -> _ ->
maps:from_list([{to_binary(Cont), #{}} || #'VolumeBind'{container_path = Cont} <- Vols]) maps:from_list([{to_binary(Cont), #{}} || Cont <- Vols])
end. end.
build_binds(#'ContainerSpec'{volumes = Vols}) -> build_binds(Binds) when is_list(Binds) ->
case Vols of case Binds of
[] -> [] ->
#{}; #{};
_ -> _ ->
#{<<"Binds">> => [volume_bind(Vol) || Vol <- Vols]} #{<<"Binds">> => [to_binary(Bind) || Bind <- Binds]}
end. end.
build_networks(#'ContainerSpec'{networks = Nets}) -> build_networking_config(Endpoints) when is_list(Endpoints) ->
case Nets of case Endpoints of
[] -> #{}; [] -> #{};
_ -> _ ->
NetCfg = maps:from_list([{to_binary(N), #{}} || N <- Nets]), NetCfg = maps:from_list([{to_binary(Name), #{}} || #'DockerNetworkEndpoint'{name = Name} <- Endpoints]),
#{<<"EndpointsConfig">> => NetCfg} #{<<"EndpointsConfig">> => NetCfg}
end. end.
build_network_mode(#'ContainerSpec'{network_mode = <<>>}) -> build_network_mode(<<>>) ->
#{}; #{};
build_network_mode(#'ContainerSpec'{network_mode = NetworkMode}) -> build_network_mode(NetworkMode) ->
#{<<"NetworkMode">> => to_binary(NetworkMode)}. #{<<"NetworkMode">> => to_binary(NetworkMode)}.
build_healthcheck(#'ContainerSpec'{healthcheck = undefined}) -> build_healthcheck(undefined) ->
#{}; #{};
build_healthcheck(#'ContainerSpec'{healthcheck = #'Healthcheck'{ build_healthcheck(#'Healthcheck'{
test = Test, test = Test,
interval_ns = IntervalNs, interval_ns = IntervalNs,
timeout_ns = TimeoutNs, timeout_ns = TimeoutNs,
retries = Retries retries = Retries
}}) -> }) ->
#{ #{
<<"Test">> => [to_binary(Item) || Item <- Test], <<"Test">> => [to_binary(Item) || Item <- Test],
<<"Interval">> => IntervalNs, <<"Interval">> => IntervalNs,
@ -337,12 +387,12 @@ build_healthcheck(#'ContainerSpec'{healthcheck = #'Healthcheck'{
<<"Retries">> => Retries <<"Retries">> => Retries
}. }.
build_restart(#'ContainerSpec'{restart = undefined}) -> build_restart(undefined) ->
#{}; #{};
build_restart(#'ContainerSpec'{restart = #'RestartPolicy'{ build_restart(#'RestartPolicy'{
name = Name, name = Name,
maximum_retry_count = RetryCount maximum_retry_count = RetryCount
}}) -> }) ->
RestartPolicy = #{ RestartPolicy = #{
<<"Name">> => to_binary(Name) <<"Name">> => to_binary(Name)
}, },
@ -355,7 +405,7 @@ build_restart(#'ContainerSpec'{restart = #'RestartPolicy'{
}} }}
end. end.
build_privileged(#'ContainerSpec'{privileged = Privileged}) -> build_privileged(Privileged) ->
case to_bool(Privileged) of case to_bool(Privileged) of
true -> true ->
#{<<"Privileged">> => true}; #{<<"Privileged">> => true};
@ -363,7 +413,7 @@ build_privileged(#'ContainerSpec'{privileged = Privileged}) ->
#{} #{}
end. end.
build_cap_add_drop(#'ContainerSpec'{cap_add = Add, cap_drop = Drop}) -> build_cap_add_drop(Add, Drop) when is_list(Add), is_list(Drop) ->
case {Add, Drop} of case {Add, Drop} of
{[], []} -> {[], []} ->
#{}; #{};
@ -374,7 +424,7 @@ build_cap_add_drop(#'ContainerSpec'{cap_add = Add, cap_drop = Drop}) ->
} }
end. end.
build_devices(#'ContainerSpec'{devices = Devs}) -> build_devices(Devs) when is_list(Devs) ->
case Devs of case Devs of
[] -> [] ->
#{}; #{};
@ -391,14 +441,7 @@ build_devices(#'ContainerSpec'{devices = Devs}) ->
#{<<"Devices">> => DevObjs} #{<<"Devices">> => DevObjs}
end. end.
build_resources(#'ContainerSpec'{resources = undefined}) -> build_resources(MemoryBytes, ReservationBytes, NanoCpus, CpuShares) ->
#{};
build_resources(#'ContainerSpec'{resources = #'ResourceLimits'{
memory_bytes = MemoryBytes,
memory_reservation_bytes = ReservationBytes,
nano_cpus = NanoCpus,
cpu_shares = CpuShares
}}) ->
HostConfig0 = #{}, HostConfig0 = #{},
HostConfig1 = case MemoryBytes of HostConfig1 = case MemoryBytes of
0 -> 0 ->
@ -425,7 +468,7 @@ build_resources(#'ContainerSpec'{resources = #'ResourceLimits'{
HostConfig3#{<<"CpuShares">> => CpuShares} HostConfig3#{<<"CpuShares">> => CpuShares}
end. end.
build_ulimits(#'ContainerSpec'{ulimits = Ulimits}) -> build_ulimits(Ulimits) when is_list(Ulimits) ->
case Ulimits of case Ulimits of
[] -> [] ->
#{}; #{};
@ -437,7 +480,7 @@ build_ulimits(#'ContainerSpec'{ulimits = Ulimits}) ->
} || #'Ulimit'{name = Name, soft = Soft, hard = Hard} <- Ulimits]} } || #'Ulimit'{name = Name, soft = Soft, hard = Hard} <- Ulimits]}
end. end.
build_sysctls(#'ContainerSpec'{sysctls = Sysctls}) -> build_sysctls(Sysctls) when is_list(Sysctls) ->
case Sysctls of case Sysctls of
[] -> [] ->
#{}; #{};
@ -445,16 +488,15 @@ build_sysctls(#'ContainerSpec'{sysctls = Sysctls}) ->
#{<<"Sysctls">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Sysctls])} #{<<"Sysctls">> => maps:from_list([{to_binary(Key), to_binary(Value)} || {Key, Value} <- Sysctls])}
end. end.
build_tmpfs(#'ContainerSpec'{tmpfs = Tmpfs}) -> build_tmpfs(Tmpfs) when is_list(Tmpfs) ->
case Tmpfs of case Tmpfs of
[] -> [] ->
#{}; #{};
_ -> _ ->
#{<<"Tmpfs">> => maps:from_list([{to_binary(Path), to_binary(Options)} || #{<<"Tmpfs">> => maps:from_list([{to_binary(Path), to_binary(Options)} || {Path, Options} <- Tmpfs])}
#'TmpfsMount'{path = Path, options = Options} <- Tmpfs])}
end. end.
build_extra_hosts(#'ContainerSpec'{extra_hosts = Hosts}) -> build_extra_hosts(Hosts) when is_list(Hosts) ->
case Hosts of case Hosts of
[] -> [] ->
#{}; #{};
@ -467,7 +509,7 @@ 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(#'PortExpose'{container_port = Port, protocol = Protocol}) -> normalize_expose_port(#'DockerExposedPort'{container_port = Port, protocol = Protocol}) ->
PortBin = integer_to_binary(Port), PortBin = integer_to_binary(Port),
ProtocolBin = to_binary(Protocol), ProtocolBin = to_binary(Protocol),
case ProtocolBin of case ProtocolBin of
@ -484,15 +526,14 @@ device_permissions(<<>>) ->
device_permissions(Permissions) -> device_permissions(Permissions) ->
to_binary(Permissions). to_binary(Permissions).
volume_bind(#'VolumeBind'{host_path = HostPath, container_path = ContainerPath, read_only = ReadOnly}) -> add_unique_front([], List) ->
HostPathBin = to_binary(HostPath), List;
ContainerPathBin = to_binary(ContainerPath), add_unique_front([Item | Rest], List) ->
case to_bool(ReadOnly) of NList = case lists:member(Item, List) of
true -> true -> List;
<<HostPathBin/binary, ":", ContainerPathBin/binary, ":ro">>; false -> [Item | List]
false -> end,
<<HostPathBin/binary, ":", ContainerPathBin/binary>> add_unique_front(Rest, NList).
end.
build_stop_container_url(ContainerName, 0) -> build_stop_container_url(ContainerName, 0) ->
lists:flatten(io_lib:format("/containers/~s/stop", [binary_to_list(ContainerName)])); lists:flatten(io_lib:format("/containers/~s/stop", [binary_to_list(ContainerName)]));

View File

@ -45,7 +45,7 @@ start_monitor(TaskId, ContainerDir, Params)
-spec deploy(TaskId :: integer(), ContainerDir :: string(), Params :: message_pb:'ContainerDeployParams'()) -> no_return(). -spec deploy(TaskId :: integer(), ContainerDir :: string(), Params :: message_pb:'ContainerDeployParams'()) -> no_return().
deploy(TaskId, ContainerDir, Params = #'ContainerDeployParams'{ deploy(TaskId, ContainerDir, Params = #'ContainerDeployParams'{
container_name = ContainerName, container_name = ContainerName,
spec = #'ContainerSpec'{image = Image0} create = #'DockerCreateOptions'{config = #'DockerContainerConfig'{image = Image0}}
}) when is_integer(TaskId), is_list(ContainerDir) -> }) when is_integer(TaskId), is_list(ContainerDir) ->
report_task_event(TaskId, <<"info">>, <<"开始部署容器:"/utf8, ContainerName/binary>>), report_task_event(TaskId, <<"info">>, <<"开始部署容器:"/utf8, ContainerName/binary>>),
try try

File diff suppressed because it is too large Load Diff

View File

@ -27,75 +27,84 @@ test_commands() ->
test_create_container() -> test_create_container() ->
Params = #'ContainerDeployParams'{ Params = #'ContainerDeployParams'{
container_name = <<"my_nginx_new1">>, container_name = <<"my_nginx_new1">>,
spec = #'ContainerSpec'{ create = #'DockerCreateOptions'{
image = <<"docker.1ms.run/library/nginx:latest">>, config = #'DockerContainerConfig'{
command = [ image = <<"docker.1ms.run/library/nginx:latest">>,
<<"nginx">>, cmd = [
<<"-g">>, <<"nginx">>,
<<"daemon off;">> <<"-g">>,
], <<"daemon off;">>
entrypoint = [ ],
<<"/docker-entrypoint.sh">> entrypoint = [
], <<"/docker-entrypoint.sh">>
env = [ ],
<<"ENV1=val1">>, env = [
<<"ENV2=val2">> <<"ENV1=val1">>,
], <<"ENV2=val2">>
expose = [ ],
#'PortExpose'{container_port = 80, protocol = <<"tcp">>}, volumes = [
#'PortExpose'{container_port = 443, protocol = <<"tcp">>} <<"/data">>,
], <<"/var/log">>
volumes = [ ],
#'VolumeBind'{host_path = <<"/host/data">>, container_path = <<"/data">>}, labels = [
#'VolumeBind'{host_path = <<"/host/log">>, container_path = <<"/var/log">>} {<<"role">>, <<"web">>},
], {<<"env">>, <<"prod">>}
networks = [ ],
<<"mynet">> user = <<"www-data">>,
], working_dir = <<"/app">>,
labels = [ hostname = <<"myhost">>,
{<<"role">>, <<"web">>}, exposed_ports = [
{<<"env">>, <<"prod">>} #'DockerExposedPort'{container_port = 80, protocol = <<"tcp">>},
], #'DockerExposedPort'{container_port = 443, protocol = <<"tcp">>}
restart = #'RestartPolicy'{name = <<"always">>}, ],
user = <<"www-data">>, healthcheck = #'Healthcheck'{
working_dir = <<"/app">>, test = [
hostname = <<"myhost">>, <<"CMD-SHELL">>,
privileged = true, <<"curl -f http://localhost || exit 1">>
cap_add = [ ],
<<"NET_ADMIN">> interval_ns = 30000000000,
], timeout_ns = 10000000000,
cap_drop = [ retries = 3
<<"MKNOD">> }
],
devices = [
#'DeviceMapping'{host_path = <<"/dev/snd">>, container_path = <<"/dev/snd">>}
],
resources = #'ResourceLimits'{
memory_bytes = 512 * 1024 * 1024,
memory_reservation_bytes = 256 * 1024 * 1024,
cpu_shares = 512,
nano_cpus = 1500000000
}, },
ulimits = [ host_config = #'DockerHostConfig'{
#'Ulimit'{name = <<"nofile">>, soft = 1024, hard = 2048} binds = [
], <<"/host/data:/data">>,
sysctls = [ <<"/host/log:/var/log">>
{<<"net.ipv4.ip_forward">>, <<"1">>} ],
], network_mode = <<"bridge">>,
tmpfs = [ restart_policy = #'RestartPolicy'{name = <<"always">>},
#'TmpfsMount'{path = <<"/tmp">>} privileged = true,
], cap_add = [
extra_hosts = [ <<"NET_ADMIN">>
<<"host1:192.168.0.1">> ],
], cap_drop = [
healthcheck = #'Healthcheck'{ <<"MKNOD">>
test = [ ],
<<"CMD-SHELL">>, devices = [
<<"curl -f http://localhost || exit 1">> #'DeviceMapping'{host_path = <<"/dev/snd">>, container_path = <<"/dev/snd">>}
], ],
interval_ns = 30000000000, memory = 512 * 1024 * 1024,
timeout_ns = 10000000000, memory_reservation = 256 * 1024 * 1024,
retries = 3 cpu_shares = 512,
nano_cpus = 1500000000,
ulimits = [
#'Ulimit'{name = <<"nofile">>, soft = 1024, hard = 2048}
],
sysctls = [
{<<"net.ipv4.ip_forward">>, <<"1">>}
],
tmpfs = [
{<<"/tmp">>, <<>>}
],
extra_hosts = [
<<"host1:192.168.0.1">>
]
},
networking_config = #'DockerNetworkingConfig'{
endpoints = [
#'DockerNetworkEndpoint'{name = <<"mynet">>}
]
} }
} }
}, },