Skip to content

Commit 17d870b

Browse files
Eric Windischvieux
authored andcommitted
Pause/freeze containers during commit
Initiates a pause before committing a container, adds a pause option to the commit command, defaulting to 'true'. Fixes bug: #6267 Fixes bug: #3675 Docker-DCO-1.1-Signed-off-by: Eric Windisch <ewindisch@docker.com> (github: ewindisch)
1 parent 3f18afc commit 17d870b

File tree

10 files changed

+58
-9
lines changed

10 files changed

+58
-9
lines changed

api/client/commands.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
15381538

15391539
func (cli *DockerCli) CmdCommit(args ...string) error {
15401540
cmd := cli.Subcmd("commit", "[OPTIONS] CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
1541+
flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
15411542
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
15421543
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\")")
15431544
// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
@@ -1569,6 +1570,11 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
15691570
v.Set("tag", tag)
15701571
v.Set("comment", *flComment)
15711572
v.Set("author", *flAuthor)
1573+
1574+
if *flPause != true {
1575+
v.Set("pause", "0")
1576+
}
1577+
15721578
var (
15731579
config *runconfig.Config
15741580
env engine.Env

api/common.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
)
1212

1313
const (
14-
APIVERSION version.Version = "1.12"
14+
APIVERSION version.Version = "1.13"
1515
DEFAULTHTTPHOST = "127.0.0.1"
1616
DEFAULTUNIXSOCKET = "/var/run/docker.sock"
1717
)

api/server/server.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,12 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit
439439
utils.Errorf("%s", err)
440440
}
441441

442+
if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
443+
job.Setenv("pause", "1")
444+
} else {
445+
job.Setenv("pause", r.FormValue("pause"))
446+
}
447+
442448
job.Setenv("repo", r.Form.Get("repo"))
443449
job.Setenv("tag", r.Form.Get("tag"))
444450
job.Setenv("author", r.Form.Get("author"))

daemon/daemon.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,12 @@ func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error
620620

621621
// Commit creates a new filesystem image from the current state of a container.
622622
// The image can optionally be tagged into a repository
623-
func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, config *runconfig.Config) (*image.Image, error) {
624-
// FIXME: freeze the container before copying it to avoid data corruption?
623+
func (daemon *Daemon) Commit(container *Container, repository, tag, comment, author string, pause bool, config *runconfig.Config) (*image.Image, error) {
624+
if pause {
625+
container.Pause()
626+
defer container.Unpause()
627+
}
628+
625629
if err := container.Mount(); err != nil {
626630
return nil, err
627631
}

docs/sources/reference/commandline/cli.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,13 +337,19 @@ schema.
337337

338338
-a, --author="" Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
339339
-m, --message="" Commit message
340+
-p, --pause=true Pause container during commit
340341

341342
It can be useful to commit a container's file changes or settings into a
342343
new image. This allows you debug a container by running an interactive
343344
shell, or to export a working dataset to another server. Generally, it
344345
is better to use Dockerfiles to manage your images in a documented and
345346
maintainable way.
346347

348+
By default, the container being committed and its processes will be paused
349+
during the process of committing the image. This reduces the likelihood of
350+
encountering data corruption during the process of creating the commit.
351+
If this behavior is undesired, set the 'p' option to false.
352+
347353
### Commit an existing container
348354

349355
$ sudo docker ps

integration-cli/docker_cli_commit_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,33 @@ func TestCommitAfterContainerIsDone(t *testing.T) {
3434
logDone("commit - echo foo and commit the image")
3535
}
3636

37+
func TestCommitWithoutPause(t *testing.T) {
38+
runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "echo", "foo")
39+
out, _, _, err := runCommandWithStdoutStderr(runCmd)
40+
errorOut(err, t, fmt.Sprintf("failed to run container: %v %v", out, err))
41+
42+
cleanedContainerID := stripTrailingCharacters(out)
43+
44+
waitCmd := exec.Command(dockerBinary, "wait", cleanedContainerID)
45+
_, _, err = runCommandWithOutput(waitCmd)
46+
errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
47+
48+
commitCmd := exec.Command(dockerBinary, "commit", "-p", "false", cleanedContainerID)
49+
out, _, err = runCommandWithOutput(commitCmd)
50+
errorOut(err, t, fmt.Sprintf("failed to commit container to image: %v %v", out, err))
51+
52+
cleanedImageID := stripTrailingCharacters(out)
53+
54+
inspectCmd := exec.Command(dockerBinary, "inspect", cleanedImageID)
55+
out, _, err = runCommandWithOutput(inspectCmd)
56+
errorOut(err, t, fmt.Sprintf("failed to inspect image: %v %v", out, err))
57+
58+
deleteContainer(cleanedContainerID)
59+
deleteImages(cleanedImageID)
60+
61+
logDone("commit - echo foo and commit the image")
62+
}
63+
3764
func TestCommitNewFile(t *testing.T) {
3865
cmd := exec.Command(dockerBinary, "run", "--name", "commiter", "busybox", "/bin/sh", "-c", "echo koye > /foo")
3966
if _, err := runCommand(cmd); err != nil {

integration/container_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
421421
t.Errorf("Container shouldn't be running")
422422
}
423423

424-
img, err := r.Commit(container1, "", "", "unit test commited image", "", nil)
424+
img, err := r.Commit(container1, "", "", "unit test commited image", "", true, nil)
425425
if err != nil {
426426
t.Error(err)
427427
}
@@ -447,7 +447,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
447447
t.Errorf("Container shouldn't be running")
448448
}
449449

450-
img2, err := r.Commit(container2, "", "", "unit test commited image", "", nil)
450+
img2, err := r.Commit(container2, "", "", "unit test commited image", "", true, nil)
451451
if err != nil {
452452
t.Error(err)
453453
}
@@ -481,7 +481,7 @@ func TestCopyVolumeContent(t *testing.T) {
481481
t.Errorf("Container shouldn't be running")
482482
}
483483

484-
img, err := r.Commit(container1, "", "", "unit test commited image", "", nil)
484+
img, err := r.Commit(container1, "", "", "unit test commited image", "", true, nil)
485485
if err != nil {
486486
t.Error(err)
487487
}

integration/runtime_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ func TestDaemonCreate(t *testing.T) {
334334
}
335335
container, _, err = daemon.Create(config, "")
336336

337-
_, err = daemon.Commit(container, "testrepo", "testtag", "", "", config)
337+
_, err = daemon.Commit(container, "testrepo", "testtag", "", "", true, config)
338338
if err != nil {
339339
t.Error(err)
340340
}

server/buildfile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
752752
autoConfig := *b.config
753753
autoConfig.Cmd = autoCmd
754754
// Commit the container
755-
image, err := b.daemon.Commit(container, "", "", "", b.maintainer, &autoConfig)
755+
image, err := b.daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig)
756756
if err != nil {
757757
return err
758758
}

server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ func (srv *Server) ContainerCommit(job *engine.Job) engine.Status {
10381038
return job.Error(err)
10391039
}
10401040

1041-
img, err := srv.daemon.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &newConfig)
1041+
img, err := srv.daemon.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), job.GetenvBool("pause"), &newConfig)
10421042
if err != nil {
10431043
return job.Error(err)
10441044
}

0 commit comments

Comments
 (0)