diff --git a/cli/command/formatter/service.go b/cli/command/formatter/service.go index 697d6be4c0..5dde8006d2 100644 --- a/cli/command/formatter/service.go +++ b/cli/command/formatter/service.go @@ -85,6 +85,9 @@ ContainerSpec: {{- if .ContainerWorkDir }} Dir: {{ .ContainerWorkDir }} {{- end -}} +{{- if .HasContainerInit }} + Init: {{ .ContainerInit }} +{{- end -}} {{- if .ContainerUser }} User: {{ .ContainerUser }} {{- end }} @@ -372,6 +375,14 @@ func (ctx *serviceInspectContext) ContainerUser() string { return ctx.Service.Spec.TaskTemplate.ContainerSpec.User } +func (ctx *serviceInspectContext) HasContainerInit() bool { + return ctx.Service.Spec.TaskTemplate.ContainerSpec.Init != nil +} + +func (ctx *serviceInspectContext) ContainerInit() bool { + return *ctx.Service.Spec.TaskTemplate.ContainerSpec.Init +} + func (ctx *serviceInspectContext) ContainerMounts() []mounttypes.Mount { return ctx.Service.Spec.TaskTemplate.ContainerSpec.Mounts } diff --git a/cli/command/service/create.go b/cli/command/service/create.go index ca7aaba376..ec74eb43c3 100644 --- a/cli/command/service/create.go +++ b/cli/command/service/create.go @@ -58,6 +58,8 @@ func newCreateCommand(dockerCli command.Cli) *cobra.Command { flags.SetAnnotation(flagDNSSearch, "version", []string{"1.25"}) flags.Var(&opts.hosts, flagHost, "Set one or more custom host-to-IP mappings (host:ip)") 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.SetAnnotation(flagInit, "version", []string{"1.37"}) flags.Var(cliopts.NewListOptsRef(&opts.resources.resGenericResources, ValidateSingleGenericResource), "generic-resource", "User defined resources") flags.SetAnnotation(flagHostAdd, "version", []string{"1.32"}) diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go index 6d42745156..6a9591abce 100644 --- a/cli/command/service/opts.go +++ b/cli/command/service/opts.go @@ -480,6 +480,7 @@ type serviceOptions struct { user string groups opts.ListOpts credentialSpec credentialSpecOpt + init bool stopSignal string tty bool readOnly bool @@ -624,6 +625,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N TTY: options.tty, ReadOnly: options.readOnly, Mounts: options.mounts.Value(), + Init: &options.init, DNSConfig: &swarm.DNSConfig{ Nameservers: options.dns.GetAll(), Search: options.dnsSearch.GetAll(), @@ -875,6 +877,7 @@ const ( flagRollbackMonitor = "rollback-monitor" flagRollbackOrder = "rollback-order" flagRollbackParallelism = "rollback-parallelism" + flagInit = "init" flagStopGracePeriod = "stop-grace-period" flagStopSignal = "stop-signal" flagTTY = "tty" diff --git a/cli/command/service/update.go b/cli/command/service/update.go index 66494fdbb9..3e380db23e 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -94,6 +94,8 @@ func newUpdateCommand(dockerCli command.Cli) *cobra.Command { flags.SetAnnotation(flagDNSSearchAdd, "version", []string{"1.25"}) flags.Var(&options.hosts, flagHostAdd, "Add a custom host-to-IP mapping (host:ip)") 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.SetAnnotation(flagInit, "version", []string{"1.37"}) // Add needs parsing, Remove only needs the key flags.Var(newListOptsVar(), flagGenericResourcesRemove, "Remove a Generic resource") @@ -235,6 +237,12 @@ func runUpdate(dockerCli command.Cli, flags *pflag.FlagSet, options *serviceOpti // nolint: gocyclo func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags *pflag.FlagSet, spec *swarm.ServiceSpec) error { + updateBoolPtr := func(flag string, field **bool) { + if flags.Changed(flag) { + b, _ := flags.GetBool(flag) + *field = &b + } + } updateString := func(flag string, field *string) { if flags.Changed(flag) { *field, _ = flags.GetString(flag) @@ -306,6 +314,7 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags updateString(flagWorkdir, &cspec.Dir) updateString(flagUser, &cspec.User) updateString(flagHostname, &cspec.Hostname) + updateBoolPtr(flagInit, &cspec.Init) if err := updateIsolation(flagIsolation, &cspec.Isolation); err != nil { return err } diff --git a/cli/command/service/update_test.go b/cli/command/service/update_test.go index fa761ba08f..847b6ab128 100644 --- a/cli/command/service/update_test.go +++ b/cli/command/service/update_test.go @@ -547,6 +547,32 @@ func TestUpdateReadOnly(t *testing.T) { assert.Check(t, !cspec.ReadOnly) } +func TestUpdateInit(t *testing.T) { + spec := &swarm.ServiceSpec{ + TaskTemplate: swarm.TaskSpec{ + ContainerSpec: &swarm.ContainerSpec{}, + }, + } + cspec := spec.TaskTemplate.ContainerSpec + + // Update with --init=true + flags := newUpdateCommand(nil).Flags() + flags.Set("init", "true") + updateService(nil, nil, flags, spec) + assert.Check(t, is.Equal(true, *cspec.Init)) + + // Update without --init, no change + flags = newUpdateCommand(nil).Flags() + updateService(nil, nil, flags, spec) + assert.Check(t, is.Equal(true, *cspec.Init)) + + // Update with --init=false + flags = newUpdateCommand(nil).Flags() + flags.Set("init", "false") + updateService(nil, nil, flags, spec) + assert.Check(t, is.Equal(false, *cspec.Init)) +} + func TestUpdateStopSignal(t *testing.T) { spec := &swarm.ServiceSpec{ TaskTemplate: swarm.TaskSpec{ diff --git a/docs/reference/commandline/service_create.md b/docs/reference/commandline/service_create.md index cdda1373ae..8fdb5297a1 100644 --- a/docs/reference/commandline/service_create.md +++ b/docs/reference/commandline/service_create.md @@ -43,6 +43,7 @@ Options: --help Print usage --host list Set one or more custom host-to-IP mappings (host:ip) --hostname string Container hostname + --init bool Use an init inside each service container to forward signals and reap processes --isolation string Service container isolation mode -l, --label list Service labels --limit-cpu decimal Limit CPUs diff --git a/docs/reference/commandline/service_update.md b/docs/reference/commandline/service_update.md index 5c43f02099..f3d70495b3 100644 --- a/docs/reference/commandline/service_update.md +++ b/docs/reference/commandline/service_update.md @@ -54,6 +54,7 @@ Options: --host-add list Add a custom host-to-IP mapping (host:ip) --host-rm list Remove a custom host-to-IP mapping (host:ip) --hostname string Container hostname + --init bool Use an init inside each service container to forward signals and reap processes --image string Service image tag --isolation string Service container isolation mode --label-add list Add or update a service label