mirror of https://github.com/docker/cli.git
Add systctl support for services
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
a4a50de4b8
commit
f620349837
|
@ -60,6 +60,8 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
flags.SetAnnotation(flagHost, "version", []string{"1.25"})
|
flags.SetAnnotation(flagHost, "version", []string{"1.25"})
|
||||||
flags.BoolVar(&opts.init, flagInit, false, "Use an init inside each service container to forward signals and reap processes")
|
flags.BoolVar(&opts.init, flagInit, false, "Use an init inside each service container to forward signals and reap processes")
|
||||||
flags.SetAnnotation(flagInit, "version", []string{"1.37"})
|
flags.SetAnnotation(flagInit, "version", []string{"1.37"})
|
||||||
|
flags.Var(&opts.sysctls, flagSysCtl, "Sysctl options")
|
||||||
|
flags.SetAnnotation(flagSysCtl, "version", []string{"1.40"})
|
||||||
|
|
||||||
flags.Var(cliopts.NewListOptsRef(&opts.resources.resGenericResources, ValidateSingleGenericResource), "generic-resource", "User defined resources")
|
flags.Var(cliopts.NewListOptsRef(&opts.resources.resGenericResources, ValidateSingleGenericResource), "generic-resource", "User defined resources")
|
||||||
flags.SetAnnotation(flagHostAdd, "version", []string{"1.32"})
|
flags.SetAnnotation(flagHostAdd, "version", []string{"1.32"})
|
||||||
|
|
|
@ -96,6 +96,11 @@ ContainerSpec:
|
||||||
{{- if .ContainerUser }}
|
{{- if .ContainerUser }}
|
||||||
User: {{ .ContainerUser }}
|
User: {{ .ContainerUser }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .ContainerSysCtls }}
|
||||||
|
SysCtls:
|
||||||
|
{{- range $k, $v := .ContainerSysCtls }}
|
||||||
|
{{ $k }}{{if $v }}: {{ $v }}{{ end }}
|
||||||
|
{{- end }}{{ end }}
|
||||||
{{- if .ContainerMounts }}
|
{{- if .ContainerMounts }}
|
||||||
Mounts:
|
Mounts:
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
@ -415,6 +420,14 @@ func (ctx *serviceInspectContext) ContainerMounts() []mounttypes.Mount {
|
||||||
return ctx.Service.Spec.TaskTemplate.ContainerSpec.Mounts
|
return ctx.Service.Spec.TaskTemplate.ContainerSpec.Mounts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *serviceInspectContext) ContainerSysCtls() map[string]string {
|
||||||
|
return ctx.Service.Spec.TaskTemplate.ContainerSpec.Sysctls
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *serviceInspectContext) HasContainerSysCtls() bool {
|
||||||
|
return len(ctx.Service.Spec.TaskTemplate.ContainerSpec.Sysctls) > 0
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *serviceInspectContext) HasResources() bool {
|
func (ctx *serviceInspectContext) HasResources() bool {
|
||||||
return ctx.Service.Spec.TaskTemplate.Resources != nil
|
return ctx.Service.Spec.TaskTemplate.Resources != nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -490,6 +490,7 @@ type serviceOptions struct {
|
||||||
dnsSearch opts.ListOpts
|
dnsSearch opts.ListOpts
|
||||||
dnsOption opts.ListOpts
|
dnsOption opts.ListOpts
|
||||||
hosts opts.ListOpts
|
hosts opts.ListOpts
|
||||||
|
sysctls opts.ListOpts
|
||||||
|
|
||||||
resources resourceOptions
|
resources resourceOptions
|
||||||
stopGrace opts.DurationOpt
|
stopGrace opts.DurationOpt
|
||||||
|
@ -531,6 +532,7 @@ func newServiceOptions() *serviceOptions {
|
||||||
dnsOption: opts.NewListOpts(nil),
|
dnsOption: opts.NewListOpts(nil),
|
||||||
dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch),
|
dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch),
|
||||||
hosts: opts.NewListOpts(opts.ValidateExtraHost),
|
hosts: opts.NewListOpts(opts.ValidateExtraHost),
|
||||||
|
sysctls: opts.NewListOpts(nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,6 +645,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N
|
||||||
StopGracePeriod: options.ToStopGracePeriod(flags),
|
StopGracePeriod: options.ToStopGracePeriod(flags),
|
||||||
Healthcheck: healthConfig,
|
Healthcheck: healthConfig,
|
||||||
Isolation: container.Isolation(options.isolation),
|
Isolation: container.Isolation(options.isolation),
|
||||||
|
Sysctls: opts.ConvertKVStringsToMap(options.sysctls.GetAll()),
|
||||||
},
|
},
|
||||||
Networks: networks,
|
Networks: networks,
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
|
@ -890,6 +893,9 @@ const (
|
||||||
flagRollbackOrder = "rollback-order"
|
flagRollbackOrder = "rollback-order"
|
||||||
flagRollbackParallelism = "rollback-parallelism"
|
flagRollbackParallelism = "rollback-parallelism"
|
||||||
flagInit = "init"
|
flagInit = "init"
|
||||||
|
flagSysCtl = "sysctl"
|
||||||
|
flagSysCtlAdd = "sysctl-add"
|
||||||
|
flagSysCtlRemove = "sysctl-rm"
|
||||||
flagStopGracePeriod = "stop-grace-period"
|
flagStopGracePeriod = "stop-grace-period"
|
||||||
flagStopSignal = "stop-signal"
|
flagStopSignal = "stop-signal"
|
||||||
flagTTY = "tty"
|
flagTTY = "tty"
|
||||||
|
|
|
@ -233,3 +233,16 @@ func TestToServiceMaxReplicasGlobalModeConflict(t *testing.T) {
|
||||||
_, err := opt.ToServiceMode()
|
_, err := opt.ToServiceMode()
|
||||||
assert.Error(t, err, "replicas-max-per-node can only be used with replicated mode")
|
assert.Error(t, err, "replicas-max-per-node can only be used with replicated mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToServiceSysCtls(t *testing.T) {
|
||||||
|
o := newServiceOptions()
|
||||||
|
o.mode = "replicated"
|
||||||
|
o.sysctls.Set("net.ipv4.ip_forward=1")
|
||||||
|
o.sysctls.Set("kernel.shmmax=123456")
|
||||||
|
|
||||||
|
expected := map[string]string{"net.ipv4.ip_forward": "1", "kernel.shmmax": "123456"}
|
||||||
|
flags := newCreateCommand(nil).Flags()
|
||||||
|
service, err := o.ToService(context.Background(), &fakeClient{}, flags)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.DeepEqual(service.TaskTemplate.ContainerSpec.Sysctls, expected))
|
||||||
|
}
|
||||||
|
|
|
@ -96,6 +96,10 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command {
|
||||||
flags.SetAnnotation(flagHostAdd, "version", []string{"1.25"})
|
flags.SetAnnotation(flagHostAdd, "version", []string{"1.25"})
|
||||||
flags.BoolVar(&options.init, flagInit, false, "Use an init inside each service container to forward signals and reap processes")
|
flags.BoolVar(&options.init, flagInit, false, "Use an init inside each service container to forward signals and reap processes")
|
||||||
flags.SetAnnotation(flagInit, "version", []string{"1.37"})
|
flags.SetAnnotation(flagInit, "version", []string{"1.37"})
|
||||||
|
flags.Var(&options.sysctls, flagSysCtlAdd, "Add or update a Sysctl option")
|
||||||
|
flags.SetAnnotation(flagSysCtlAdd, "version", []string{"1.40"})
|
||||||
|
flags.Var(newListOptsVar(), flagSysCtlRemove, "Remove a Sysctl option")
|
||||||
|
flags.SetAnnotation(flagSysCtlRemove, "version", []string{"1.40"})
|
||||||
|
|
||||||
// Add needs parsing, Remove only needs the key
|
// Add needs parsing, Remove only needs the key
|
||||||
flags.Var(newListOptsVar(), flagGenericResourcesRemove, "Remove a Generic resource")
|
flags.Var(newListOptsVar(), flagGenericResourcesRemove, "Remove a Generic resource")
|
||||||
|
@ -328,6 +332,8 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSysCtls(flags, &task.ContainerSpec.Sysctls)
|
||||||
|
|
||||||
if anyChanged(flags, flagLimitCPU, flagLimitMemory) {
|
if anyChanged(flags, flagLimitCPU, flagLimitMemory) {
|
||||||
taskResources().Limits = spec.TaskTemplate.Resources.Limits
|
taskResources().Limits = spec.TaskTemplate.Resources.Limits
|
||||||
updateInt64Value(flagLimitCPU, &task.Resources.Limits.NanoCPUs)
|
updateInt64Value(flagLimitCPU, &task.Resources.Limits.NanoCPUs)
|
||||||
|
@ -661,6 +667,25 @@ func updateLabels(flags *pflag.FlagSet, field *map[string]string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateSysCtls(flags *pflag.FlagSet, field *map[string]string) {
|
||||||
|
if *field != nil && flags.Changed(flagSysCtlRemove) {
|
||||||
|
values := flags.Lookup(flagSysCtlRemove).Value.(*opts.ListOpts).GetAll()
|
||||||
|
for key := range opts.ConvertKVStringsToMap(values) {
|
||||||
|
delete(*field, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flags.Changed(flagSysCtlAdd) {
|
||||||
|
if *field == nil {
|
||||||
|
*field = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
values := flags.Lookup(flagSysCtlAdd).Value.(*opts.ListOpts).GetAll()
|
||||||
|
for key, value := range opts.ConvertKVStringsToMap(values) {
|
||||||
|
(*field)[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updateEnvironment(flags *pflag.FlagSet, field *[]string) {
|
func updateEnvironment(flags *pflag.FlagSet, field *[]string) {
|
||||||
if flags.Changed(flagEnvAdd) {
|
if flags.Changed(flagEnvAdd) {
|
||||||
envSet := map[string]string{}
|
envSet := map[string]string{}
|
||||||
|
|
|
@ -828,3 +828,100 @@ func TestUpdateMaxReplicas(t *testing.T) {
|
||||||
|
|
||||||
assert.DeepEqual(t, svc.TaskTemplate.Placement, &swarm.Placement{MaxReplicas: uint64(2)})
|
assert.DeepEqual(t, svc.TaskTemplate.Placement, &swarm.Placement{MaxReplicas: uint64(2)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateSysCtls(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
spec map[string]string
|
||||||
|
add []string
|
||||||
|
rm []string
|
||||||
|
expected map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "from scratch",
|
||||||
|
add: []string{"sysctl.zet=value-99", "sysctl.alpha=value-1"},
|
||||||
|
expected: map[string]string{"sysctl.zet": "value-99", "sysctl.alpha": "value-1"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "append new",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
add: []string{"new.sysctl=newvalue"},
|
||||||
|
expected: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2", "new.sysctl": "newvalue"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "append duplicate is a no-op",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
add: []string{"sysctl.one=value-1"},
|
||||||
|
expected: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove and append existing is a no-op",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
add: []string{"sysctl.one=value-1"},
|
||||||
|
rm: []string{"sysctl.one=value-1"},
|
||||||
|
expected: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove and append new should append",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
add: []string{"new.sysctl=newvalue"},
|
||||||
|
rm: []string{"new.sysctl=newvalue"},
|
||||||
|
expected: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2", "new.sysctl": "newvalue"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update existing",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
add: []string{"sysctl.one=newvalue"},
|
||||||
|
expected: map[string]string{"sysctl.one": "newvalue", "sysctl.two": "value-2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update existing twice",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
add: []string{"sysctl.one=newvalue", "sysctl.one=evennewervalue"},
|
||||||
|
expected: map[string]string{"sysctl.one": "evennewervalue", "sysctl.two": "value-2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove all",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
rm: []string{"sysctl.one=value-1", "sysctl.two=value-2"},
|
||||||
|
expected: map[string]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove by key",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
rm: []string{"sysctl.one"},
|
||||||
|
expected: map[string]string{"sysctl.two": "value-2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "remove by key and different value",
|
||||||
|
spec: map[string]string{"sysctl.one": "value-1", "sysctl.two": "value-2"},
|
||||||
|
rm: []string{"sysctl.one=anyvalueyoulike"},
|
||||||
|
expected: map[string]string{"sysctl.two": "value-2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
svc := swarm.ServiceSpec{
|
||||||
|
TaskTemplate: swarm.TaskSpec{
|
||||||
|
ContainerSpec: &swarm.ContainerSpec{Sysctls: tc.spec},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
flags := newUpdateCommand(nil).Flags()
|
||||||
|
for _, v := range tc.add {
|
||||||
|
assert.NilError(t, flags.Set(flagSysCtlAdd, v))
|
||||||
|
}
|
||||||
|
for _, v := range tc.rm {
|
||||||
|
assert.NilError(t, flags.Set(flagSysCtlRemove, v))
|
||||||
|
}
|
||||||
|
err := updateService(ctx, &fakeClient{}, flags, &svc)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if !assert.Check(t, is.DeepEqual(svc.TaskTemplate.ContainerSpec.Sysctls, tc.expected)) {
|
||||||
|
t.Logf("expected: %v", tc.expected)
|
||||||
|
t.Logf("actual: %v", svc.TaskTemplate.ContainerSpec.Sysctls)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -151,6 +151,7 @@ func Service(
|
||||||
Privileges: &privileges,
|
Privileges: &privileges,
|
||||||
Isolation: container.Isolation(service.Isolation),
|
Isolation: container.Isolation(service.Isolation),
|
||||||
Init: service.Init,
|
Init: service.Init,
|
||||||
|
Sysctls: service.Sysctls,
|
||||||
},
|
},
|
||||||
LogDriver: logDriver,
|
LogDriver: logDriver,
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
|
|
|
@ -240,6 +240,10 @@ services:
|
||||||
|
|
||||||
stop_signal: SIGUSR1
|
stop_signal: SIGUSR1
|
||||||
|
|
||||||
|
sysctls:
|
||||||
|
net.core.somaxconn: 1024
|
||||||
|
net.ipv4.tcp_syncookies: 0
|
||||||
|
|
||||||
# String or list
|
# String or list
|
||||||
# tmpfs: /run
|
# tmpfs: /run
|
||||||
tmpfs:
|
tmpfs:
|
||||||
|
|
|
@ -346,8 +346,12 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
|
||||||
StdinOpen: true,
|
StdinOpen: true,
|
||||||
StopSignal: "SIGUSR1",
|
StopSignal: "SIGUSR1",
|
||||||
StopGracePeriod: durationPtr(20 * time.Second),
|
StopGracePeriod: durationPtr(20 * time.Second),
|
||||||
Tmpfs: []string{"/run", "/tmp"},
|
Sysctls: map[string]string{
|
||||||
Tty: true,
|
"net.core.somaxconn": "1024",
|
||||||
|
"net.ipv4.tcp_syncookies": "0",
|
||||||
|
},
|
||||||
|
Tmpfs: []string{"/run", "/tmp"},
|
||||||
|
Tty: true,
|
||||||
Ulimits: map[string]*types.UlimitsConfig{
|
Ulimits: map[string]*types.UlimitsConfig{
|
||||||
"nproc": {
|
"nproc": {
|
||||||
Single: 65535,
|
Single: 65535,
|
||||||
|
@ -756,6 +760,9 @@ services:
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
stop_grace_period: 20s
|
stop_grace_period: 20s
|
||||||
stop_signal: SIGUSR1
|
stop_signal: SIGUSR1
|
||||||
|
sysctls:
|
||||||
|
net.core.somaxconn: "1024"
|
||||||
|
net.ipv4.tcp_syncookies: "0"
|
||||||
tmpfs:
|
tmpfs:
|
||||||
- /run
|
- /run
|
||||||
- /tmp
|
- /tmp
|
||||||
|
@ -1325,6 +1332,10 @@ func fullExampleJSON(workingDir string) string {
|
||||||
"stdin_open": true,
|
"stdin_open": true,
|
||||||
"stop_grace_period": "20s",
|
"stop_grace_period": "20s",
|
||||||
"stop_signal": "SIGUSR1",
|
"stop_signal": "SIGUSR1",
|
||||||
|
"sysctls": {
|
||||||
|
"net.core.somaxconn": "1024",
|
||||||
|
"net.ipv4.tcp_syncookies": "0"
|
||||||
|
},
|
||||||
"tmpfs": [
|
"tmpfs": [
|
||||||
"/run",
|
"/run",
|
||||||
"/tmp"
|
"/tmp"
|
||||||
|
|
|
@ -304,6 +304,7 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec
|
||||||
reflect.TypeOf(types.ServiceConfigObjConfig{}): transformStringSourceMap,
|
reflect.TypeOf(types.ServiceConfigObjConfig{}): transformStringSourceMap,
|
||||||
reflect.TypeOf(types.StringOrNumberList{}): transformStringOrNumberList,
|
reflect.TypeOf(types.StringOrNumberList{}): transformStringOrNumberList,
|
||||||
reflect.TypeOf(map[string]*types.ServiceNetworkConfig{}): transformServiceNetworkMap,
|
reflect.TypeOf(map[string]*types.ServiceNetworkConfig{}): transformServiceNetworkMap,
|
||||||
|
reflect.TypeOf(types.Mapping{}): transformMappingOrListFunc("=", false),
|
||||||
reflect.TypeOf(types.MappingWithEquals{}): transformMappingOrListFunc("=", true),
|
reflect.TypeOf(types.MappingWithEquals{}): transformMappingOrListFunc("=", true),
|
||||||
reflect.TypeOf(types.Labels{}): transformMappingOrListFunc("=", false),
|
reflect.TypeOf(types.Labels{}): transformMappingOrListFunc("=", false),
|
||||||
reflect.TypeOf(types.MappingWithColon{}): transformMappingOrListFunc(":", false),
|
reflect.TypeOf(types.MappingWithColon{}): transformMappingOrListFunc(":", false),
|
||||||
|
|
|
@ -1461,6 +1461,47 @@ services:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadSysctls(t *testing.T) {
|
||||||
|
config, err := loadYAML(`
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: busybox
|
||||||
|
sysctls:
|
||||||
|
- net.core.somaxconn=1024
|
||||||
|
- net.ipv4.tcp_syncookies=0
|
||||||
|
- testing.one.one=
|
||||||
|
- testing.one.two
|
||||||
|
`)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
expected := types.Mapping{
|
||||||
|
"net.core.somaxconn": "1024",
|
||||||
|
"net.ipv4.tcp_syncookies": "0",
|
||||||
|
"testing.one.one": "",
|
||||||
|
"testing.one.two": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Assert(t, is.Len(config.Services, 1))
|
||||||
|
assert.Check(t, is.DeepEqual(expected, config.Services[0].Sysctls))
|
||||||
|
|
||||||
|
config, err = loadYAML(`
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: busybox
|
||||||
|
sysctls:
|
||||||
|
net.core.somaxconn: 1024
|
||||||
|
net.ipv4.tcp_syncookies: 0
|
||||||
|
testing.one.one: ""
|
||||||
|
testing.one.two:
|
||||||
|
`)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
assert.Assert(t, is.Len(config.Services, 1))
|
||||||
|
assert.Check(t, is.DeepEqual(expected, config.Services[0].Sysctls))
|
||||||
|
}
|
||||||
|
|
||||||
func TestTransform(t *testing.T) {
|
func TestTransform(t *testing.T) {
|
||||||
var source = []interface{}{
|
var source = []interface{}{
|
||||||
"80-82:8080-8082",
|
"80-82:8080-8082",
|
||||||
|
|
|
@ -24,7 +24,6 @@ var UnsupportedProperties = []string{
|
||||||
"restart",
|
"restart",
|
||||||
"security_opt",
|
"security_opt",
|
||||||
"shm_size",
|
"shm_size",
|
||||||
"sysctls",
|
|
||||||
"ulimits",
|
"ulimits",
|
||||||
"userns_mode",
|
"userns_mode",
|
||||||
}
|
}
|
||||||
|
@ -200,7 +199,7 @@ type ServiceConfig struct {
|
||||||
StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
|
StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
|
||||||
StopGracePeriod *Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
|
StopGracePeriod *Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
|
||||||
StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
|
StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
|
||||||
Sysctls StringList `yaml:",omitempty" json:"sysctls,omitempty"`
|
Sysctls Mapping `yaml:",omitempty" json:"sysctls,omitempty"`
|
||||||
Tmpfs StringList `yaml:",omitempty" json:"tmpfs,omitempty"`
|
Tmpfs StringList `yaml:",omitempty" json:"tmpfs,omitempty"`
|
||||||
Tty bool `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"`
|
Tty bool `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"`
|
||||||
Ulimits map[string]*UlimitsConfig `yaml:",omitempty" json:"ulimits,omitempty"`
|
Ulimits map[string]*UlimitsConfig `yaml:",omitempty" json:"ulimits,omitempty"`
|
||||||
|
@ -240,6 +239,12 @@ type StringOrNumberList []string
|
||||||
// For the key without value (`key`), the mapped value is set to nil.
|
// For the key without value (`key`), the mapped value is set to nil.
|
||||||
type MappingWithEquals map[string]*string
|
type MappingWithEquals map[string]*string
|
||||||
|
|
||||||
|
// Mapping is a mapping type that can be converted from a list of
|
||||||
|
// key[=value] strings.
|
||||||
|
// For the key with an empty value (`key=`), or key without value (`key`), the
|
||||||
|
// mapped value is set to an empty string `""`.
|
||||||
|
type Mapping map[string]string
|
||||||
|
|
||||||
// Labels is a mapping type for labels
|
// Labels is a mapping type for labels
|
||||||
type Labels map[string]string
|
type Labels map[string]string
|
||||||
|
|
||||||
|
|
|
@ -3696,6 +3696,7 @@ _docker_service_update_and_create() {
|
||||||
--placement-pref
|
--placement-pref
|
||||||
--publish -p
|
--publish -p
|
||||||
--secret
|
--secret
|
||||||
|
--sysctl
|
||||||
"
|
"
|
||||||
|
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
|
@ -3746,6 +3747,8 @@ _docker_service_update_and_create() {
|
||||||
--rollback
|
--rollback
|
||||||
--secret-add
|
--secret-add
|
||||||
--secret-rm
|
--secret-rm
|
||||||
|
--sysctl-add
|
||||||
|
--sysctl-rm
|
||||||
"
|
"
|
||||||
|
|
||||||
boolean_options="$boolean_options
|
boolean_options="$boolean_options
|
||||||
|
|
|
@ -77,6 +77,7 @@ Options:
|
||||||
--secret secret Specify secrets to expose to the service
|
--secret secret Specify secrets to expose to the service
|
||||||
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) (default 10s)
|
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) (default 10s)
|
||||||
--stop-signal string Signal to stop the container
|
--stop-signal string Signal to stop the container
|
||||||
|
--sysctl list Sysctl options
|
||||||
-t, --tty Allocate a pseudo-TTY
|
-t, --tty Allocate a pseudo-TTY
|
||||||
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s)
|
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s)
|
||||||
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback") (default "pause")
|
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback") (default "pause")
|
||||||
|
|
|
@ -93,6 +93,8 @@ Options:
|
||||||
--secret-rm list Remove a secret
|
--secret-rm list Remove a secret
|
||||||
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h)
|
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h)
|
||||||
--stop-signal string Signal to stop the container
|
--stop-signal string Signal to stop the container
|
||||||
|
--sysctl-add list Add or update a Sysctl option
|
||||||
|
--sysctl-rm list Remove a Sysctl option
|
||||||
-t, --tty Allocate a pseudo-TTY
|
-t, --tty Allocate a pseudo-TTY
|
||||||
--update-delay duration Delay between updates (ns|us|ms|s|m|h)
|
--update-delay duration Delay between updates (ns|us|ms|s|m|h)
|
||||||
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback")
|
--update-failure-action string Action on update failure ("pause"|"continue"|"rollback")
|
||||||
|
|
Loading…
Reference in New Issue