Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for running container from OCI archive #3537

Merged
merged 3 commits into from
Oct 22, 2024

Conversation

austinvazquez
Copy link
Contributor

@austinvazquez austinvazquez commented Oct 14, 2024

Issue

Proposal for #3536

Description

This change adds the ability to create and run containers from OCI archive without performing separate load step.

Testing

As this behavior is not provided by Docker, this change adds a nerdctl-only test for this behavior.

@austinvazquez
Copy link
Contributor Author

If maintainers would prefer, I can break 79e4e24 into its own PR. The change was trivial at first before I added docs changes and integration test. LMK your thoughts.

@austinvazquez austinvazquez marked this pull request as ready for review October 14, 2024 19:26
@@ -409,12 +409,17 @@ func processContainerCreateOptions(cmd *cobra.Command) (types.ContainerCreateOpt
if err != nil {
return opt, err
}
quiet, err := cmd.Flags().GetBool("quiet")
Copy link
Member

Choose a reason for hiding this comment

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

Should be a separate PR

Copy link
Member

Choose a reason for hiding this comment

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

Does Docker or Podman have this flag?

Otherwise —pull-quiet might be less confusing? idk

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍🏼 Opened #3551
Docker has --quiet across load, run, and create.

@@ -361,6 +363,33 @@ func runAction(cmd *cobra.Command, args []string) error {
return err
}

if imageRef := args[0]; strings.HasPrefix(imageRef, "oci-archive://") {
Copy link
Member

@AkihiroSuda AkihiroSuda Oct 15, 2024

Choose a reason for hiding this comment

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

This has to be supported in nerdctl create too (See ipfs:// code)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks will take a look.


// Running multi-image OCI archives is not yet supported.
if len(images) != 1 {
return errors.New("multiple images in OCI archive found")
Copy link
Member

Choose a reason for hiding this comment

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

What about just defaulting to the first one? (With a warning)

func TestRunFromOCIArchive(t *testing.T) {
testutil.RequiresBuild(t)
testutil.RegisterBuildCacheCleanup(t)
testutil.DockerIncompatible(t)
Copy link
Member

Choose a reason for hiding this comment

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

Needs a comment

Copy link
Member

@AkihiroSuda AkihiroSuda Oct 15, 2024

Choose a reason for hiding this comment

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

oci-archive:// needs docs too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in d669f3d. Added documentation for both create and run.

@austinvazquez
Copy link
Contributor Author

Going to let this CI run finish before rebasing for #3551

@austinvazquez austinvazquez force-pushed the feat-run-oci-archive branch 2 times, most recently from d4a5e21 to d669f3d Compare October 15, 2024 20:38
@@ -123,6 +124,37 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa
}
opts = append(opts, platformOpts...)

if imageRef := args[0]; strings.HasPrefix(imageRef, "oci-archive://") {
Copy link
Member

Choose a reason for hiding this comment

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

Protocol prefixes should be parsed in the same place as ipfs://

func Parse(rawRef string) (*ImageReference, error) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the reference. I missed this when looking at the ipfs code.

Path: "/tmp/build/saved-image.tar",
Error: "",
String: "/tmp/build/saved-image.tar",
Suggested: "oci-archive-/tmp/-abcde",
Copy link
Contributor

@apostasie apostasie Oct 17, 2024

Choose a reason for hiding this comment

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

You likely need to do something for the suggested name of oci-archive://.

This suggested name is not valid for a container name (it is used when you do not specify a name for your container).

Maybe something in the line of:

func (ir *ImageReference) SuggestContainerName(suffix string) string {
	name := "untitled"
	if ir.Protocol != "" && ir.Domain == "" {
		if ir.Protocol == OCIArchive {
			name = string(ir.Protocol) + "-" + path.Base(ir.Path)[:shortIDLength]
		}else{
			name = string(ir.Protocol) + "-" + ir.String()[:shortIDLength]
		}
	} else if ir.Path != "" {
		name = path.Base(ir.Path)
	}
	return name + "-" + suffix[:5]
}

... although that is likely not sufficient, as filesystem might allow characters that are not safe to use as image identifiers.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we keep it simple and only suggest ‘oci-archive-container-id’ so that we do not have to deal with local path sanitization.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @apostasie. Let me take another look here. We load the image from the archive before and reset the image ref to the name in the image manifest before calling parse again on that reference. I shouldn't have just made this test work though. Maybe it would be better to have another type for oci-archive image references which doesn't support suggested container name as it doesn't make sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

I’ll have a look around as well on how this is used.
thanks @austinvazquez !

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should be addressed with 4034998. @apostasie, I took another look and changed how I was looking at the problem. When parsing an raw image reference which is a path for an OCI archive, we should fail and let the caller (pkg/create) know the reference is a path to an image archive and needs to be loaded before (re)parsing. This should resolve the quirkiness of having a image reference object which was not really a valid image reference.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, reading through - it is a bit weird indeed, because, yep, it is not really an image ref, it is a filesystem location... - I think it is ok as you put it now.

image := images[0].Name
// Multi-image archive provided, default to first image found.
if len(images) != 1 {
log.L.Warnf("multi-image OCI archive provided, defaulting to image %s...", image)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
log.L.Warnf("multi-image OCI archive provided, defaulting to image %s...", image)
log.L.Warnf("multiple images are found for the platform, defaulting to image %s...", image)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Applied in 932bfaf

if options.Input != "" {
f, err := os.Open(options.Input)
if err != nil {
return []images.Image{}, err
Copy link
Member

Choose a reason for hiding this comment

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

why not return nil, err?

Copy link
Contributor Author

@austinvazquez austinvazquez Oct 18, 2024

Choose a reason for hiding this comment

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

I feel like I picked this up early in my Go learning (maybe a project I worked did this) but yeah looks like nil is recommended to avoid memory alloc. Will update.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in d8ab512

Signed-off-by: Austin Vazquez <macedonv@amazon.com>
Signed-off-by: Austin Vazquez <macedonv@amazon.com>
@austinvazquez austinvazquez force-pushed the feat-run-oci-archive branch 2 times, most recently from 932bfaf to 4034998 Compare October 21, 2024 17:30
containerName := testutil.Identifier(t)

teardown := func() {
base.Cmd("rm", containerName).Run()
Copy link
Contributor

Choose a reason for hiding this comment

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

-f for both rm and rmi would be better in teardown.

imageName := testutil.Identifier(t)

teardown := func() {
base.Cmd("rmi", imageName).Run()
Copy link
Contributor

Choose a reason for hiding this comment

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

-f

@@ -273,6 +273,10 @@ func TestReferenceUtil(t *testing.T) {
Tag: "latest",
ExplicitTag: "",
},
"oci-archive:///tmp/build/saved-image.tar": {
Protocol: "oci-archive",
Copy link
Contributor

Choose a reason for hiding this comment

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

Protocol is not necessary here, since the test stops as it errors (and since your latest version does not set the protocol)

@apostasie
Copy link
Contributor

@austinvazquez thanks! - I left a few nits comments.

Signed-off-by: Austin Vazquez <macedonv@amazon.com>
Copy link
Member

@AkihiroSuda AkihiroSuda left a comment

Choose a reason for hiding this comment

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

Thanks

@AkihiroSuda AkihiroSuda merged commit 0612a1d into containerd:main Oct 22, 2024
26 checks passed
@austinvazquez austinvazquez deleted the feat-run-oci-archive branch October 22, 2024 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants