From f8e77dfb3de50b3c4f0f8c852389a6ed5bcbcd6e Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Mon, 29 Sep 2014 04:03:56 -0400 Subject: [PATCH 1/8] pass --change changes to the commit job Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: dqminh) Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: rhatdan) --- api/client/commands.go | 3 +++ api/server/server.go | 1 + 2 files changed, 4 insertions(+) diff --git a/api/client/commands.go b/api/client/commands.go index 9776936506..f25b6bbb43 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1702,6 +1702,8 @@ func (cli *DockerCli) CmdCommit(args ...string) error { flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit") flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith \")") + flChanges := opts.NewListOpts(nil) + cmd.Var(&flChanges, []string{"c", "-change"}, "Apply a modification before committing the image") // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands") cmd.Require(flag.Max, 2) @@ -1726,6 +1728,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error { v.Set("tag", tag) v.Set("comment", *flComment) v.Set("author", *flAuthor) + v.Set("changes", strings.Join(flChanges.GetAll(), "\n")) if *flPause != true { v.Set("pause", "0") diff --git a/api/server/server.go b/api/server/server.go index 78ca4b7829..ef6951c691 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -518,6 +518,7 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit job.Setenv("tag", r.Form.Get("tag")) job.Setenv("author", r.Form.Get("author")) job.Setenv("comment", r.Form.Get("comment")) + job.Setenv("changes", r.Form.Get("changes")) job.SetenvSubEnv("config", &config) job.Stdout.Add(stdoutBuffer) From 7f091eca704970a5cb8a4fdab295dae543c47a89 Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Fri, 9 Jan 2015 16:07:00 -0500 Subject: [PATCH 2/8] build_config job: parse dockerfile ast into config Instead of building the actual image, `build_config` will serialize a subset of dockerfile ast into *runconfig.Config Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: dqminh) Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: rhatdan) --- builder/evaluator.go | 5 ++++ builder/internals.go | 3 +++ builder/job.go | 61 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/builder/evaluator.go b/builder/evaluator.go index e027c8bceb..3ce5f0926f 100644 --- a/builder/evaluator.go +++ b/builder/evaluator.go @@ -96,6 +96,11 @@ type Builder struct { ForceRemove bool Pull bool + // set this to true if we want the builder to not commit between steps. + // This is useful when we only want to use the evaluator table to generate + // the final configs of the Dockerfile but dont want the layers + disableCommit bool + AuthConfig *registry.AuthConfig AuthConfigFile *registry.ConfigFile diff --git a/builder/internals.go b/builder/internals.go index c315d2f949..9668c5f3a3 100644 --- a/builder/internals.go +++ b/builder/internals.go @@ -60,6 +60,9 @@ func (b *Builder) readContext(context io.Reader) error { } func (b *Builder) commit(id string, autoCmd []string, comment string) error { + if b.disableCommit { + return nil + } if b.image == "" && !b.noBaseImage { return fmt.Errorf("Please provide a source image with `from` prior to commit") } diff --git a/builder/job.go b/builder/job.go index 53490b7e57..edc50c53c3 100644 --- a/builder/job.go +++ b/builder/job.go @@ -1,12 +1,16 @@ package builder import ( + "bytes" + "encoding/json" + "fmt" "io" "io/ioutil" "os" "os/exec" "github.com/docker/docker/api" + "github.com/docker/docker/builder/parser" "github.com/docker/docker/daemon" "github.com/docker/docker/engine" "github.com/docker/docker/graph" @@ -14,6 +18,7 @@ import ( "github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/urlutil" "github.com/docker/docker/registry" + "github.com/docker/docker/runconfig" "github.com/docker/docker/utils" ) @@ -24,6 +29,7 @@ type BuilderJob struct { func (b *BuilderJob) Install() { b.Engine.Register("build", b.CmdBuild) + b.Engine.Register("build_config", b.CmdBuildConfig) } func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { @@ -138,3 +144,58 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) engine.Status { } return engine.StatusOK } + +func (b *BuilderJob) CmdBuildConfig(job *engine.Job) engine.Status { + if len(job.Args) != 0 { + return job.Errorf("Usage: %s\n", job.Name) + } + var ( + validCmd = map[string]struct{}{ + "entrypoint": {}, + "cmd": {}, + "user": {}, + "workdir": {}, + "env": {}, + "volume": {}, + "expose": {}, + "onbuild": {}, + } + + changes = job.Getenv("changes") + newConfig runconfig.Config + ) + + if err := job.GetenvJson("config", &newConfig); err != nil { + return job.Error(err) + } + + ast, err := parser.Parse(bytes.NewBufferString(changes)) + if err != nil { + return job.Error(err) + } + + builder := &Builder{ + Daemon: b.Daemon, + Engine: b.Engine, + Config: &newConfig, + OutStream: ioutil.Discard, + ErrStream: ioutil.Discard, + disableCommit: true, + } + + for i, n := range ast.Children { + cmd := n.Value + if _, ok := validCmd[cmd]; ok { + if err := builder.dispatch(i, n); err != nil { + return job.Error(err) + } + } else { + fmt.Fprintf(builder.ErrStream, "# Skipping serialization of instruction %s\n", strings.ToUpper(cmd)) + } + } + + if err := json.NewEncoder(job.Stdout).Encode(builder.Config); err != nil { + return job.Error(err) + } + return engine.StatusOK +} From b30257ccf96f646c6b008312d39544d6700f5cb1 Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Wed, 1 Oct 2014 05:35:44 -0400 Subject: [PATCH 3/8] support `changes` in commit job In addition to config env, `commit` now will also accepts a `changes` env which is a string contains new-line separated Dockerfile instructions. `commit` will evaluate `changes` into `runconfig.Config` and merge it with `config` env, and then finally commit a new image with the changed config Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: dqminh) Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: rhatdan) --- daemon/commit.go | 19 ++++++++++--- integration-cli/docker_cli_commit_test.go | 33 +++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/daemon/commit.go b/daemon/commit.go index 7c83c60cc4..f253a94d82 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -1,6 +1,9 @@ package daemon import ( + "bytes" + "encoding/json" + "github.com/docker/docker/engine" "github.com/docker/docker/image" "github.com/docker/docker/runconfig" @@ -18,11 +21,21 @@ func (daemon *Daemon) ContainerCommit(job *engine.Job) engine.Status { } var ( - config = container.Config - newConfig runconfig.Config + config = container.Config + stdoutBuffer = bytes.NewBuffer(nil) + newConfig runconfig.Config ) - if err := job.GetenvJson("config", &newConfig); err != nil { + buildConfigJob := daemon.eng.Job("build_config") + buildConfigJob.Stdout.Add(stdoutBuffer) + buildConfigJob.Setenv("changes", job.Getenv("changes")) + // FIXME this should be remove when we remove deprecated config param + buildConfigJob.Setenv("config", job.Getenv("config")) + + if err := buildConfigJob.Run(); err != nil { + return job.Error(err) + } + if err := json.NewDecoder(stdoutBuffer).Decode(&newConfig); err != nil { return job.Error(err) } diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index 18eca54444..95a34b9169 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -202,3 +202,36 @@ func TestCommitWithHostBindMount(t *testing.T) { logDone("commit - commit bind mounted file") } + +func TestCommitChange(t *testing.T) { + defer deleteAllContainers() + cmd(t, "run", "--name", "test", "busybox", "true") + + cmd := exec.Command(dockerBinary, "commit", + "--change", "EXPOSE 8080", + "--change", "ENV DEBUG true", + "test", "test-commit") + imageId, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(imageId, err) + } + imageId = strings.Trim(imageId, "\r\n") + defer deleteImages(imageId) + + expected := map[string]string{ + "Config.ExposedPorts": "map[8080/tcp:map[]]", + "Config.Env": "[DEBUG=true PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin]", + } + + for conf, value := range expected { + res, err := inspectField(imageId, conf) + if err != nil { + t.Errorf("failed to get value %s, error: %s", conf, err) + } + if res != value { + t.Errorf("%s('%s'), expected %s", conf, res, value) + } + } + + logDone("commit - commit --change") +} From 6d4cd446fe1df4074f44267c4c5b0134bcedc65c Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Wed, 1 Oct 2014 11:13:59 -0400 Subject: [PATCH 4/8] instantiate the builder job in commit integration tests Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: dqminh) Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: rhatdan) --- integration/api_test.go | 3 +++ integration/server_test.go | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/integration/api_test.go b/integration/api_test.go index 8daa4d46f3..e978c311bf 100644 --- a/integration/api_test.go +++ b/integration/api_test.go @@ -16,6 +16,7 @@ import ( "github.com/docker/docker/api" "github.com/docker/docker/api/server" + "github.com/docker/docker/builder" "github.com/docker/docker/engine" "github.com/docker/docker/runconfig" "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar" @@ -158,6 +159,8 @@ func TestGetContainersTop(t *testing.T) { func TestPostCommit(t *testing.T) { eng := NewTestEngine(t) + b := &builder.BuilderJob{Engine: eng} + b.Install() defer mkDaemonFromEngine(eng, t).Nuke() // Create a container and remove a file diff --git a/integration/server_test.go b/integration/server_test.go index 1384973306..6d12ad35ad 100644 --- a/integration/server_test.go +++ b/integration/server_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/docker/docker/builder" "github.com/docker/docker/engine" ) @@ -22,6 +23,8 @@ func TestCreateNumberHostname(t *testing.T) { func TestCommit(t *testing.T) { eng := NewTestEngine(t) + b := &builder.BuilderJob{Engine: eng} + b.Install() defer mkDaemonFromEngine(eng, t).Nuke() config, _, _, err := parseRun([]string{unitTestImageID, "/bin/cat"}) @@ -42,6 +45,8 @@ func TestCommit(t *testing.T) { func TestMergeConfigOnCommit(t *testing.T) { eng := NewTestEngine(t) + b := &builder.BuilderJob{Engine: eng} + b.Install() runtime := mkDaemonFromEngine(eng, t) defer runtime.Nuke() From 3210d13fc8fb93263a7a5eadef0a0f133087a889 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Fri, 24 Oct 2014 21:11:00 +0000 Subject: [PATCH 5/8] Return error on invalid --change command Signed-off-by: Michael Crosby Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: rhatdan) --- builder/job.go | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/builder/job.go b/builder/job.go index edc50c53c3..2e43547735 100644 --- a/builder/job.go +++ b/builder/job.go @@ -3,7 +3,6 @@ package builder import ( "bytes" "encoding/json" - "fmt" "io" "io/ioutil" "os" @@ -22,6 +21,18 @@ import ( "github.com/docker/docker/utils" ) +// whitelist of commands allowed for a commit +var validCommitCommands = map[string]bool{ + "entrypoint": true, + "cmd": true, + "user": true, + "workdir": true, + "env": true, + "volume": true, + "expose": true, + "onbuild": true, +} + type BuilderJob struct { Engine *engine.Engine Daemon *daemon.Daemon @@ -149,18 +160,8 @@ func (b *BuilderJob) CmdBuildConfig(job *engine.Job) engine.Status { if len(job.Args) != 0 { return job.Errorf("Usage: %s\n", job.Name) } - var ( - validCmd = map[string]struct{}{ - "entrypoint": {}, - "cmd": {}, - "user": {}, - "workdir": {}, - "env": {}, - "volume": {}, - "expose": {}, - "onbuild": {}, - } + var ( changes = job.Getenv("changes") newConfig runconfig.Config ) @@ -174,6 +175,13 @@ func (b *BuilderJob) CmdBuildConfig(job *engine.Job) engine.Status { return job.Error(err) } + // ensure that the commands are valid + for _, n := range ast.Children { + if !validCommitCommands[n.Value] { + return job.Errorf("%s is not a valid change command", n.Value) + } + } + builder := &Builder{ Daemon: b.Daemon, Engine: b.Engine, @@ -184,13 +192,8 @@ func (b *BuilderJob) CmdBuildConfig(job *engine.Job) engine.Status { } for i, n := range ast.Children { - cmd := n.Value - if _, ok := validCmd[cmd]; ok { - if err := builder.dispatch(i, n); err != nil { - return job.Error(err) - } - } else { - fmt.Fprintf(builder.ErrStream, "# Skipping serialization of instruction %s\n", strings.ToUpper(cmd)) + if err := builder.dispatch(i, n); err != nil { + return job.Error(err) } } From 5767548fa79342cee94dbb66b9c41671d4a1879f Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Fri, 9 Jan 2015 16:08:26 -0500 Subject: [PATCH 6/8] add docs for commit --change Docker-DCO-1.1-Signed-off-by: Daniel, Dao Quang Minh (github: dqminh) Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: rhatdan) --- docs/man/docker-commit.1.md | 13 +++++++++++++ docs/sources/reference/commandline/cli.md | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index d7619133d0..384d5ef697 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -8,6 +8,7 @@ docker-commit - Create a new image from a container's changes **docker commit** [**-a**|**--author**[=*AUTHOR*]] [**--help**] +[**-c**|**--change**[= []**]] [**-m**|**--message**[=*MESSAGE*]] [**-p**|**--pause**[=*true*]] CONTAINER [REPOSITORY[:TAG]] @@ -19,6 +20,9 @@ Using an existing container's name or ID you can create a new image. **-a**, **--author**="" Author (e.g., "John Hannibal Smith ") +**-c** , **--change**=[] + Apply a modification in Dockerfile format before committing the image. + **--help** Print usage statement @@ -38,8 +42,17 @@ create a new image run docker ps to find the container's ID and then run: # docker commit -m="Added Apache to Fedora base image" \ -a="A D Ministrator" 98bd7fc99854 fedora/fedora_httpd:20 +## Modify configuration settings before committing the image +An existing container was created without the necessary environment variable +DEBUG set to "true". To create a new image based on the container with a +correct DEBUG environment variable, run docker ps to find the container's ID +and then run + + # docker commit -c="ENV DEBUG true" 98bd7fc99854 debug-image + # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.com source material and in June 2014, updated by Sven Dowideit July 2014, updated by Sven Dowideit +Oct 2014, updated by Daniel, Dao Quang Minh diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index 0a277fd8ab..a1d73c9b5a 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -694,6 +694,7 @@ you refer to it on the command line. Create a new image from a container's changes -a, --author="" Author (e.g., "John Hannibal Smith ") + -c, --change=[] Apply a modification in Dockerfile format before committing the image -m, --message="" Commit message -p, --pause=true Pause container during commit @@ -720,6 +721,19 @@ If this behavior is undesired, set the 'p' option to false. REPOSITORY TAG ID CREATED VIRTUAL SIZE SvenDowideit/testimage version3 f5283438590d 16 seconds ago 335.7 MB +#### Commit an existing container with new configurations + + $ sudo docker ps + ID IMAGE COMMAND CREATED STATUS PORTS + c3f279d17e0a ubuntu:12.04 /bin/bash 7 days ago Up 25 hours + 197387f1b436 ubuntu:12.04 /bin/bash 7 days ago Up 25 hours + $ sudo docker inspect -f "{{ .Config.Env }}" c3f279d17e0a + [HOME=/ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin] + $ sudo docker commit --change "ENV DEBUG true" c3f279d17e0a SvenDowideit/testimage:version3 + f5283438590d + $ sudo docker inspect -f "{{ .Config.Env }}" f5283438590d + [HOME=/ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin DEBUG=true] + ## cp Copy files/folders from a container's filesystem to the host From 17abfc3ddc79592753289a8556a343e276fb15b5 Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Thu, 5 Feb 2015 12:26:05 +0100 Subject: [PATCH 7/8] pass --change changes to the import job Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: rhatdan) --- api/client/commands.go | 12 ++++++--- api/server/server.go | 3 ++- builder/job.go | 7 ++--- docs/man/docker-commit.1.md | 13 ++++----- docs/man/docker-import.1.md | 11 ++++++++ docs/sources/reference/commandline/cli.md | 22 ++++++++++++--- graph/import.go | 33 ++++++++++++++++++----- integration-cli/docker_cli_commit_test.go | 8 ++++-- 8 files changed, 84 insertions(+), 25 deletions(-) diff --git a/api/client/commands.go b/api/client/commands.go index f25b6bbb43..2419132911 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -1156,6 +1156,8 @@ func (cli *DockerCli) CmdKill(args ...string) error { func (cli *DockerCli) CmdImport(args ...string) error { cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true) + flChanges := opts.NewListOpts(nil) + cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image.") cmd.Require(flag.Min, 1) utils.ParseFlags(cmd, args, true) @@ -1168,7 +1170,9 @@ func (cli *DockerCli) CmdImport(args ...string) error { v.Set("fromSrc", src) v.Set("repo", repository) - + for _, change := range flChanges.GetAll() { + v.Add("changes", change) + } if cmd.NArg() == 3 { fmt.Fprintf(cli.err, "[DEPRECATED] The format 'URL|- [REPOSITORY [TAG]]' has been deprecated. Please use URL|- [REPOSITORY[:TAG]]\n") v.Set("tag", cmd.Arg(2)) @@ -1703,7 +1707,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error { flComment := cmd.String([]string{"m", "-message"}, "", "Commit message") flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith \")") flChanges := opts.NewListOpts(nil) - cmd.Var(&flChanges, []string{"c", "-change"}, "Apply a modification before committing the image") + cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image.") // FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands") cmd.Require(flag.Max, 2) @@ -1728,7 +1732,9 @@ func (cli *DockerCli) CmdCommit(args ...string) error { v.Set("tag", tag) v.Set("comment", *flComment) v.Set("author", *flAuthor) - v.Set("changes", strings.Join(flChanges.GetAll(), "\n")) + for _, change := range flChanges.GetAll() { + v.Add("changes", change) + } if *flPause != true { v.Set("pause", "0") diff --git a/api/server/server.go b/api/server/server.go index ef6951c691..9407b2397d 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -518,7 +518,7 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit job.Setenv("tag", r.Form.Get("tag")) job.Setenv("author", r.Form.Get("author")) job.Setenv("comment", r.Form.Get("comment")) - job.Setenv("changes", r.Form.Get("changes")) + job.SetenvList("changes", r.Form["changes"]) job.SetenvSubEnv("config", &config) job.Stdout.Add(stdoutBuffer) @@ -571,6 +571,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon } job = eng.Job("import", r.Form.Get("fromSrc"), repo, tag) job.Stdin.Add(r.Body) + job.SetenvList("changes", r.Form["changes"]) } if version.GreaterThan("1.0") { diff --git a/builder/job.go b/builder/job.go index 2e43547735..559335298e 100644 --- a/builder/job.go +++ b/builder/job.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "os/exec" + "strings" "github.com/docker/docker/api" "github.com/docker/docker/builder/parser" @@ -21,7 +22,7 @@ import ( "github.com/docker/docker/utils" ) -// whitelist of commands allowed for a commit +// whitelist of commands allowed for a commit/import var validCommitCommands = map[string]bool{ "entrypoint": true, "cmd": true, @@ -162,7 +163,7 @@ func (b *BuilderJob) CmdBuildConfig(job *engine.Job) engine.Status { } var ( - changes = job.Getenv("changes") + changes = job.GetenvList("changes") newConfig runconfig.Config ) @@ -170,7 +171,7 @@ func (b *BuilderJob) CmdBuildConfig(job *engine.Job) engine.Status { return job.Error(err) } - ast, err := parser.Parse(bytes.NewBufferString(changes)) + ast, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n"))) if err != nil { return job.Error(err) } diff --git a/docs/man/docker-commit.1.md b/docs/man/docker-commit.1.md index 384d5ef697..663dfdc68f 100644 --- a/docs/man/docker-commit.1.md +++ b/docs/man/docker-commit.1.md @@ -21,7 +21,8 @@ Using an existing container's name or ID you can create a new image. Author (e.g., "John Hannibal Smith ") **-c** , **--change**=[] - Apply a modification in Dockerfile format before committing the image. + Apply specified Dockerfile instructions while committing the image + Supported Dockerfile instructions: CMD, ENTRYPOINT, ENV, EXPOSE, ONBUILD, USER, VOLUME, WORKDIR **--help** Print usage statement @@ -42,11 +43,11 @@ create a new image run docker ps to find the container's ID and then run: # docker commit -m="Added Apache to Fedora base image" \ -a="A D Ministrator" 98bd7fc99854 fedora/fedora_httpd:20 -## Modify configuration settings before committing the image -An existing container was created without the necessary environment variable -DEBUG set to "true". To create a new image based on the container with a -correct DEBUG environment variable, run docker ps to find the container's ID -and then run +## Apply specified Dockerfile instructions while committing the image +If an existing container was created without the DEBUG environment +variable set to "true", you can create a new image based on that +container by first getting the container's ID with docker ps and +then running: # docker commit -c="ENV DEBUG true" 98bd7fc99854 debug-image diff --git a/docs/man/docker-import.1.md b/docs/man/docker-import.1.md index 974288c721..d948dec68c 100644 --- a/docs/man/docker-import.1.md +++ b/docs/man/docker-import.1.md @@ -6,9 +6,15 @@ docker-import - Create an empty filesystem image and import the contents of the # SYNOPSIS **docker import** +[**-c**|**--change**[= []**]] [**--help**] URL|- [REPOSITORY[:TAG]] +# OPTIONS +**-c**, **--change**=[] + Apply specified Dockerfile instructions while importing the image + Supported Dockerfile instructions: CMD, ENTRYPOINT, ENV, EXPOSE, ONBUILD, USER, VOLUME, WORKDIR + # DESCRIPTION Create a new filesystem image from the contents of a tarball (`.tar`, `.tar.gz`, `.tgz`, `.bzip`, `.tar.xz`, `.txz`) into it, then optionally tag it. @@ -39,6 +45,11 @@ Import to docker via pipe and stdin: # tar -c . | docker import - exampleimagedir +## Apply specified Dockerfile instructions while importing the image +This example sets the docker image ENV variable DEBUG to true by default. + + # tar -c . | docker import -c="ENV DEBUG true" - exampleimagedir + # HISTORY April 2014, Originally compiled by William Henry (whenry at redhat dot com) based on docker.com source material and internal work. diff --git a/docs/sources/reference/commandline/cli.md b/docs/sources/reference/commandline/cli.md index a1d73c9b5a..1b4a650357 100644 --- a/docs/sources/reference/commandline/cli.md +++ b/docs/sources/reference/commandline/cli.md @@ -694,7 +694,7 @@ you refer to it on the command line. Create a new image from a container's changes -a, --author="" Author (e.g., "John Hannibal Smith ") - -c, --change=[] Apply a modification in Dockerfile format before committing the image + -c, --change=[] Apply specified Dockerfile instructions while committing the image -m, --message="" Commit message -p, --pause=true Pause container during commit @@ -709,7 +709,12 @@ while the image is committed. This reduces the likelihood of encountering data corruption during the process of creating the commit. If this behavior is undesired, set the 'p' option to false. -#### Commit an existing container +The `--change` option will apply `Dockerfile` instructions to the image +that is created. +Supported `Dockerfile` instructions: `CMD`, `ENTRYPOINT`, `ENV`, `EXPOSE`, +`ONBUILD`, `USER`, `VOLUME`, `WORKDIR` + +#### Commit a container $ sudo docker ps ID IMAGE COMMAND CREATED STATUS PORTS @@ -721,7 +726,7 @@ If this behavior is undesired, set the 'p' option to false. REPOSITORY TAG ID CREATED VIRTUAL SIZE SvenDowideit/testimage version3 f5283438590d 16 seconds ago 335.7 MB -#### Commit an existing container with new configurations +#### Commit a container with new configurations $ sudo docker ps ID IMAGE COMMAND CREATED STATUS PORTS @@ -1151,11 +1156,18 @@ NOTE: Docker will warn you if any containers exist that are using these untagged tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it. + -c, --change=[] Apply specified Dockerfile instructions while importing the image + URLs must start with `http` and point to a single file archive (.tar, .tar.gz, .tgz, .bzip, .tar.xz, or .txz) containing a root filesystem. If you would like to import from a local directory or archive, you can use the `-` parameter to take the data from `STDIN`. +The `--change` option will apply `Dockerfile` instructions to the image +that is created. +Supported `Dockerfile` instructions: `CMD`, `ENTRYPOINT`, `ENV`, `EXPOSE`, +`ONBUILD`, `USER`, `VOLUME`, `WORKDIR` + #### Examples **Import from a remote location:** @@ -1174,6 +1186,10 @@ Import to docker via pipe and `STDIN`. $ sudo tar -c . | sudo docker import - exampleimagedir +**Import from a local directory with new configurations:** + + $ sudo tar -c . | sudo docker import --change "ENV DEBUG true" - exampleimagedir + Note the `sudo` in this example – you must preserve the ownership of the files (especially root ownership) during the archiving with tar. If you are not root (or the sudo command) when you diff --git a/graph/import.go b/graph/import.go index a8e8e04b5b..41f4b4f3f1 100644 --- a/graph/import.go +++ b/graph/import.go @@ -1,12 +1,15 @@ package graph import ( + "bytes" + "encoding/json" "net/http" "net/url" log "github.com/Sirupsen/logrus" "github.com/docker/docker/engine" "github.com/docker/docker/pkg/archive" + "github.com/docker/docker/runconfig" "github.com/docker/docker/utils" ) @@ -15,12 +18,14 @@ func (s *TagStore) CmdImport(job *engine.Job) engine.Status { return job.Errorf("Usage: %s SRC REPO [TAG]", job.Name) } var ( - src = job.Args[0] - repo = job.Args[1] - tag string - sf = utils.NewStreamFormatter(job.GetenvBool("json")) - archive archive.ArchiveReader - resp *http.Response + src = job.Args[0] + repo = job.Args[1] + tag string + sf = utils.NewStreamFormatter(job.GetenvBool("json")) + archive archive.ArchiveReader + resp *http.Response + stdoutBuffer = bytes.NewBuffer(nil) + newConfig runconfig.Config ) if len(job.Args) > 2 { tag = job.Args[2] @@ -47,7 +52,21 @@ func (s *TagStore) CmdImport(job *engine.Job) engine.Status { defer progressReader.Close() archive = progressReader } - img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, nil) + + buildConfigJob := job.Eng.Job("build_config") + buildConfigJob.Stdout.Add(stdoutBuffer) + buildConfigJob.Setenv("changes", job.Getenv("changes")) + // FIXME this should be remove when we remove deprecated config param + buildConfigJob.Setenv("config", job.Getenv("config")) + + if err := buildConfigJob.Run(); err != nil { + return job.Error(err) + } + if err := json.NewDecoder(stdoutBuffer).Decode(&newConfig); err != nil { + return job.Error(err) + } + + img, err := s.graph.Create(archive, "", "", "Imported from "+src, "", nil, &newConfig) if err != nil { return job.Error(err) } diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index 95a34b9169..b8bc7bdfc7 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -205,9 +205,13 @@ func TestCommitWithHostBindMount(t *testing.T) { func TestCommitChange(t *testing.T) { defer deleteAllContainers() - cmd(t, "run", "--name", "test", "busybox", "true") - cmd := exec.Command(dockerBinary, "commit", + cmd := exec.Command(dockerBinary, "run", "--name", "test", "busybox", "true") + if _, err := runCommand(cmd); err != nil { + t.Fatal(err) + } + + cmd = exec.Command(dockerBinary, "commit", "--change", "EXPOSE 8080", "--change", "ENV DEBUG true", "test", "test-commit") From 4a9fa9650b154e70d55f750c3674c2d6dd390bef Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Mon, 12 Jan 2015 14:52:44 -0500 Subject: [PATCH 8/8] I am only seeing the values I set Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: rhatdan) --- integration-cli/docker_cli_commit_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index b8bc7bdfc7..8ee26e0723 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -214,6 +214,7 @@ func TestCommitChange(t *testing.T) { cmd = exec.Command(dockerBinary, "commit", "--change", "EXPOSE 8080", "--change", "ENV DEBUG true", + "--change", "ENV test 1", "test", "test-commit") imageId, _, err := runCommandWithOutput(cmd) if err != nil { @@ -224,7 +225,7 @@ func TestCommitChange(t *testing.T) { expected := map[string]string{ "Config.ExposedPorts": "map[8080/tcp:map[]]", - "Config.Env": "[DEBUG=true PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin]", + "Config.Env": "[DEBUG=true test=1]", } for conf, value := range expected {