diff --git a/cmd/uncloud/service/run.go b/cmd/uncloud/service/run.go index 89d404e2..82515456 100644 --- a/cmd/uncloud/service/run.go +++ b/cmd/uncloud/service/run.go @@ -13,14 +13,16 @@ import ( ) type runOptions struct { - command []string - image string - machines []string - mode string - name string - publish []string - replicas uint - volumes []string + command []string + entrypoint string + entrypointChanged bool + image string + machines []string + mode string + name string + publish []string + replicas uint + volumes []string cluster string } @@ -35,6 +37,7 @@ func NewRunCommand() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) + opts.entrypointChanged = cmd.Flag("entrypoint").Changed opts.image = args[0] if len(args) > 1 { opts.command = args[1:] @@ -44,6 +47,8 @@ func NewRunCommand() *cobra.Command { }, } + cmd.Flags().StringVar(&opts.entrypoint, "entrypoint", "", + "Overwrite the default ENTRYPOINT of the image. Pass an empty string \"\" to reset it.") cmd.Flags().StringVar(&opts.mode, "mode", api.ServiceModeReplicated, fmt.Sprintf("Replication mode of the service: either %q (a specified number of containers across "+ "the machines) or %q (one container on every machine).", @@ -128,6 +133,14 @@ func run(ctx context.Context, uncli *cli.CLI, opts runOptions) error { Ports: ports, Replicas: opts.replicas, } + + // Overwrite the default ENTRYPOINT of the image or reset it if an empty string is passed. + if opts.entrypoint != "" { + spec.Container.Entrypoint = []string{opts.entrypoint} + } else if opts.entrypointChanged { + spec.Container.Entrypoint = []string{""} + } + if err := spec.Validate(); err != nil { return fmt.Errorf("invalid service configuration: %w", err) } diff --git a/internal/api/container.go b/internal/api/container.go index 4e771c07..f99e4589 100644 --- a/internal/api/container.go +++ b/internal/api/container.go @@ -75,10 +75,11 @@ func (c *Container) ServiceSpec() (ServiceSpec, error) { // is created. Figure out how to get a spec that is equal to the initial spec. return ServiceSpec{ Container: ContainerSpec{ - Command: c.Config.Cmd, - Image: c.Config.Image, - Init: c.HostConfig.Init, - Volumes: c.HostConfig.Binds, + Command: c.Config.Cmd, + Entrypoint: c.Config.Entrypoint, + Image: c.Config.Image, + Init: c.HostConfig.Init, + Volumes: c.HostConfig.Binds, }, Mode: c.ServiceMode(), Name: c.ServiceName(), diff --git a/internal/api/service.go b/internal/api/service.go index 9c2480dc..669bba8b 100644 --- a/internal/api/service.go +++ b/internal/api/service.go @@ -67,8 +67,11 @@ func ValidateServiceID(id string) bool { } type ContainerSpec struct { + // Command overrides the default CMD of the image to be executed when running a container. Command []string - Image string + // Entrypoint overrides the default ENTRYPOINT of the image. + Entrypoint []string + Image string // Run a custom init inside the container. If nil, use the daemon's configured settings. Init *bool // List of volumes to bind mount into the container. diff --git a/internal/cli/client/container.go b/internal/cli/client/container.go index 8ff7c125..c050a2be 100644 --- a/internal/cli/client/container.go +++ b/internal/cli/client/container.go @@ -42,9 +42,10 @@ func (cli *Client) CreateContainer( // TODO: calculate the spec hash and set it as a label to detect changes in the service spec. config := &container.Config{ - Cmd: spec.Container.Command, - Hostname: containerName, - Image: spec.Container.Image, + Cmd: spec.Container.Command, + Entrypoint: spec.Container.Entrypoint, + Hostname: containerName, + Image: spec.Container.Image, Labels: map[string]string{ api.LabelServiceID: serviceID, api.LabelServiceName: spec.Name,