Merge pull request #10567 from adrianreber/2021-06-04-compress
Add support for selectable checkpoint archive compression algorithm
This commit is contained in:
		
						commit
						aca6ef01d8
					
				| 
						 | 
				
			
			@ -1211,3 +1211,10 @@ func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete str
 | 
			
		|||
	}
 | 
			
		||||
	return completeKeyValues(toComplete, kv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AutocompleteCheckpointCompressType - Autocomplete checkpoint compress type options.
 | 
			
		||||
// -> "gzip", "none", "zstd"
 | 
			
		||||
func AutocompleteCheckpointCompressType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 | 
			
		||||
	types := []string{"gzip", "none", "zstd"}
 | 
			
		||||
	return types, cobra.ShellCompDirectiveNoFileComp
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package containers
 | 
			
		|||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/common/pkg/completion"
 | 
			
		||||
	"github.com/containers/podman/v3/cmd/podman/common"
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +12,7 @@ import (
 | 
			
		|||
	"github.com/containers/podman/v3/cmd/podman/validate"
 | 
			
		||||
	"github.com/containers/podman/v3/pkg/domain/entities"
 | 
			
		||||
	"github.com/containers/podman/v3/pkg/rootless"
 | 
			
		||||
	"github.com/containers/storage/pkg/archive"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -36,9 +38,7 @@ var (
 | 
			
		|||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	checkpointOptions entities.CheckpointOptions
 | 
			
		||||
)
 | 
			
		||||
var checkpointOptions entities.CheckpointOptions
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	registry.Commands = append(registry.Commands, registry.CliCommand{
 | 
			
		||||
| 
						 | 
				
			
			@ -60,11 +60,32 @@ func init() {
 | 
			
		|||
	flags.BoolVarP(&checkpointOptions.PreCheckPoint, "pre-checkpoint", "P", false, "Dump container's memory information only, leave the container running")
 | 
			
		||||
	flags.BoolVar(&checkpointOptions.WithPrevious, "with-previous", false, "Checkpoint container with pre-checkpoint images")
 | 
			
		||||
 | 
			
		||||
	flags.StringP("compress", "c", "zstd", "Select compression algorithm (gzip, none, zstd) for checkpoint archive.")
 | 
			
		||||
	_ = checkpointCommand.RegisterFlagCompletionFunc("compress", common.AutocompleteCheckpointCompressType)
 | 
			
		||||
 | 
			
		||||
	validate.AddLatestFlag(checkpointCommand, &checkpointOptions.Latest)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkpoint(cmd *cobra.Command, args []string) error {
 | 
			
		||||
	var errs utils.OutputErrors
 | 
			
		||||
	if cmd.Flags().Changed("compress") {
 | 
			
		||||
		if checkpointOptions.Export == "" {
 | 
			
		||||
			return errors.Errorf("--compress can only be used with --export")
 | 
			
		||||
		}
 | 
			
		||||
		compress, _ := cmd.Flags().GetString("compress")
 | 
			
		||||
		switch strings.ToLower(compress) {
 | 
			
		||||
		case "none":
 | 
			
		||||
			checkpointOptions.Compression = archive.Uncompressed
 | 
			
		||||
		case "gzip":
 | 
			
		||||
			checkpointOptions.Compression = archive.Gzip
 | 
			
		||||
		case "zstd":
 | 
			
		||||
			checkpointOptions.Compression = archive.Zstd
 | 
			
		||||
		default:
 | 
			
		||||
			return errors.Errorf("Selected compression algorithm (%q) not supported. Please select one from: gzip, none, zstd", compress)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		checkpointOptions.Compression = archive.Zstd
 | 
			
		||||
	}
 | 
			
		||||
	if rootless.IsRootless() {
 | 
			
		||||
		return errors.New("checkpointing a container requires root")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,31 +10,25 @@ podman\-container\-checkpoint - Checkpoints one or more running containers
 | 
			
		|||
Checkpoints all the processes in one or more containers. You may use container IDs or names as input.
 | 
			
		||||
 | 
			
		||||
## OPTIONS
 | 
			
		||||
#### **--keep**, **-k**
 | 
			
		||||
 | 
			
		||||
Keep all temporary log and statistics files created by CRIU during checkpointing. These files
 | 
			
		||||
are not deleted if checkpointing fails for further debugging. If checkpointing succeeds these
 | 
			
		||||
files are theoretically not needed, but if these files are needed Podman can keep the files
 | 
			
		||||
for further analysis.
 | 
			
		||||
 | 
			
		||||
#### **--all**, **-a**
 | 
			
		||||
 | 
			
		||||
Checkpoint all running containers.
 | 
			
		||||
 | 
			
		||||
#### **--latest**, **-l**
 | 
			
		||||
#### **--compress**, **-c**
 | 
			
		||||
 | 
			
		||||
Instead of providing the container name or ID, checkpoint the last created container. (This option is not available with the remote Podman client)
 | 
			
		||||
Specify the compression algorithm used for the checkpoint archive created
 | 
			
		||||
with the **--export, -e** option. Possible algorithms are *gzip*, *none*
 | 
			
		||||
and *zstd*. If no compression algorithm is specified Podman will use
 | 
			
		||||
*zstd*.
 | 
			
		||||
 | 
			
		||||
#### **--leave-running**, **-R**
 | 
			
		||||
One possible reason to use *none* is to enable faster creation of checkpoint
 | 
			
		||||
archives. Not compressing the checkpoint archive can result in faster checkpoint
 | 
			
		||||
archive creation.
 | 
			
		||||
 | 
			
		||||
Leave the container running after checkpointing instead of stopping it.
 | 
			
		||||
 | 
			
		||||
#### **--tcp-established**
 | 
			
		||||
 | 
			
		||||
Checkpoint a container with established TCP connections. If the checkpoint
 | 
			
		||||
image contains established TCP connections, this options is required during
 | 
			
		||||
restore. Defaults to not checkpointing containers with established TCP
 | 
			
		||||
connections.
 | 
			
		||||
```
 | 
			
		||||
# podman container checkpoint -l --compress=none --export=dump.tar
 | 
			
		||||
# podman container checkpoint -l --compress=gzip --export=dump.tar.gz
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### **--export**, **-e**
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,11 +50,33 @@ This option must be used in combination with the **--export, -e** option.
 | 
			
		|||
When this option is specified, the content of volumes associated with
 | 
			
		||||
the container will not be included into the checkpoint tar.gz file.
 | 
			
		||||
 | 
			
		||||
#### **--keep**, **-k**
 | 
			
		||||
 | 
			
		||||
Keep all temporary log and statistics files created by CRIU during checkpointing. These files
 | 
			
		||||
are not deleted if checkpointing fails for further debugging. If checkpointing succeeds these
 | 
			
		||||
files are theoretically not needed, but if these files are needed Podman can keep the files
 | 
			
		||||
for further analysis.
 | 
			
		||||
 | 
			
		||||
#### **--latest**, **-l**
 | 
			
		||||
 | 
			
		||||
Instead of providing the container name or ID, checkpoint the last created container. (This option is not available with the remote Podman client)
 | 
			
		||||
 | 
			
		||||
#### **--leave-running**, **-R**
 | 
			
		||||
 | 
			
		||||
Leave the container running after checkpointing instead of stopping it.
 | 
			
		||||
 | 
			
		||||
#### **--pre-checkpoint**, **-P**
 | 
			
		||||
 | 
			
		||||
Dump the container's memory information only, leaving the container running. Later
 | 
			
		||||
operations will supersede prior dumps. It only works on runc 1.0-rc3 or higher.
 | 
			
		||||
 | 
			
		||||
#### **--tcp-established**
 | 
			
		||||
 | 
			
		||||
Checkpoint a container with established TCP connections. If the checkpoint
 | 
			
		||||
image contains established TCP connections, this options is required during
 | 
			
		||||
restore. Defaults to not checkpointing containers with established TCP
 | 
			
		||||
connections.
 | 
			
		||||
 | 
			
		||||
#### **--with-previous**
 | 
			
		||||
 | 
			
		||||
Check out the container with previous criu image files in pre-dump. It only works
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ import (
 | 
			
		|||
	"github.com/containers/podman/v3/libpod/define"
 | 
			
		||||
	"github.com/containers/podman/v3/libpod/events"
 | 
			
		||||
	"github.com/containers/podman/v3/pkg/signal"
 | 
			
		||||
	"github.com/containers/storage/pkg/archive"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -776,6 +777,9 @@ type ContainerCheckpointOptions struct {
 | 
			
		|||
	// ImportPrevious tells the API to restore container with two
 | 
			
		||||
	// images. One is TargetFile, the other is ImportPrevious.
 | 
			
		||||
	ImportPrevious string
 | 
			
		||||
	// Compression tells the API which compression to use for
 | 
			
		||||
	// the exported checkpoint archive.
 | 
			
		||||
	Compression archive.Compression
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Checkpoint checkpoints a container
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -985,7 +985,7 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
 | 
			
		||||
		Compression:      archive.Gzip,
 | 
			
		||||
		Compression:      options.Compression,
 | 
			
		||||
		IncludeSourceDir: true,
 | 
			
		||||
		IncludeFiles:     includeFiles,
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import (
 | 
			
		|||
	"github.com/containers/image/v5/types"
 | 
			
		||||
	"github.com/containers/podman/v3/libpod/define"
 | 
			
		||||
	"github.com/containers/podman/v3/pkg/specgen"
 | 
			
		||||
	"github.com/containers/storage/pkg/archive"
 | 
			
		||||
	"github.com/cri-o/ocicni/pkg/ocicni"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -178,6 +179,7 @@ type CheckpointOptions struct {
 | 
			
		|||
	TCPEstablished bool
 | 
			
		||||
	PreCheckPoint  bool
 | 
			
		||||
	WithPrevious   bool
 | 
			
		||||
	Compression    archive.Compression
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CheckpointReport struct {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -483,6 +483,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
 | 
			
		|||
		KeepRunning:    options.LeaveRunning,
 | 
			
		||||
		PreCheckPoint:  options.PreCheckPoint,
 | 
			
		||||
		WithPrevious:   options.WithPrevious,
 | 
			
		||||
		Compression:    options.Compression,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if options.All {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -425,6 +425,106 @@ var _ = Describe("Podman checkpoint", func() {
 | 
			
		|||
		// Remove exported checkpoint
 | 
			
		||||
		os.Remove(fileName)
 | 
			
		||||
	})
 | 
			
		||||
	// This test does the same steps which are necessary for migrating
 | 
			
		||||
	// a container from one host to another
 | 
			
		||||
	It("podman checkpoint container with export and different compression algorithms", func() {
 | 
			
		||||
		localRunString := getRunString([]string{"--rm", ALPINE, "top"})
 | 
			
		||||
		session := podmanTest.Podman(localRunString)
 | 
			
		||||
		session.WaitWithDefaultTimeout()
 | 
			
		||||
		Expect(session.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
 | 
			
		||||
		cid := session.OutputToString()
 | 
			
		||||
		fileName := "/tmp/checkpoint-" + cid + ".tar"
 | 
			
		||||
 | 
			
		||||
		// Checkpoint with the default algorithm
 | 
			
		||||
		result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		// As the container has been started with '--rm' it will be completely
 | 
			
		||||
		// cleaned up after checkpointing.
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
 | 
			
		||||
 | 
			
		||||
		// Restore container
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
 | 
			
		||||
		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
 | 
			
		||||
 | 
			
		||||
		// Checkpoint with the zstd algorithm
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "--compress", "zstd"})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		// As the container has been started with '--rm' it will be completely
 | 
			
		||||
		// cleaned up after checkpointing.
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
 | 
			
		||||
 | 
			
		||||
		// Restore container
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
 | 
			
		||||
		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
 | 
			
		||||
 | 
			
		||||
		// Checkpoint with the none algorithm
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "-c", "none"})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		// As the container has been started with '--rm' it will be completely
 | 
			
		||||
		// cleaned up after checkpointing.
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
 | 
			
		||||
 | 
			
		||||
		// Restore container
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
 | 
			
		||||
		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
 | 
			
		||||
 | 
			
		||||
		// Checkpoint with the gzip algorithm
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "-c", "gzip"})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		// As the container has been started with '--rm' it will be completely
 | 
			
		||||
		// cleaned up after checkpointing.
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
 | 
			
		||||
 | 
			
		||||
		// Restore container
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
 | 
			
		||||
		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
 | 
			
		||||
 | 
			
		||||
		// Checkpoint with the non-existing algorithm
 | 
			
		||||
		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName, "-c", "non-existing"})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(125))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
 | 
			
		||||
 | 
			
		||||
		result = podmanTest.Podman([]string{"rm", "-fa"})
 | 
			
		||||
		result.WaitWithDefaultTimeout()
 | 
			
		||||
		Expect(result.ExitCode()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
 | 
			
		||||
		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
 | 
			
		||||
 | 
			
		||||
		// Remove exported checkpoint
 | 
			
		||||
		os.Remove(fileName)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	It("podman checkpoint and restore container with root file-system changes", func() {
 | 
			
		||||
		// Start the container
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue