Skip to content

Add Standalone SOCI Image Convert mode for SOCI index creation using disk based OCI Layouts without containerd#1881

Merged
sondavidb merged 1 commit into
awslabs:mainfrom
prafgup:prafulg/standalon-convert-without-containerd
Mar 5, 2026
Merged

Add Standalone SOCI Image Convert mode for SOCI index creation using disk based OCI Layouts without containerd#1881
sondavidb merged 1 commit into
awslabs:mainfrom
prafgup:prafulg/standalon-convert-without-containerd

Conversation

@prafgup
Copy link
Copy Markdown
Contributor

@prafgup prafgup commented Mar 1, 2026

Issue #, if available:
Closes #1057

Description of changes:
This PR adds standalone mode to the soci convert command, enabling SOCI index creation without requiring a running containerd daemon. This is particularly useful for CI/CD pipelines and environments where running containerd is impractical without privileged mode.

Key Features

  • Standalone Mode (--standalone): Reads an OCI image layout (tar or directory) from disk, creates SOCI indexes, and writes the converted image back to disk
  • Output Format (--format): Supports oci-archive (tar, default) and oci-dir (directory) output formats
    • This follows the same convention used by tools like Podman (--format oci-archive / oci-dir), Skopeo (copy oci-archive: / oci:), and crane using --format oci for directory output.

Usage Example

Tar output (oci-archive, default):

# Pull an image as OCI layout
crane pull --format oci myregistry.com/myimage:latest /tmp/my-image

# Convert to SOCI-enabled image (tar output)
soci convert --standalone /tmp/my-image /tmp/my-soci-image.tar

# Import into containerd
ctr images import --no-unpack --index-name myregistry.com/myimage:latest-soci /tmp/my-soci-image.tar

--- or push with crane like - (crane only supports dir for oci layout pushing)

mkdir -p /tmp/my-soci-image-dir
tar -xf /tmp/my-soci-image.tar -C /tmp/my-soci-image-dir
crane push /tmp/my-soci-image-dir myregistry.com/myimage:latest-soci

Directory output (oci-dir):

# Pull an image as OCI layout
crane pull --format oci myregistry.com/myimage:latest /tmp/my-image

# Convert to SOCI-enabled image (directory output)
soci convert --standalone --format oci-dir /tmp/my-image /tmp/my-soci-image

# Push back to registry
crane push /tmp/my-soci-image myregistry.com/myimage:latest-soc

