Pārlūkot izejas kodu

Merge pull request #23718 from yongtang/23498-entrypoint-unset

Allow unset `--entrypoint` in `docker run` or `docker create`
Sebastiaan van Stijn 9 gadi atpakaļ
vecāks
revīzija
2684459ed4

+ 4 - 0
daemon/create.go

@@ -240,6 +240,10 @@ func (daemon *Daemon) mergeAndVerifyConfig(config *containertypes.Config, img *i
 			return err
 			return err
 		}
 		}
 	}
 	}
+	// Reset the Entrypoint if it is [""]
+	if len(config.Entrypoint) == 1 && config.Entrypoint[0] == "" {
+		config.Entrypoint = nil
+	}
 	if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
 	if len(config.Entrypoint) == 0 && len(config.Cmd) == 0 {
 		return fmt.Errorf("No command specified")
 		return fmt.Errorf("No command specified")
 	}
 	}

+ 3 - 1
docs/reference/api/docker_remote_api_v1.25.md

@@ -377,7 +377,9 @@ Create a container
 -   **Labels** - Adds a map of labels to a container. To specify a map: `{"key":"value"[,"key2":"value2"]}`
 -   **Labels** - Adds a map of labels to a container. To specify a map: `{"key":"value"[,"key2":"value2"]}`
 -   **Cmd** - Command to run specified as a string or an array of strings.
 -   **Cmd** - Command to run specified as a string or an array of strings.
 -   **Entrypoint** - Set the entry point for the container as a string or an array
 -   **Entrypoint** - Set the entry point for the container as a string or an array
-      of strings.
+      of strings. If the array consists of exactly one empty string (`[""]`) then the entry point
+      is reset to system default (i.e., the entry point used by docker when there is no `ENTRYPOINT`
+      instruction in the Dockerfile).
 -   **Image** - A string specifying the image name to use for the container.
 -   **Image** - A string specifying the image name to use for the container.
 -   **Volumes** - An object mapping mount point paths (strings) inside the
 -   **Volumes** - An object mapping mount point paths (strings) inside the
       container to empty objects.
       container to empty objects.

+ 4 - 0
docs/reference/run.md

@@ -1305,6 +1305,10 @@ or two examples of how to pass more parameters to that ENTRYPOINT:
     $ docker run -it --entrypoint /bin/bash example/redis -c ls -l
     $ docker run -it --entrypoint /bin/bash example/redis -c ls -l
     $ docker run -it --entrypoint /usr/bin/redis-cli example/redis --help
     $ docker run -it --entrypoint /usr/bin/redis-cli example/redis --help
 
 
+You can reset a containers entrypoint by passing an empty string, for example:
+
+    $ docker run -it --entrypoint="" mysql bash
+
 > **Note**: Passing `--entrypoint` will clear out any default command set on the
 > **Note**: Passing `--entrypoint` will clear out any default command set on the
 > image (i.e. any `CMD` instruction in the Dockerfile used to build it).
 > image (i.e. any `CMD` instruction in the Dockerfile used to build it).
 
 

+ 28 - 0
integration-cli/docker_cli_create_test.go

@@ -478,3 +478,31 @@ func (s *DockerSuite) TestCreate64ByteHexID(c *check.C) {
 
 
 	dockerCmd(c, "create", imageID)
 	dockerCmd(c, "create", imageID)
 }
 }
+
+// Test case for #23498
+func (s *DockerSuite) TestCreateUnsetEntrypoint(c *check.C) {
+	testRequires(c, DaemonIsLinux)
+	name := "test-entrypoint"
+	dockerfile := `FROM busybox
+ADD entrypoint.sh /entrypoint.sh
+RUN chmod 755 /entrypoint.sh
+ENTRYPOINT ["/entrypoint.sh"]
+CMD echo foobar`
+
+	ctx, err := fakeContext(dockerfile, map[string]string{
+		"entrypoint.sh": `#!/bin/sh
+echo "I am an entrypoint"
+exec "$@"`,
+	})
+	c.Assert(err, check.IsNil)
+	defer ctx.Close()
+
+	_, err = buildImageFromContext(name, ctx, true)
+	c.Assert(err, check.IsNil)
+
+	out, _ := dockerCmd(c, "create", "--entrypoint=", name, "echo", "foo")
+	id := strings.TrimSpace(out)
+	c.Assert(id, check.Not(check.Equals), "")
+	out, _ = dockerCmd(c, "start", "-a", id)
+	c.Assert(strings.TrimSpace(out), check.Equals, "foo")
+}

+ 30 - 0
integration-cli/docker_cli_run_test.go

@@ -4497,3 +4497,33 @@ func (s *DockerSuite) TestRunAddHostInHostMode(c *check.C) {
 	out, _ := dockerCmd(c, "run", "--add-host=extra:1.2.3.4", "--net=host", "busybox", "cat", "/etc/hosts")
 	out, _ := dockerCmd(c, "run", "--add-host=extra:1.2.3.4", "--net=host", "busybox", "cat", "/etc/hosts")
 	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
 	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
 }
 }
+
+// Test case for #23498
+func (s *DockerSuite) TestRunUnsetEntrypoint(c *check.C) {
+	testRequires(c, DaemonIsLinux)
+	name := "test-entrypoint"
+	dockerfile := `FROM busybox
+ADD entrypoint.sh /entrypoint.sh
+RUN chmod 755 /entrypoint.sh
+ENTRYPOINT ["/entrypoint.sh"]
+CMD echo foobar`
+
+	ctx, err := fakeContext(dockerfile, map[string]string{
+		"entrypoint.sh": `#!/bin/sh
+echo "I am an entrypoint"
+exec "$@"`,
+	})
+	c.Assert(err, check.IsNil)
+	defer ctx.Close()
+
+	_, err = buildImageFromContext(name, ctx, true)
+	c.Assert(err, check.IsNil)
+
+	out, _ := dockerCmd(c, "run", "--entrypoint=", "-t", name, "echo", "foo")
+	c.Assert(strings.TrimSpace(out), check.Equals, "foo")
+
+	// CMD will be reset as well (the same as setting a custom entrypoint)
+	_, _, err = dockerCmdWithError("run", "--entrypoint=", "-t", name)
+	c.Assert(err, check.NotNil)
+	c.Assert(err.Error(), checker.Contains, "No command specified")
+}

+ 3 - 0
runconfig/opts/parse.go

@@ -366,6 +366,9 @@ func Parse(flags *pflag.FlagSet, copts *ContainerOptions) (*container.Config, *c
 	}
 	}
 	if copts.flEntrypoint != "" {
 	if copts.flEntrypoint != "" {
 		entrypoint = strslice.StrSlice{copts.flEntrypoint}
 		entrypoint = strslice.StrSlice{copts.flEntrypoint}
+	} else if flags.Changed("entrypoint") {
+		// if `--entrypoint=` is parsed then Entrypoint is reset
+		entrypoint = []string{""}
 	}
 	}
 
 
 	ports, portBindings, err := nat.ParsePortSpecs(copts.flPublish.GetAll())
 	ports, portBindings, err := nat.ParsePortSpecs(copts.flPublish.GetAll())