aboutsummaryrefslogtreecommitdiff
path: root/libpod/runtime_ctr.go
diff options
context:
space:
mode:
authorAdrian Reber <areber@redhat.com>2019-02-06 19:22:46 +0000
committerAdrian Reber <areber@redhat.com>2019-06-03 22:05:12 +0200
commit0028578b432d207e1e5b313c76e587eae275bdac (patch)
treef26e1c867f72d304c84ba86109a252902a50048e /libpod/runtime_ctr.go
parenta05cfd24bb6929ca4431f9169b9b215b0d43d91e (diff)
downloadpodman-0028578b432d207e1e5b313c76e587eae275bdac.tar.gz
podman-0028578b432d207e1e5b313c76e587eae275bdac.tar.bz2
podman-0028578b432d207e1e5b313c76e587eae275bdac.zip
Added support to migrate containers
This commit adds an option to the checkpoint command to export a checkpoint into a tar.gz file as well as importing a checkpoint tar.gz file during restore. With all checkpoint artifacts in one file it is possible to easily transfer a checkpoint and thus enabling container migration in Podman. With the following steps it is possible to migrate a running container from one system (source) to another (destination). Source system: * podman container checkpoint -l -e /tmp/checkpoint.tar.gz * scp /tmp/checkpoint.tar.gz destination:/tmp Destination system: * podman pull 'container-image-as-on-source-system' * podman container restore -i /tmp/checkpoint.tar.gz The exported tar.gz file contains the checkpoint image as created by CRIU and a few additional JSON files describing the state of the checkpointed container. Now the container is running on the destination system with the same state just as during checkpointing. If the container is kept running on the source system with the checkpoint flag '-R', the result will be that the same container is running on two different hosts. Signed-off-by: Adrian Reber <areber@redhat.com>
Diffstat (limited to 'libpod/runtime_ctr.go')
-rw-r--r--libpod/runtime_ctr.go60
1 files changed, 51 insertions, 9 deletions
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 0c8d3edab..9d0bbf7e8 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/storage"
"github.com/containers/storage/pkg/stringid"
spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-tools/generate"
opentracing "github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -34,7 +35,7 @@ type CtrCreateOption func(*Container) error
// A true return will include the container, a false return will exclude it.
type ContainerFilter func(*Container) bool
-// NewContainer creates a new container from a given OCI config
+// NewContainer creates a new container from a given OCI config.
func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (c *Container, err error) {
r.lock.Lock()
defer r.lock.Unlock()
@@ -44,20 +45,38 @@ func (r *Runtime) NewContainer(ctx context.Context, rSpec *spec.Spec, options ..
return r.newContainer(ctx, rSpec, options...)
}
-func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (c *Container, err error) {
- span, _ := opentracing.StartSpanFromContext(ctx, "newContainer")
- span.SetTag("type", "runtime")
- defer span.Finish()
+// RestoreContainer re-creates a container from an imported checkpoint
+func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config *ContainerConfig) (c *Container, err error) {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+ if !r.valid {
+ return nil, ErrRuntimeStopped
+ }
+ ctr, err := r.initContainerVariables(rSpec, config)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error initializing container variables")
+ }
+ return r.setupContainer(ctx, ctr, true)
+}
+
+func (r *Runtime) initContainerVariables(rSpec *spec.Spec, config *ContainerConfig) (c *Container, err error) {
if rSpec == nil {
return nil, errors.Wrapf(ErrInvalidArg, "must provide a valid runtime spec to create container")
}
-
ctr := new(Container)
ctr.config = new(ContainerConfig)
ctr.state = new(ContainerState)
- ctr.config.ID = stringid.GenerateNonCryptoID()
+ if config == nil {
+ ctr.config.ID = stringid.GenerateNonCryptoID()
+ ctr.config.ShmSize = DefaultShmSize
+ } else {
+ // This is a restore from an imported checkpoint
+ if err := JSONDeepCopy(config, ctr.config); err != nil {
+ return nil, errors.Wrapf(err, "error copying container config for restore")
+ }
+ }
ctr.config.Spec = new(spec.Spec)
if err := JSONDeepCopy(rSpec, ctr.config.Spec); err != nil {
@@ -65,8 +84,6 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
}
ctr.config.CreatedTime = time.Now()
- ctr.config.ShmSize = DefaultShmSize
-
ctr.state.BindMounts = make(map[string]string)
ctr.config.StopTimeout = CtrRemoveTimeout
@@ -80,12 +97,29 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
}
ctr.runtime = r
+
+ return ctr, nil
+}
+
+func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ...CtrCreateOption) (c *Container, err error) {
+ span, _ := opentracing.StartSpanFromContext(ctx, "newContainer")
+ span.SetTag("type", "runtime")
+ defer span.Finish()
+
+ ctr, err := r.initContainerVariables(rSpec, nil)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error initializing container variables")
+ }
+
for _, option := range options {
if err := option(ctr); err != nil {
return nil, errors.Wrapf(err, "error running container create option")
}
}
+ return r.setupContainer(ctx, ctr, false)
+}
+func (r *Runtime) setupContainer(ctx context.Context, ctr *Container, restore bool) (c *Container, err error) {
// Allocate a lock for the container
lock, err := r.lockManager.AllocateLock()
if err != nil {
@@ -154,6 +188,14 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
return nil, errors.Wrapf(ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.CgroupManager)
}
+ if restore {
+ // Remove information about /dev/shm mount
+ // for new container from imported checkpoint
+ g := generate.Generator{Config: ctr.config.Spec}
+ g.RemoveMount("/dev/shm")
+ ctr.config.ShmDir = ""
+ }
+
// Set up storage for the container
if err := ctr.setupStorage(ctx); err != nil {
return nil, err