Added option to keep containers running after checkpointing

CRIU supports to leave processes running after checkpointing:

  -R|--leave-running    leave tasks in running state after checkpoint

runc also support to leave containers running after checkpointing:

   --leave-running      leave the process running after checkpointing

With this commit the support to leave a container running after
checkpointing is brought to Podman:

   --leave-running, -R  leave the container running after writing checkpoint to disk

Now it is possible to checkpoint a container at some point in time
without stopping the container. This can be used to rollback the
container to an early state:

$ podman run --tmpfs /tmp --name podman-criu-test -d docker://docker.io/yovfiatbeb/podman-criu-test
$ curl 10.88.64.253:8080/examples/servlets/servlet/HelloWorldExample
3
$ podman container checkpoint -R -l
$ curl 10.88.64.253:8080/examples/servlets/servlet/HelloWorldExample
4
$ curl 10.88.64.253:8080/examples/servlets/servlet/HelloWorldExample
5
$ podman stop -l
$ podman container restore -l
$ curl 10.88.64.253:8080/examples/servlets/servlet/HelloWorldExample
4

So after checkpointing the container kept running and was stopped after
some time. Restoring this container will restore the state right at the
checkpoint.

Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
Adrian Reber
2018-11-20 15:34:15 +00:00
committed by Adrian Reber
parent ff47a4c2d5
commit b0572d6229
4 changed files with 27 additions and 10 deletions

View File

@ -23,6 +23,10 @@ var (
Name: "keep, k",
Usage: "keep all temporary checkpoint files",
},
cli.BoolFlag{
Name: "leave-running, R",
Usage: "leave the container running after writing checkpoint to disk",
},
cli.BoolFlag{
Name: "all, a",
Usage: "checkpoint all running containers",
@ -52,6 +56,7 @@ func checkpointCmd(c *cli.Context) error {
options := libpod.ContainerCheckpointOptions{
Keep: c.Bool("keep"),
KeepRunning: c.Bool("leave-running"),
}
if err := checkAllAndLatest(c); err != nil {

View File

@ -834,6 +834,7 @@ func (c *Container) Refresh(ctx context.Context) error {
// for checkpointing to corresponding functions
type ContainerCheckpointOptions struct {
Keep bool
KeepRunning bool
}
// Checkpoint checkpoints a container

View File

@ -440,7 +440,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
if c.state.State != ContainerStateRunning {
return errors.Wrapf(ErrCtrStateInvalid, "%q is not running, cannot checkpoint", c.state.State)
}
if err := c.runtime.ociRuntime.checkpointContainer(c); err != nil {
if err := c.runtime.ociRuntime.checkpointContainer(c, options); err != nil {
return err
}
@ -457,12 +457,14 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
logrus.Debugf("Checkpointed container %s", c.ID())
if !options.KeepRunning {
c.state.State = ContainerStateStopped
// Cleanup Storage and Network
if err := c.cleanup(ctx); err != nil {
return err
}
}
if !options.Keep {
// Remove log file

View File

@ -844,13 +844,22 @@ func (r *OCIRuntime) execStopContainer(ctr *Container, timeout uint) error {
}
// checkpointContainer checkpoints the given container
func (r *OCIRuntime) checkpointContainer(ctr *Container) error {
func (r *OCIRuntime) checkpointContainer(ctr *Container, options ContainerCheckpointOptions) error {
// imagePath is used by CRIU to store the actual checkpoint files
imagePath := ctr.CheckpointPath()
// workPath will be used to store dump.log and stats-dump
workPath := ctr.bundlePath()
logrus.Debugf("Writing checkpoint to %s", imagePath)
logrus.Debugf("Writing checkpoint logs to %s", workPath)
return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, "checkpoint",
"--image-path", imagePath, "--work-path", workPath, ctr.ID())
args := []string{}
args = append(args, "checkpoint")
args = append(args, "--image-path")
args = append(args, imagePath)
args = append(args, "--work-path")
args = append(args, workPath)
if options.KeepRunning {
args = append(args, "--leave-running")
}
args = append(args, ctr.ID())
return utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...)
}