mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
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:
@ -46,6 +46,7 @@ func init() {
|
|||||||
flags.BoolVarP(&checkpointCommand.All, "all", "a", false, "Checkpoint all running containers")
|
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.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.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)
|
markFlagHiddenForRemoteClient("latest", flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@ type CheckpointValues struct {
|
|||||||
All bool
|
All bool
|
||||||
Latest bool
|
Latest bool
|
||||||
Export string
|
Export string
|
||||||
|
IgnoreRootfs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommitValues struct {
|
type CommitValues struct {
|
||||||
@ -433,6 +434,7 @@ type RestoreValues struct {
|
|||||||
TcpEstablished bool
|
TcpEstablished bool
|
||||||
Import string
|
Import string
|
||||||
Name string
|
Name string
|
||||||
|
IgnoreRootfs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type RmValues struct {
|
type RmValues struct {
|
||||||
|
@ -45,6 +45,7 @@ func init() {
|
|||||||
flags.BoolVar(&restoreCommand.TcpEstablished, "tcp-established", false, "Restore a container with established TCP connections")
|
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.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.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)
|
markFlagHiddenForRemoteClient("latest", flags)
|
||||||
}
|
}
|
||||||
@ -60,6 +61,10 @@ func restoreCmd(c *cliconfig.RestoreValues, cmd *cobra.Command) error {
|
|||||||
}
|
}
|
||||||
defer runtime.DeferredShutdown(false)
|
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 != "" {
|
if c.Import == "" && c.Name != "" {
|
||||||
return errors.Errorf("--name can only be used with --import")
|
return errors.Errorf("--name can only be used with --import")
|
||||||
}
|
}
|
||||||
|
@ -758,6 +758,7 @@ _podman_container_checkpoint() {
|
|||||||
-R
|
-R
|
||||||
--leave-running
|
--leave-running
|
||||||
--tcp-established
|
--tcp-established
|
||||||
|
--ignore-rootfs
|
||||||
"
|
"
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
-e|--export)
|
-e|--export)
|
||||||
@ -870,6 +871,7 @@ _podman_container_restore() {
|
|||||||
-l
|
-l
|
||||||
--latest
|
--latest
|
||||||
--tcp-established
|
--tcp-established
|
||||||
|
--ignore-rootfs
|
||||||
"
|
"
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
-i|--import)
|
-i|--import)
|
||||||
|
@ -42,7 +42,15 @@ connections.
|
|||||||
|
|
||||||
Export the checkpoint to a tar.gz file. The exported checkpoint can be used
|
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
|
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
|
## EXAMPLE
|
||||||
|
|
||||||
|
@ -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
|
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**.
|
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
|
## EXAMPLE
|
||||||
|
|
||||||
podman container restore mywebserver
|
podman container restore mywebserver
|
||||||
|
@ -799,6 +799,9 @@ type ContainerCheckpointOptions struct {
|
|||||||
// checkpoint archive a new name should be used for the
|
// checkpoint archive a new name should be used for the
|
||||||
// restored container
|
// restored container
|
||||||
Name string
|
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
|
// Checkpoint checkpoints a container
|
||||||
|
@ -510,41 +510,44 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
|
|||||||
return nil
|
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) {
|
if (len(c.config.NamedVolumes) > 0) || (len(c.Dependencies()) > 0) {
|
||||||
return errors.Errorf("Cannot export checkpoints of containers with named volumes or dependencies")
|
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)
|
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
|
// Get root file-system changes included in the checkpoint archive
|
||||||
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
|
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
|
||||||
rootfsDiffFile, err := os.Create(rootfsDiffPath)
|
if !ignoreRootfs {
|
||||||
if err != nil {
|
rootfsDiffFile, err := os.Create(rootfsDiffPath)
|
||||||
return errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath)
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath)
|
||||||
|
}
|
||||||
|
tarStream, err := c.runtime.GetDiffTarStream("", c.ID())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(rootfsDiffFile, tarStream)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath)
|
||||||
|
}
|
||||||
|
tarStream.Close()
|
||||||
|
rootfsDiffFile.Close()
|
||||||
|
includeFiles = append(includeFiles, "rootfs-diff.tar")
|
||||||
}
|
}
|
||||||
tarStream, err := c.runtime.GetDiffTarStream("", c.ID())
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath)
|
|
||||||
}
|
|
||||||
_, err = io.Copy(rootfsDiffFile, tarStream)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath)
|
|
||||||
}
|
|
||||||
tarStream.Close()
|
|
||||||
rootfsDiffFile.Close()
|
|
||||||
|
|
||||||
|
|
||||||
input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
|
input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
|
||||||
Compression: archive.Gzip,
|
Compression: archive.Gzip,
|
||||||
IncludeSourceDir: true,
|
IncludeSourceDir: true,
|
||||||
IncludeFiles: []string{
|
IncludeFiles: includeFiles,
|
||||||
"checkpoint",
|
|
||||||
"artifacts",
|
|
||||||
"ctr.log",
|
|
||||||
"config.dump",
|
|
||||||
"spec.dump",
|
|
||||||
"rootfs-diff.tar",
|
|
||||||
"network.status"},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -627,7 +630,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
|
|||||||
}
|
}
|
||||||
|
|
||||||
if options.TargetFile != "" {
|
if options.TargetFile != "" {
|
||||||
if err = c.exportCheckpoint(options.TargetFile); err != nil {
|
if err = c.exportCheckpoint(options.TargetFile, options.IgnoreRootfs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -816,17 +819,19 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Before actually restarting the container, apply the root file-system changes
|
// Before actually restarting the container, apply the root file-system changes
|
||||||
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
|
if !options.IgnoreRootfs {
|
||||||
if _, err := os.Stat(rootfsDiffPath); err == nil {
|
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
|
||||||
// Only do this if a rootfs-diff.tar actually exists
|
if _, err := os.Stat(rootfsDiffPath); err == nil {
|
||||||
rootfsDiffFile, err := os.Open(rootfsDiffPath)
|
// Only do this if a rootfs-diff.tar actually exists
|
||||||
if err != nil {
|
rootfsDiffFile, err := os.Open(rootfsDiffPath)
|
||||||
return errors.Wrapf(err, "Failed to open root file-system diff file %s", rootfsDiffPath)
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Failed to open root file-system diff file %s", rootfsDiffPath)
|
||||||
|
}
|
||||||
|
if err := c.runtime.ApplyDiffTarStream(c.ID(), rootfsDiffFile); err != nil {
|
||||||
|
return errors.Wrapf(err, "Failed to apply root file-system diff file %s", rootfsDiffPath)
|
||||||
|
}
|
||||||
|
rootfsDiffFile.Close()
|
||||||
}
|
}
|
||||||
if err := c.runtime.ApplyDiffTarStream(c.ID(), rootfsDiffFile); err != nil {
|
|
||||||
return errors.Wrapf(err, "Failed to apply root file-system diff file %s", rootfsDiffPath)
|
|
||||||
}
|
|
||||||
rootfsDiffFile.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.ociRuntime.createContainer(c, c.config.CgroupParent, &options); err != nil {
|
if err := c.ociRuntime.createContainer(c, c.config.CgroupParent, &options); err != nil {
|
||||||
|
@ -524,6 +524,10 @@ func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues) error {
|
|||||||
KeepRunning: c.LeaveRunning,
|
KeepRunning: c.LeaveRunning,
|
||||||
TCPEstablished: c.TcpEstablished,
|
TCPEstablished: c.TcpEstablished,
|
||||||
TargetFile: c.Export,
|
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 {
|
if c.All {
|
||||||
containers, err = r.Runtime.GetRunningContainers()
|
containers, err = r.Runtime.GetRunningContainers()
|
||||||
@ -560,6 +564,7 @@ func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues)
|
|||||||
TCPEstablished: c.TcpEstablished,
|
TCPEstablished: c.TcpEstablished,
|
||||||
TargetFile: c.Import,
|
TargetFile: c.Import,
|
||||||
Name: c.Name,
|
Name: c.Name,
|
||||||
|
IgnoreRootfs: c.IgnoreRootfs,
|
||||||
}
|
}
|
||||||
|
|
||||||
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
|
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
|
||||||
|
@ -668,6 +668,9 @@ func (r *LocalRuntime) Checkpoint(c *cliconfig.CheckpointValues) error {
|
|||||||
if c.Export != "" {
|
if c.Export != "" {
|
||||||
return errors.New("the remote client does not support exporting checkpoints")
|
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
|
var lastError error
|
||||||
ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
|
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 != "" {
|
if c.Import != "" {
|
||||||
return errors.New("the remote client does not support importing checkpoints")
|
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
|
var lastError error
|
||||||
ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
|
ids, err := iopodman.GetContainersByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
|
||||||
|
Reference in New Issue
Block a user