Testing performed:

  • Added new Integration test and all integration tests pass (TestStandaloneConvert*)
    - Basic conversion with validation (all permutation of input (tar/dir) and output (tar/dir)
    - Specific platform selection (--platform)
    - Error handling (nonexistent images, missing arguments, wrong output format)
    - Idempotency verification
  • Tested on ARM64 architecture (linux/arm64/v8) (lima on macOs)
    • lima sudo GO_TEST_FLAGS="-run TestStandalone -count=1" make integration
    • lima sudo make test
  • Manual verification of image download, conversion, and push workflow

Standalone Convert with oci-archive output -

crane auth login source-registry.com --username $REPOSITORY --password $TOKEN
crane pull --format oci source-registry.com/myimage:latest /tmp/my-crane-image-dir

sudo ./out/soci convert --standalone /tmp/my-crane-image-dir /tmp/my-soci-image.tar

ztoc skipped - layer sha256:7511aa994dfed5f54c697fcec6db7176449e7d87317b3f6ad093185182ce01c7 (application/vnd.oci.image.layer.v1.tar+gzip) size 3222 is less than min-layer-size 10485760
ztoc skipped - layer sha256:12bb71ceae3401038ce93aa7ce3a115f4a5cb3e9a85277ef4a97718c0fc9298e (application/vnd.oci.image.layer.v1.tar+gzip) size 221568 is less than min-layer-size 10485760
....
layer sha256:3e9c02b40ec11c1a3cc84f775102e2a3b100700fc7753098adc6d62e3fc6563b -> ztoc sha256:0aa198e2f2f6ff02675b7f7dc27e008a1b81bc15a87a5e4d5f868259a3cdc5f0
layer sha256:d8c6b361b623cabb0a89fad4a7d491d7d543f0834ca0c581e0176e1b76a68a15 -> ztoc sha256:ea8f91d2a57139b053186c8a1ae1901684bc06fda5b7d00aef0bd3d6d4e9e4c1



mkdir -p /tmp/my-soci-image-dir
tar -xf /tmp/my-soci-image.tar -C /tmp/my-soci-image-dir
crane push /tmp/my-soci-image-dir dest-registry.com/myimage:latest-soci 

2026/03/01 17:51:41 existing manifest: sha256:fe64b32c84403bd29758342ac0f78a384961bf6788d5de22b9fea1e7c7f1c84a
2026/03/01 17:51:41 existing manifest: sha256:c60d93f19b8a3dd886faa3b455ea809d0055173aa0e501fb0926f196d736a984
2026/03/01 17:51:41 dest-registry.com/myimage:latest-soci : digest: sha256:f265a1fddffc035eb949ac3ff03a597ce4c823b8bde2ae6cb63a0c85f69d0de9 size: 803
dest-registry.com/myimage@sha256:f265a1fddffc035eb949ac3ff03a597ce4c823b8bde2ae6cb63a0c85f69d0de9

Standalone Convert with oci-dir output -

sudo ./out/soci convert --standalone /tmp/my-crane-image-dir /tmp/my-soci-image --format oci-dir

ztoc skipped - layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 (application/vnd.oci.image.layer.v1.tar+gzip) size 32 is less than min-layer-size 10485760
ztoc skipped - layer sha256:7511aa994dfed5f54c697fcec6db7176449e7d87317b3f6ad093185182ce01c7 (application/vnd.oci.image.layer.v1.tar+gzip) size 3222 is less than min-layer-size 10485760
...
ztoc skipped - layer sha256:f6a26d16afc76b03f36290b56770ae0db2ab11aab759d2c7bd49bdfc865b3b87 (application/vnd.oci.image.layer.v1.tar+gzip) size 10395600 is less than min-layer-size 10485760
ztoc skipped - layer sha256:ef6465a1674b258144bd7eac86347823926436a5d53f100cadfe098c82e4c4d4 (application/vnd.oci.image.layer.v1.tar+gzip) size 78 is less than min-layer-size 10485760


crane push /tmp/my-soci-image dest-registry.com/myimage:latest-soci 
2026/03/01 20:50:51 existing manifest: sha256:fe64b32c84403bd29758342ac0f78a384961bf6788d5de22b9fea1e7c7f1c84a
2026/03/01 20:50:51 existing manifest: sha256:c60d93f19b8a3dd886faa3b455ea809d0055173aa0e501fb0926f196d736a984
2026/03/01 20:50:51 dest-registry.com/myimage:latest-soci : digest: sha256:f265a1fddffc035eb949ac3ff03a597ce4c823b8bde2ae6cb63a0c85f69d0de9 size: 803
dest-registry.com/myimage:@sha256:f265a1fddffc035eb949ac3ff03a597ce4c823b8bde2ae6cb63a0c85f69d0de9

Integration tests -

sudo GO_TEST_FLAGS="-run TestStandalone -count=1" make integration

SOCI_SNAPSHOTTER_PROJECT_ROOT=/Volumes/git/prafulg/soci-snapshotter
=== RUN   TestStandaloneConvertBasic
=== RUN   TestStandaloneConvertBasic/dir-to-tar
=== RUN   TestStandaloneConvertBasic/tar-to-tar
=== RUN   TestStandaloneConvertBasic/dir-to-dir
=== RUN   TestStandaloneConvertBasic/tar-to-dir
--- PASS: TestStandaloneConvertBasic (31.63s)
    --- PASS: TestStandaloneConvertBasic/dir-to-tar (2.92s)
    --- PASS: TestStandaloneConvertBasic/tar-to-tar (2.65s)
    --- PASS: TestStandaloneConvertBasic/dir-to-dir (2.71s)
    --- PASS: TestStandaloneConvertBasic/tar-to-dir (2.69s)
=== RUN   TestStandaloneConvertSpecificPlatform
--- PASS: TestStandaloneConvertSpecificPlatform (18.89s)
=== RUN   TestStandaloneInvalidConversion
=== RUN   TestStandaloneInvalidConversion/nonexistent_input
=== RUN   TestStandaloneInvalidConversion/invalid_format
=== RUN   TestStandaloneInvalidConversion/missing_destination
--- PASS: TestStandaloneInvalidConversion (1.19s)
    --- PASS: TestStandaloneInvalidConversion/nonexistent_input (0.02s)
    --- PASS: TestStandaloneInvalidConversion/invalid_format (0.03s)
    --- PASS: TestStandaloneInvalidConversion/missing_destination (0.03s)
=== RUN   TestStandaloneConvertIdempotent
--- PASS: TestStandaloneConvertIdempotent (19.88s)
PASS
ok      github.com/awslabs/soci-snapshotter/integration 193.187s

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@prafgup prafgup requested a review from a team as a code owner March 1, 2026 21:26
@github-actions github-actions Bot added go Pull requests that update Go code testing Unit and/or integration tests labels Mar 1, 2026
Copy link
Copy Markdown
Contributor

@sondavidb sondavidb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM, some small things I'd like looked at before approving.

Thanks!

Comment thread integration/convert_standalone_test.go
Comment thread Dockerfile Outdated
Comment thread integration/standalone_convert_test.go Outdated
Comment thread integration/standalone_convert_test.go Outdated
Comment thread integration/convert_standalone_test.go
Comment thread integration/convert_standalone_test.go
Signed-off-by: Praful Gupta <prafulgupta6@gmail.com>
@prafgup prafgup force-pushed the prafulg/standalon-convert-without-containerd branch from 22f933e to 81f9f1b Compare March 5, 2026 00:43
@prafgup
Copy link
Copy Markdown
Contributor Author

prafgup commented Mar 5, 2026

Hey @sondavidb ,
Resolved all your comments 😄 feel free to review again. (Also fixed the issue I mentioned here #1881 (comment))

@sondavidb
Copy link
Copy Markdown
Contributor

Sure. I'll take a look tomorrow. Will run CI in the meantime.

Comment thread cmd/soci/commands/convert.go
Copy link
Copy Markdown
Contributor

@sondavidb sondavidb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

Comment thread cmd/soci/commands/internal/standalone.go
@Shubhranshu153
Copy link
Copy Markdown
Contributor

LGTM. Thanks for working on it.

@prafgup
Copy link
Copy Markdown
Contributor Author

prafgup commented Mar 5, 2026

Thanks for the review 🚀

I'll followup with the doc update PR once this is merged 😄 (also would appreciate a release for this feature so we can start consuming it internally)

@sondavidb
Copy link
Copy Markdown
Contributor

(also would appreciate a release for this feature so we can start consuming it internally)

Sure, I can bring this up and see when we can get a release out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

go Pull requests that update Go code testing Unit and/or integration tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Create a SOCI Index without a Container Runtime

3 participants