浏览代码

Add Entrypoint to builder and container config

By setting an entrypoint in the Dockerfile this
allows one to run an image and only pass arguments.
Michael Crosby 12 年之前
父节点
当前提交
b16ff9f859
共有 8 个文件被更改,包括 90 次插入4 次删除
  1. 13 2
      builder.go
  2. 18 1
      buildfile.go
  3. 9 0
      buildfile_test.go
  4. 8 0
      container.go
  5. 26 0
      container_test.go
  6. 1 0
      docs/sources/commandline/command/run.rst
  7. 7 0
      docs/sources/use/builder.rst
  8. 8 1
      utils.go

+ 13 - 2
builder.go

@@ -50,12 +50,23 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
 		config.Hostname = id[:12]
 	}
 
+	var args []string
+	var entrypoint string
+
+	if len(config.Entrypoint) != 0 {
+		entrypoint = config.Entrypoint[0]
+		args = append(config.Entrypoint[1:], config.Cmd...)
+	} else {
+		entrypoint = config.Cmd[0]
+		args = config.Cmd[1:]
+	}
+
 	container := &Container{
 		// FIXME: we should generate the ID here instead of receiving it as an argument
 		ID:              id,
 		Created:         time.Now(),
-		Path:            config.Cmd[0],
-		Args:            config.Cmd[1:], //FIXME: de-duplicate from config
+		Path:            entrypoint,
+		Args:            args, //FIXME: de-duplicate from config
 		Config:          config,
 		Image:           img.ID, // Always use the resolved image id
 		NetworkSettings: &NetworkSettings{},

+ 18 - 1
buildfile.go

@@ -141,7 +141,7 @@ func (b *buildFile) CmdEnv(args string) error {
 func (b *buildFile) CmdCmd(args string) error {
 	var cmd []string
 	if err := json.Unmarshal([]byte(args), &cmd); err != nil {
-		utils.Debugf("Error unmarshalling: %s, using /bin/sh -c", err)
+		utils.Debugf("Error unmarshalling: %s, setting cmd to /bin/sh -c", err)
 		cmd = []string{"/bin/sh", "-c", args}
 	}
 	if err := b.commit("", cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
@@ -165,6 +165,23 @@ func (b *buildFile) CmdCopy(args string) error {
 	return fmt.Errorf("COPY has been deprecated. Please use ADD instead")
 }
 
+func (b *buildFile) CmdEntrypoint(args string) error {
+	if args == "" {
+		return fmt.Errorf("Entrypoint cannot be empty")
+	}
+
+	var entrypoint []string
+	if err := json.Unmarshal([]byte(args), &entrypoint); err != nil {
+		b.config.Entrypoint = []string{"/bin/sh", "-c", args}
+	} else {
+		b.config.Entrypoint = entrypoint
+	}
+	if err := b.commit("", b.config.Cmd, fmt.Sprintf("ENTRYPOINT %s", args)); err != nil {
+		return err
+	}
+	return nil
+}
+
 func (b *buildFile) addRemote(container *Container, orig, dest string) error {
 	file, err := utils.Download(orig, ioutil.Discard)
 	if err != nil {

+ 9 - 0
buildfile_test.go

@@ -79,6 +79,15 @@ run [ "$(cat /somewheeeere/over/the/rainbooow/ga)" = "bu" ]
 from %s
 env    FOO BAR
 run    [ "$FOO" = "BAR" ]
+`,
+		nil,
+	},
+
+	{
+		`
+from docker-ut
+ENTRYPOINT /bin/echo
+CMD Hello world
 `,
 		nil,
 	},

+ 8 - 0
container.go

@@ -76,6 +76,7 @@ type Config struct {
 	Image        string // Name of the image as it was passed by the operator (eg. could be symbolic)
 	Volumes      map[string]struct{}
 	VolumesFrom  string
+	Entrypoint   []string
 }
 
 type HostConfig struct {
@@ -123,6 +124,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 	cmd.Var(flVolumes, "v", "Attach a data volume")
 
 	flVolumesFrom := cmd.String("volumes-from", "", "Mount volumes from the specified container")
+	flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
 
 	var flBinds ListOpts
 	cmd.Var(&flBinds, "b", "Bind mount a volume from the host (e.g. -b /host:/container)")
@@ -153,6 +155,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 
 	parsedArgs := cmd.Args()
 	runCmd := []string{}
+	entrypoint := []string{}
 	image := ""
 	if len(parsedArgs) >= 1 {
 		image = cmd.Arg(0)
@@ -160,6 +163,10 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 	if len(parsedArgs) > 1 {
 		runCmd = parsedArgs[1:]
 	}
+	if *flEntrypoint != "" {
+		entrypoint = []string{*flEntrypoint}
+	}
+
 	config := &Config{
 		Hostname:     *flHostname,
 		PortSpecs:    flPorts,
@@ -177,6 +184,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig,
 		Image:        image,
 		Volumes:      flVolumes,
 		VolumesFrom:  *flVolumesFrom,
+		Entrypoint:   entrypoint,
 	}
 	hostConfig := &HostConfig{
 		Binds: flBinds,

+ 26 - 0
container_test.go

@@ -1043,6 +1043,32 @@ func TestEnv(t *testing.T) {
 	}
 }
 
+func TestEntrypoint(t *testing.T) {
+	runtime, err := newTestRuntime()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nuke(runtime)
+	container, err := NewBuilder(runtime).Create(
+		&Config{
+			Image:      GetTestImage(runtime).ID,
+			Entrypoint: []string{"/bin/echo"},
+			Cmd:        []string{"-n", "foobar"},
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container)
+	output, err := container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(output) != "foobar" {
+		t.Error(string(output))
+	}
+}
+
 func grepFile(t *testing.T, path string, pattern string) {
 	f, err := os.Open(path)
 	if err != nil {

+ 1 - 0
docs/sources/commandline/command/run.rst

@@ -26,3 +26,4 @@
       -v=[]: Creates a new volume and mounts it at the specified path.
       -volumes-from="": Mount all volumes from the given container.
       -b=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]
+      -entrypoint="": Overwrite the default entrypoint set by the image.

+ 7 - 0
docs/sources/use/builder.rst

@@ -153,6 +153,13 @@ of `<src>` will be written at `<dst>`.
 If `<dest>` doesn't exist, it is created along with all missing directories in its path. All new
 files and directories are created with mode 0700, uid and gid 0.
 
+2.8 ENTRYPOINT
+-------------
+
+    ``ENTRYPOINT /bin/echo``
+
+The `ENTRYPOINT` instruction adds an entry command that will not be overwritten when arguments are passed to docker run, unlike the behavior of `CMD`.  This allows arguments to be passed to the entrypoint.  i.e. `docker run <image> -d` will pass the "-d" argument to the entrypoint.
+
 3. Dockerfile Examples
 ======================
 

+ 8 - 1
utils.go

@@ -44,7 +44,11 @@ func CompareConfig(a, b *Config) bool {
 			return false
 		}
 	}
-
+	for i := 0; i < len(a.Entrypoint); i++ {
+		if a.Entrypoint[i] != b.Entrypoint[i] {
+			return false
+		}
+	}
 	return true
 }
 
@@ -85,4 +89,7 @@ func MergeConfig(userConf, imageConf *Config) {
 	if userConf.Dns == nil || len(userConf.Dns) == 0 {
 		userConf.Dns = imageConf.Dns
 	}
+	if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 {
+		userConf.Entrypoint = imageConf.Entrypoint
+	}
 }