diff --git a/cmd/nerdctl/container/container_commit.go b/cmd/nerdctl/container/container_commit.go index 7db58bca88e..536656d3c3e 100644 --- a/cmd/nerdctl/container/container_commit.go +++ b/cmd/nerdctl/container/container_commit.go @@ -17,6 +17,7 @@ package container import ( + "errors" "github.com/spf13/cobra" "github.com/containerd/nerdctl/v2/cmd/nerdctl/completion" @@ -40,6 +41,7 @@ func CommitCommand() *cobra.Command { cmd.Flags().StringP("message", "m", "", "Commit message") cmd.Flags().StringArrayP("change", "c", nil, "Apply Dockerfile instruction to the created image (supported directives: [CMD, ENTRYPOINT])") cmd.Flags().BoolP("pause", "p", true, "Pause container during commit") + cmd.Flags().StringP("compression", "", "gzip", "commit compression algorithm (zstd or gzip)") return cmd } @@ -66,13 +68,18 @@ func commitOptions(cmd *cobra.Command) (types.ContainerCommitOptions, error) { return types.ContainerCommitOptions{}, err } + com, err := cmd.Flags().GetString("compression") + if err != nil { + return types.ContainerCommitOptions{}, err + } return types.ContainerCommitOptions{ - Stdout: cmd.OutOrStdout(), - GOptions: globalOptions, - Author: author, - Message: message, - Pause: pause, - Change: change, + Stdout: cmd.OutOrStdout(), + GOptions: globalOptions, + Author: author, + Message: message, + Pause: pause, + Change: change, + Compression: com, }, nil } @@ -82,7 +89,9 @@ func commitAction(cmd *cobra.Command, args []string) error { if err != nil { return err } - + if ok, err := verifyOption(options); !ok { + return err + } client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), options.GOptions.Namespace, options.GOptions.Address) if err != nil { return err @@ -98,3 +107,10 @@ func commitShellComplete(cmd *cobra.Command, args []string, toComplete string) ( } return nil, cobra.ShellCompDirectiveNoFileComp } + +func verifyOption(op types.ContainerCommitOptions) (bool, error) { + if string(types.ZSTD) != op.Compression && string(types.GZIP) != op.Compression { + return false, errors.New("--compression param only support zstd or gzip") + } + return true, nil +} diff --git a/docs/command-reference.md b/docs/command-reference.md index a4d2f7af7be..0aaa6bfa39b 100644 --- a/docs/command-reference.md +++ b/docs/command-reference.md @@ -759,6 +759,7 @@ Flags: - :whale: `-m, --message`: Commit message - :whale: `-c, --change`: Apply Dockerfile instruction to the created image (supported directives: [CMD, ENTRYPOINT]) - :whale: `-p, --pause`: Pause container during commit (default: true) +- :nerd_face: `--compression`: Commit compression algorithm,(supported value: zstd or gzip) (default: gzip) ## Image management diff --git a/pkg/api/types/container_types.go b/pkg/api/types/container_types.go index 5325915631d..f2b92df2468 100644 --- a/pkg/api/types/container_types.go +++ b/pkg/api/types/container_types.go @@ -371,8 +371,17 @@ type ContainerCommitOptions struct { Change []string // Pause container during commit Pause bool + // Compression is set commit compression algorithm + Compression string } +type CompressionType string + +const ( + ZSTD CompressionType = "zstd" + GZIP CompressionType = "gzip" +) + // ContainerDiffOptions specifies options for `nerdctl (container) diff`. type ContainerDiffOptions struct { Stdout io.Writer diff --git a/pkg/cmd/container/commit.go b/pkg/cmd/container/commit.go index 1e089c7e92c..1e219575cab 100644 --- a/pkg/cmd/container/commit.go +++ b/pkg/cmd/container/commit.go @@ -44,11 +44,12 @@ func Commit(ctx context.Context, client *containerd.Client, rawRef string, req s } opts := &commit.Opts{ - Author: options.Author, - Message: options.Message, - Ref: parsedReference.String(), - Pause: options.Pause, - Changes: changes, + Author: options.Author, + Message: options.Message, + Ref: parsedReference.String(), + Pause: options.Pause, + Changes: changes, + Compression: options.Compression, } walker := &containerwalker.ContainerWalker{ diff --git a/pkg/imgutil/commit/commit.go b/pkg/imgutil/commit/commit.go index fd5886bfb7f..1d2eb64f487 100644 --- a/pkg/imgutil/commit/commit.go +++ b/pkg/imgutil/commit/commit.go @@ -57,11 +57,12 @@ type Changes struct { } type Opts struct { - Author string - Message string - Ref string - Pause bool - Changes Changes + Author string + Message string + Ref string + Pause bool + Changes Changes + Compression string } var ( @@ -176,7 +177,7 @@ func Commit(ctx context.Context, client *containerd.Client, container containerd // Sync filesystem to make sure that all the data writes in container could be persisted to disk. Sync() - diffLayerDesc, diffID, err := createDiff(ctx, id, sn, client.ContentStore(), differ) + diffLayerDesc, diffID, err := createDiff(ctx, id, sn, client.ContentStore(), differ, opts.Compression) if err != nil { return emptyDigest, fmt.Errorf("failed to export layer: %w", err) } @@ -356,8 +357,14 @@ func writeContentsForImage(ctx context.Context, snName string, baseImg container } // createDiff creates a layer diff into containerd's content store. -func createDiff(ctx context.Context, name string, sn snapshots.Snapshotter, cs content.Store, comparer diff.Comparer) (ocispec.Descriptor, digest.Digest, error) { - newDesc, err := rootfs.CreateDiff(ctx, name, sn, comparer) +func createDiff(ctx context.Context, name string, sn snapshots.Snapshotter, cs content.Store, comparer diff.Comparer, compression string) (ocispec.Descriptor, digest.Digest, error) { + opts := make([]diff.Opt, 0) + mediaType := images.MediaTypeDockerSchema2LayerGzip + if compression == "zstd" { + opts = append(opts, diff.WithMediaType(ocispec.MediaTypeImageLayerZstd)) + mediaType = images.MediaTypeDockerSchema2LayerZstd + } + newDesc, err := rootfs.CreateDiff(ctx, name, sn, comparer, opts...) if err != nil { return ocispec.Descriptor{}, digest.Digest(""), err } @@ -378,7 +385,7 @@ func createDiff(ctx context.Context, name string, sn snapshots.Snapshotter, cs c } return ocispec.Descriptor{ - MediaType: images.MediaTypeDockerSchema2LayerGzip, + MediaType: mediaType, Digest: newDesc.Digest, Size: info.Size, }, diffID, nil