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)
| ... | ... |
@@ -1538,6 +1538,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
| 1538 | 1538 |
|
| 1539 | 1539 |
func (cli *DockerCli) CmdCommit(args ...string) error {
|
| 1540 | 1540 |
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")
|
|
| 1541 | 1542 |
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
|
| 1542 | 1543 |
flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (eg. \"John Hannibal Smith <hannibal@a-team.com>\")")
|
| 1543 | 1544 |
// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands. |
| ... | ... |
@@ -1569,6 +1570,11 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
|
| 1569 | 1569 |
v.Set("tag", tag)
|
| 1570 | 1570 |
v.Set("comment", *flComment)
|
| 1571 | 1571 |
v.Set("author", *flAuthor)
|
| 1572 |
+ |
|
| 1573 |
+ if *flPause != true {
|
|
| 1574 |
+ v.Set("pause", "0")
|
|
| 1575 |
+ } |
|
| 1576 |
+ |
|
| 1572 | 1577 |
var ( |
| 1573 | 1578 |
config *runconfig.Config |
| 1574 | 1579 |
env engine.Env |
| ... | ... |
@@ -439,6 +439,12 @@ func postCommit(eng *engine.Engine, version version.Version, w http.ResponseWrit |
| 439 | 439 |
utils.Errorf("%s", err)
|
| 440 | 440 |
} |
| 441 | 441 |
|
| 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 |
+ |
|
| 442 | 448 |
job.Setenv("repo", r.Form.Get("repo"))
|
| 443 | 449 |
job.Setenv("tag", r.Form.Get("tag"))
|
| 444 | 450 |
job.Setenv("author", r.Form.Get("author"))
|
| ... | ... |
@@ -620,8 +620,12 @@ func (daemon *Daemon) createRootfs(container *Container, img *image.Image) error |
| 620 | 620 |
|
| 621 | 621 |
// Commit creates a new filesystem image from the current state of a container. |
| 622 | 622 |
// 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 |
+ |
|
| 625 | 629 |
if err := container.Mount(); err != nil {
|
| 626 | 630 |
return nil, err |
| 627 | 631 |
} |
| ... | ... |
@@ -337,6 +337,7 @@ schema. |
| 337 | 337 |
|
| 338 | 338 |
-a, --author="" Author (e.g., "John Hannibal Smith <hannibal@a-team.com>") |
| 339 | 339 |
-m, --message="" Commit message |
| 340 |
+ -p, --pause=true Pause container during commit |
|
| 340 | 341 |
|
| 341 | 342 |
It can be useful to commit a container's file changes or settings into a |
| 342 | 343 |
new image. This allows you debug a container by running an interactive |
| ... | ... |
@@ -344,6 +345,11 @@ shell, or to export a working dataset to another server. Generally, it |
| 344 | 344 |
is better to use Dockerfiles to manage your images in a documented and |
| 345 | 345 |
maintainable way. |
| 346 | 346 |
|
| 347 |
+By default, the container being committed and its processes will be paused |
|
| 348 |
+during the process of committing the image. This reduces the likelihood of |
|
| 349 |
+encountering data corruption during the process of creating the commit. |
|
| 350 |
+If this behavior is undesired, set the 'p' option to false. |
|
| 351 |
+ |
|
| 347 | 352 |
### Commit an existing container |
| 348 | 353 |
|
| 349 | 354 |
$ sudo docker ps |
| ... | ... |
@@ -34,6 +34,33 @@ func TestCommitAfterContainerIsDone(t *testing.T) {
|
| 34 | 34 |
logDone("commit - echo foo and commit the image")
|
| 35 | 35 |
} |
| 36 | 36 |
|
| 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 |
+ |
|
| 37 | 64 |
func TestCommitNewFile(t *testing.T) {
|
| 38 | 65 |
cmd := exec.Command(dockerBinary, "run", "--name", "commiter", "busybox", "/bin/sh", "-c", "echo koye > /foo") |
| 39 | 66 |
if _, err := runCommand(cmd); err != nil {
|
| ... | ... |
@@ -421,7 +421,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
|
| 421 | 421 |
t.Errorf("Container shouldn't be running")
|
| 422 | 422 |
} |
| 423 | 423 |
|
| 424 |
- img, err := r.Commit(container1, "", "", "unit test commited image", "", nil) |
|
| 424 |
+ img, err := r.Commit(container1, "", "", "unit test commited image", "", true, nil) |
|
| 425 | 425 |
if err != nil {
|
| 426 | 426 |
t.Error(err) |
| 427 | 427 |
} |
| ... | ... |
@@ -447,7 +447,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
|
| 447 | 447 |
t.Errorf("Container shouldn't be running")
|
| 448 | 448 |
} |
| 449 | 449 |
|
| 450 |
- img2, err := r.Commit(container2, "", "", "unit test commited image", "", nil) |
|
| 450 |
+ img2, err := r.Commit(container2, "", "", "unit test commited image", "", true, nil) |
|
| 451 | 451 |
if err != nil {
|
| 452 | 452 |
t.Error(err) |
| 453 | 453 |
} |
| ... | ... |
@@ -481,7 +481,7 @@ func TestCopyVolumeContent(t *testing.T) {
|
| 481 | 481 |
t.Errorf("Container shouldn't be running")
|
| 482 | 482 |
} |
| 483 | 483 |
|
| 484 |
- img, err := r.Commit(container1, "", "", "unit test commited image", "", nil) |
|
| 484 |
+ img, err := r.Commit(container1, "", "", "unit test commited image", "", true, nil) |
|
| 485 | 485 |
if err != nil {
|
| 486 | 486 |
t.Error(err) |
| 487 | 487 |
} |
| ... | ... |
@@ -334,7 +334,7 @@ func TestDaemonCreate(t *testing.T) {
|
| 334 | 334 |
} |
| 335 | 335 |
container, _, err = daemon.Create(config, "") |
| 336 | 336 |
|
| 337 |
- _, err = daemon.Commit(container, "testrepo", "testtag", "", "", config) |
|
| 337 |
+ _, err = daemon.Commit(container, "testrepo", "testtag", "", "", true, config) |
|
| 338 | 338 |
if err != nil {
|
| 339 | 339 |
t.Error(err) |
| 340 | 340 |
} |
| ... | ... |
@@ -752,7 +752,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
|
| 752 | 752 |
autoConfig := *b.config |
| 753 | 753 |
autoConfig.Cmd = autoCmd |
| 754 | 754 |
// Commit the container |
| 755 |
- image, err := b.daemon.Commit(container, "", "", "", b.maintainer, &autoConfig) |
|
| 755 |
+ image, err := b.daemon.Commit(container, "", "", "", b.maintainer, true, &autoConfig) |
|
| 756 | 756 |
if err != nil {
|
| 757 | 757 |
return err |
| 758 | 758 |
} |
| ... | ... |
@@ -1038,7 +1038,7 @@ func (srv *Server) ContainerCommit(job *engine.Job) engine.Status {
|
| 1038 | 1038 |
return job.Error(err) |
| 1039 | 1039 |
} |
| 1040 | 1040 |
|
| 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)
|
|
| 1042 | 1042 |
if err != nil {
|
| 1043 | 1043 |
return job.Error(err) |
| 1044 | 1044 |
} |