diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2021-06-07 11:09:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-07 11:09:43 +0200 |
commit | aca6ef01d8bd265fb5343cf9b8a212f6073a2095 (patch) | |
tree | a44018f17f42fcfc64eeaec2f52f3ab0abc9a439 | |
parent | 5a209b3d76addbf5ec658a7212a84ae7afce2fee (diff) | |
parent | 949374e589876dcf726a9b93c48ac51bb625fed3 (diff) | |
download | podman-aca6ef01d8bd265fb5343cf9b8a212f6073a2095.tar.gz podman-aca6ef01d8bd265fb5343cf9b8a212f6073a2095.tar.bz2 podman-aca6ef01d8bd265fb5343cf9b8a212f6073a2095.zip |
Merge pull request #10567 from adrianreber/2021-06-04-compress
Add support for selectable checkpoint archive compression algorithm
-rw-r--r-- | cmd/podman/common/completion.go | 7 | ||||
-rw-r--r-- | cmd/podman/containers/checkpoint.go | 27 | ||||
-rw-r--r-- | docs/source/markdown/podman-container-checkpoint.1.md | 52 | ||||
-rw-r--r-- | libpod/container_api.go | 4 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 1 | ||||
-rw-r--r-- | test/e2e/checkpoint_test.go | 100 |
8 files changed, 173 insertions, 22 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index de5b2995a..c93f2017c 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -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 +} diff --git a/cmd/podman/containers/checkpoint.go b/cmd/podman/containers/checkpoint.go index 47d60453b..4fa72d520 100644 --- a/cmd/podman/containers/checkpoint.go +++ b/cmd/podman/containers/checkpoint.go @@ -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") } diff --git a/docs/source/markdown/podman-container-checkpoint.1.md b/docs/source/markdown/podman-container-checkpoint.1.md index 46b6cb646..271a44c9d 100644 --- a/docs/source/markdown/podman-container-checkpoint.1.md +++ b/docs/source/markdown/podman-container-checkpoint.1.md @@ -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** - -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** +#### **--compress**, **-c** -Leave the container running after checkpointing instead of stopping it. +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*. -#### **--tcp-established** +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. -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 diff --git a/libpod/container_api.go b/libpod/container_api.go index 4ccb240e7..b75d0b41d 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -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 diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 74a3fec32..a3acc3198 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -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, }) diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index eacc14d50..bae55e64f 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -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 { diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 237a43441..4908e72f6 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -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 { diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 9d0049910..4aca3682b 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -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 |