Add --ignore-rootfs option for checkpoint/restore

The newly added functionality to include the container's root
file-system changes into the checkpoint archive can now be explicitly
disabled. Either during checkpoint or during restore.

If a container changes a lot of files during its runtime it might be
more effective to migrated the root file-system changes in some other
way and to not needlessly increase the size of the checkpoint archive.

If a checkpoint archive does not contain the root file-system changes
information it will automatically be skipped. If the root file-system
changes are part of the checkpoint archive it is also possible to tell
Podman to ignore these changes.

Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
Adrian Reber
2019-06-27 07:56:39 +00:00
parent 1a32074884
commit 05549e8b29
10 changed files with 79 additions and 35 deletions

View File

@ -46,6 +46,7 @@ func init() {
flags.BoolVarP(&checkpointCommand.All, "all", "a", false, "Checkpoint all running containers")
flags.BoolVarP(&checkpointCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.StringVarP(&checkpointCommand.Export, "export", "e", "", "Export the checkpoint image to a tar.gz")
flags.BoolVar(&checkpointCommand.IgnoreRootfs, "ignore-rootfs", false, "Do not include root file-system changes when exporting")
markFlagHiddenForRemoteClient("latest", flags)
}

View File

@ -92,6 +92,7 @@ type CheckpointValues struct {
All bool
Latest bool
Export string
IgnoreRootfs bool
}
type CommitValues struct {
@ -433,6 +434,7 @@ type RestoreValues struct {
TcpEstablished bool
Import string
Name string
IgnoreRootfs bool
}
type RmValues struct {

View File

@ -45,6 +45,7 @@ func init() {
flags.BoolVar(&restoreCommand.TcpEstablished, "tcp-established", false, "Restore a container with established TCP connections")
flags.StringVarP(&restoreCommand.Import, "import", "i", "", "Restore from exported checkpoint archive (tar.gz)")
flags.StringVarP(&restoreCommand.Name, "name", "n", "", "Specify new name for container restored from exported checkpoint (only works with --import)")
flags.BoolVar(&restoreCommand.IgnoreRootfs, "ignore-rootfs", false, "Do not apply root file-system changes when importing from exported checkpoint")
markFlagHiddenForRemoteClient("latest", flags)
}
@ -60,6 +61,10 @@ func restoreCmd(c *cliconfig.RestoreValues, cmd *cobra.Command) error {
}
defer runtime.DeferredShutdown(false)
if c.Import == "" && c.IgnoreRootfs {
return errors.Errorf("--ignore-rootfs can only be used with --import")
}
if c.Import == "" && c.Name != "" {
return errors.Errorf("--name can only be used with --import")
}

View File

@ -758,6 +758,7 @@ _podman_container_checkpoint() {
-R
--leave-running
--tcp-established
--ignore-rootfs
"
case "$prev" in
-e|--export)
@ -870,6 +871,7 @@ _podman_container_restore() {
-l
--latest
--tcp-established
--ignore-rootfs
"
case "$prev" in
-i|--import)

View File

@ -42,7 +42,15 @@ connections.
Export the checkpoint to a tar.gz file. The exported checkpoint can be used
to import the container on another system and thus enabling container live
migration.
migration. This checkpoint archive also includes all changes to the container's
root file-system, if not explicitly disabled using **--ignore-rootfs**
**--ignore-rootfs**
This only works in combination with **--export, -e**. If a checkpoint is
exported to a tar.gz file it is possible with the help of **--ignore-rootfs**
to explicitly disable including changes to the root file-system into
the checkpoint archive file.
## EXAMPLE

View File

@ -60,6 +60,13 @@ address to the container it was using before checkpointing as each IP address ca
be used once and the restored container will have another IP address. This also means
that **--name, -n** cannot be used in combination with **--tcp-established**.
**--ignore-rootfs**
This is only available in combination with **--import, -i**. If a container is restored
from a checkpoint tar.gz file it is possible that it also contains all root file-system
changes. With **--ignore-rootfs** it is possible to explicitly disable applying these
root file-system changes to the restored container.
## EXAMPLE
podman container restore mywebserver

View File

@ -799,6 +799,9 @@ type ContainerCheckpointOptions struct {
// checkpoint archive a new name should be used for the
// restored container
Name string
// IgnoreRootfs tells the API to not export changes to
// the container's root file-system (or to not import)
IgnoreRootfs bool
}
// Checkpoint checkpoints a container

View File

@ -510,14 +510,23 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
return nil
}
func (c *Container) exportCheckpoint(dest string) (err error) {
func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) (err error) {
if (len(c.config.NamedVolumes) > 0) || (len(c.Dependencies()) > 0) {
return errors.Errorf("Cannot export checkpoints of containers with named volumes or dependencies")
}
logrus.Debugf("Exporting checkpoint image of container %q to %q", c.ID(), dest)
includeFiles := []string{
"checkpoint",
"artifacts",
"ctr.log",
"config.dump",
"spec.dump",
"network.status"}
// Get root file-system changes included in the checkpoint archive
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
if !ignoreRootfs {
rootfsDiffFile, err := os.Create(rootfsDiffPath)
if err != nil {
return errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath)
@ -532,19 +541,13 @@ func (c *Container) exportCheckpoint(dest string) (err error) {
}
tarStream.Close()
rootfsDiffFile.Close()
includeFiles = append(includeFiles, "rootfs-diff.tar")
}
input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
Compression: archive.Gzip,
IncludeSourceDir: true,
IncludeFiles: []string{
"checkpoint",
"artifacts",
"ctr.log",
"config.dump",
"spec.dump",
"rootfs-diff.tar",
"network.status"},
IncludeFiles: includeFiles,
})
if err != nil {
@ -627,7 +630,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
}
if options.TargetFile != "" {
if err = c.exportCheckpoint(options.TargetFile); err != nil {
if err = c.exportCheckpoint(options.TargetFile, options.IgnoreRootfs); err != nil {
return err
}
}
@ -816,6 +819,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
// Before actually restarting the container, apply the root file-system changes
if !options.IgnoreRootfs {
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
if _, err := os.Stat(rootfsDiffPath); err == nil {
// Only do this if a rootfs-diff.tar actually exists
@ -828,6 +832,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
rootfsDiffFile.Close()
}
}
if err := c.ociRuntime.createContainer(c, c.config.CgroupParent, &options); err != nil {
return err

View File

@ -524,6 +524,10 @@ func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues) error {
KeepRunning: c.LeaveRunning,
TCPEstablished: c.TcpEstablished,
TargetFile: c.Export,
IgnoreRootfs: c.IgnoreRootfs,
}
if c.Export == "" && c.IgnoreRootfs {
return errors.Errorf("--ignore-rootfs can only be used with --export")
}
if c.All {
containers, err = r.Runtime.GetRunningContainers()
@ -560,6 +564,7 @@ func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues)
TCPEstablished: c.TcpEstablished,
TargetFile: c.Import,
Name: c.Name,
IgnoreRootfs: c.IgnoreRootfs,
}
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {

View File

@ -668,6 +668,9 @@ func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues) error {
if c.Export != "" {
return errors.New("the remote client does not support exporting checkpoints")
}
if c.IgnoreRootfs {
return errors.New("the remote client does not support --ignore-rootfs")
}
var lastError error
ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
@ -708,6 +711,9 @@ func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues)
if c.Import != "" {
return errors.New("the remote client does not support importing checkpoints")
}
if c.IgnoreRootfs {
return errors.New("the remote client does not support --ignore-rootfs")
}
var lastError error
ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)