Skip to content

Commit bae71e6

Browse files
authored
Merge pull request #4300 from coderbirju/add-soci-convert
add soci to nerdctl image convert
2 parents 7564040 + 337f5a1 commit bae71e6

File tree

9 files changed

+252
-26
lines changed

9 files changed

+252
-26
lines changed

cmd/nerdctl/image/image_convert.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ func convertCommand() *cobra.Command {
8989
cmd.Flags().String("overlaybd-dbstr", "", "Database config string for overlaybd")
9090
// #endregion
9191

92+
// #region soci flags
93+
cmd.Flags().Bool("soci", false, "Convert image to SOCI Index V2 format.")
94+
cmd.Flags().Int64("soci-min-layer-size", -1, "The minimum size of layers that will be converted to SOCI Index V2 format")
95+
cmd.Flags().Int64("soci-span-size", -1, "The size of SOCI spans")
96+
// #endregion
97+
9298
// #region generic flags
9399
cmd.Flags().Bool("uncompress", false, "Convert tar.gz layers to uncompressed tar layers")
94100
cmd.Flags().Bool("oci", false, "Convert Docker media types to OCI media types")
@@ -213,6 +219,21 @@ func convertOptions(cmd *cobra.Command) (types.ImageConvertOptions, error) {
213219
}
214220
// #endregion
215221

222+
// #region soci flags
223+
soci, err := cmd.Flags().GetBool("soci")
224+
if err != nil {
225+
return types.ImageConvertOptions{}, err
226+
}
227+
sociMinLayerSize, err := cmd.Flags().GetInt64("soci-min-layer-size")
228+
if err != nil {
229+
return types.ImageConvertOptions{}, err
230+
}
231+
sociSpanSize, err := cmd.Flags().GetInt64("soci-span-size")
232+
if err != nil {
233+
return types.ImageConvertOptions{}, err
234+
}
235+
// #endregion
236+
216237
// #region generic flags
217238
uncompress, err := cmd.Flags().GetBool("uncompress")
218239
if err != nil {
@@ -277,6 +298,13 @@ func convertOptions(cmd *cobra.Command) (types.ImageConvertOptions, error) {
277298
OverlayFsType: overlaybdFsType,
278299
OverlaydbDBStr: overlaybdDbstr,
279300
},
301+
SociConvertOptions: types.SociConvertOptions{
302+
Soci: soci,
303+
SociOptions: types.SociOptions{
304+
SpanSize: sociSpanSize,
305+
MinLayerSize: sociMinLayerSize,
306+
},
307+
},
280308
Stdout: cmd.OutOrStdout(),
281309
}, nil
282310
}

cmd/nerdctl/image/image_convert_linux_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,24 @@ func TestImageConvert(t *testing.T) {
8989
},
9090
Expected: test.Expects(0, nil, nil),
9191
},
92+
{
93+
Description: "soci",
94+
Require: require.All(
95+
require.Not(nerdtest.Docker),
96+
nerdtest.Soci,
97+
nerdtest.SociVersion("0.10.0"),
98+
),
99+
Cleanup: func(data test.Data, helpers test.Helpers) {
100+
helpers.Anyhow("rmi", "-f", data.Identifier("converted-image"))
101+
},
102+
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
103+
return helpers.Command("image", "convert", "--soci",
104+
"--soci-span-size", "2097152",
105+
"--soci-min-layer-size", "0",
106+
testutil.CommonImage, data.Identifier("converted-image"))
107+
},
108+
Expected: test.Expects(0, nil, nil),
109+
},
92110
},
93111
}
94112

docs/command-reference.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,11 @@ Flags:
979979
- `--oci` : convert Docker media types to OCI media types
980980
- `--platform=<PLATFORM>` : convert content for a specific platform
981981
- `--all-platforms` : convert content for all platforms (default: false)
982+
- `--soci` : convert content to SOCI image manifest v2
983+
*[**Note**: soci convert uses the default platform if nothing is specified. --platform flag can be used to specify a platform]*
984+
- `--soci-span-size` : Span size in bytes that soci index uses to segment layer data. Default is 4 MiB.
985+
- `--soci-min-layer-size`: Minimum layer size in bytes to build zTOC for. Smaller layers won't have zTOC and not lazy pulled. Default is 10 MiB.
986+
982987

983988
### :nerd_face: nerdctl image encrypt
984989

docs/soci.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ SOCI Snapshotter is a containerd snapshotter plugin. It enables standard OCI ima
44

55
See https://github.com/awslabs/soci-snapshotter to learn further information.
66

7+
## SOCI Index Manifest Versions
8+
9+
SOCI supports two index manifest versions:
10+
11+
- **v1**: Original format using OCI Referrers API (disabled by default in SOCI v0.10.0+)
12+
- **v2**: New format that packages SOCI index with the image (default in SOCI v0.10.0+)
13+
14+
To enable v1 indices in SOCI v0.10.0+, add to `/etc/soci-snapshotter-grpc/config.toml`:
15+
```toml
16+
[pull_modes]
17+
[pull_modes.soci_v1]
18+
enable = true
19+
```
20+
21+
For detailed information about the differences between v1 and v2, see the [SOCI Index Manifest v2 documentation](https://github.com/awslabs/soci-snapshotter/blob/main/docs/soci-index-manifest-v2.md).
22+
723
## Prerequisites
824

925
- Install containerd remote snapshotter plugin (`soci-snapshotter-grpc`) from https://github.com/awslabs/soci-snapshotter/blob/main/docs/getting-started.md
@@ -45,3 +61,21 @@ For images that already have SOCI indices, see https://gallery.ecr.aws/soci-work
4561
nerdctl push --snapshotter=soci --soci-span-size=2097152 --soci-min-layer-size=20971520 public.ecr.aws/my-registry/my-repo:latest
4662
```
4763
--soci-span-size and --soci-min-layer-size are two properties to customize the SOCI index. See [Command Reference](https://github.com/containerd/nerdctl/blob/377b2077bb616194a8ef1e19ccde32aa1ffd6c84/docs/command-reference.md?plain=1#L773) for further details.
64+
65+
> **Note**: With SOCI v0.10.0+, When using `nerdctl push --snapshotter=soci`, it creates and pushes v1 indices. When pushing a converted image (created with `nerdctl image convert --soci`), it will push v2 indices.
66+
67+
## Enable SOCI for `nerdctl image convert`
68+
69+
| :zap: Requirement | nerdctl >= 2.1.3 |
70+
| ----------------- | ---------------- |
71+
72+
| :zap: Requirement | soci-snapshotter >= 0.10.0 |
73+
| ----------------- | ---------------- |
74+
75+
- Convert an image to generate SOCI Index artifacts v2. Running the `nerdctl image convert` with the `--soci` flag and a `srcImg` and `dstImg`, `nerdctl` will create the SOCI v2 indices and the new image will be present in the `dstImg` address.
76+
```console
77+
nerdctl image convert --soci --soci-span-size=2097152 --soci-min-layer-size=20971520 public.ecr.aws/my-registry/my-repo:latest public.ecr.aws/my-registry/my-repo:soci
78+
```
79+
--soci-span-size and --soci-min-layer-size are two properties to customize the SOCI index. See [Command Reference](https://github.com/containerd/nerdctl/blob/377b2077bb616194a8ef1e19ccde32aa1ffd6c84/docs/command-reference.md?plain=1#L773) for further details.
80+
81+
The `image convert` command with `--soci` flag creates SOCI-enabled images using SOCI Index Manifest v2, which combines the SOCI index and the original image into a single artifact.

pkg/api/types/image_types.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package types
1919
import (
2020
"io"
2121

22-
"github.com/opencontainers/image-spec/specs-go/v1"
22+
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
2323
)
2424

2525
// ImageListOptions specifies options for `nerdctl image list`.
@@ -73,6 +73,7 @@ type ImageConvertOptions struct {
7373
ZstdChunkedOptions
7474
NydusOptions
7575
OverlaybdOptions
76+
SociConvertOptions
7677
}
7778

7879
// EstargzOptions contains eStargz conversion options
@@ -135,6 +136,15 @@ type OverlaybdOptions struct {
135136
OverlayFsType string
136137
// OverlaydbDBStr database config string for overlaybd
137138
OverlaydbDBStr string
139+
// #endregion
140+
}
141+
142+
type SociConvertOptions struct {
143+
// Soci convert image to SOCI format.
144+
Soci bool
145+
// SociOptions contains SOCI-specific options
146+
SociOptions SociOptions
147+
// #endregion
138148
}
139149

140150
// ImageCryptOptions specifies options for `nerdctl image encrypt` and `nerdctl image decrypt`.
@@ -211,7 +221,7 @@ type ImagePullOptions struct {
211221
// If nil, it will unpack automatically if only 1 platform is specified.
212222
Unpack *bool
213223
// Content for specific platforms. Empty if `--all-platforms` is true
214-
OCISpecPlatform []v1.Platform
224+
OCISpecPlatform []ocispec.Platform
215225
// Pull mode
216226
Mode string
217227
// Suppress verbose output

pkg/cmd/image/convert.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747
converterutil "github.com/containerd/nerdctl/v2/pkg/imgutil/converter"
4848
"github.com/containerd/nerdctl/v2/pkg/platformutil"
4949
"github.com/containerd/nerdctl/v2/pkg/referenceutil"
50+
"github.com/containerd/nerdctl/v2/pkg/snapshotterutil"
5051
)
5152

5253
func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRawRef string, options types.ImageConvertOptions) error {
@@ -86,8 +87,9 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa
8687
zstdchunked := options.ZstdChunked
8788
overlaybd := options.Overlaybd
8889
nydus := options.Nydus
90+
soci := options.Soci
8991
var finalize func(ctx context.Context, cs content.Store, ref string, desc *ocispec.Descriptor) (*images.Image, error)
90-
if estargz || zstd || zstdchunked || overlaybd || nydus {
92+
if estargz || zstd || zstdchunked || overlaybd || nydus || soci {
9193
convertCount := 0
9294
if estargz {
9395
convertCount++
@@ -104,9 +106,12 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa
104106
if nydus {
105107
convertCount++
106108
}
109+
if soci {
110+
convertCount++
111+
}
107112

108113
if convertCount > 1 {
109-
return errors.New("options --estargz, --zstdchunked, --overlaybd and --nydus lead to conflict, only one of them can be used")
114+
return errors.New("options --estargz, --zstdchunked, --overlaybd, --nydus and --soci lead to conflict, only one of them can be used")
110115
}
111116

112117
var convertFunc converter.ConvertFunc
@@ -164,6 +169,16 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa
164169
)),
165170
)
166171
convertType = "nydus"
172+
case soci:
173+
// Convert image to SOCI format
174+
convertedRef, err := snapshotterutil.ConvertSociIndexV2(ctx, client, srcRef, targetRef, options.GOptions, options.Platforms, options.SociOptions)
175+
if err != nil {
176+
return fmt.Errorf("failed to convert image to SOCI format: %w", err)
177+
}
178+
res := converterutil.ConvertedImageInfo{
179+
Image: convertedRef,
180+
}
181+
return printConvertedImage(options.Stdout, options, res)
167182
}
168183

169184
if convertType != "overlaybd" {

pkg/cmd/image/push.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ func Push(ctx context.Context, client *containerd.Client, rawRef string, options
210210
return err
211211
}
212212
if options.GOptions.Snapshotter == "soci" {
213-
if err = snapshotterutil.CreateSoci(ref, options.GOptions, options.AllPlatforms, options.Platforms, options.SociOptions); err != nil {
213+
if err = snapshotterutil.CreateSociIndexV1(ref, options.GOptions, options.AllPlatforms, options.Platforms, options.SociOptions); err != nil {
214214
return err
215215
}
216216
if err = snapshotterutil.PushSoci(ref, options.GOptions, options.AllPlatforms, options.Platforms); err != nil {

0 commit comments

Comments
 (0)