Skip to content

Commit

Permalink
Merge pull request #3537 from austinvazquez/feat-run-oci-archive
Browse files Browse the repository at this point in the history
Add support for running container from OCI archive
  • Loading branch information
AkihiroSuda authored Oct 22, 2024
2 parents 07cb00b + a4b2959 commit 0612a1d
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 114 deletions.
32 changes: 32 additions & 0 deletions cmd/nerdctl/container/container_create_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

"github.com/containerd/containerd/v2/defaults"

"github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers"
"github.com/containerd/nerdctl/v2/pkg/testutil"
"github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
"github.com/containerd/nerdctl/v2/pkg/testutil/nettestutil"
Expand Down Expand Up @@ -306,3 +307,34 @@ func TestIssue2993(t *testing.T) {

testCase.Run(t)
}

func TestCreateFromOCIArchive(t *testing.T) {
testutil.RequiresBuild(t)
testutil.RegisterBuildCacheCleanup(t)

// Docker does not support creating containers from OCI archive.
testutil.DockerIncompatible(t)

base := testutil.NewBase(t)
imageName := testutil.Identifier(t)
containerName := testutil.Identifier(t)

teardown := func() {
base.Cmd("rm", "-f", containerName).Run()
base.Cmd("rmi", "-f", imageName).Run()
}
defer teardown()
teardown()

const sentinel = "test-nerdctl-create-from-oci-archive"
dockerfile := fmt.Sprintf(`FROM %s
CMD ["echo", "%s"]`, testutil.CommonImage, sentinel)

buildCtx := helpers.CreateBuildContext(t, dockerfile)
tag := fmt.Sprintf("%s:latest", imageName)
tarPath := fmt.Sprintf("%s/%s.tar", buildCtx, imageName)

base.Cmd("build", "--tag", tag, fmt.Sprintf("--output=type=oci,dest=%s", tarPath), buildCtx).AssertOK()
base.Cmd("create", "--rm", "--name", containerName, fmt.Sprintf("oci-archive://%s", tarPath)).AssertOK()
base.Cmd("start", "--attach", containerName).AssertOutContains("test-nerdctl-create-from-oci-archive")
}
28 changes: 28 additions & 0 deletions cmd/nerdctl/container/container_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,3 +658,31 @@ func TestRunQuiet(t *testing.T) {

assert.Assert(t, wasQuiet(result.Combined(), sentinel), "Found %s in container run output", sentinel)
}

func TestRunFromOCIArchive(t *testing.T) {
testutil.RequiresBuild(t)
testutil.RegisterBuildCacheCleanup(t)

// Docker does not support running container images from OCI archive.
testutil.DockerIncompatible(t)

base := testutil.NewBase(t)
imageName := testutil.Identifier(t)

teardown := func() {
base.Cmd("rmi", "-f", imageName).Run()
}
defer teardown()
teardown()

const sentinel = "test-nerdctl-run-from-oci-archive"
dockerfile := fmt.Sprintf(`FROM %s
CMD ["echo", "%s"]`, testutil.CommonImage, sentinel)

buildCtx := helpers.CreateBuildContext(t, dockerfile)
tag := fmt.Sprintf("%s:latest", imageName)
tarPath := fmt.Sprintf("%s/%s.tar", buildCtx, imageName)

base.Cmd("build", "--tag", tag, fmt.Sprintf("--output=type=oci,dest=%s", tarPath), buildCtx).AssertOK()
base.Cmd("run", "--rm", fmt.Sprintf("oci-archive://%s", tarPath)).AssertOutContainsAll(fmt.Sprintf("Loaded image: %s", tag), sentinel)
}
5 changes: 3 additions & 2 deletions cmd/nerdctl/image/image_load.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers"
"github.com/containerd/nerdctl/v2/pkg/api/types"
"github.com/containerd/nerdctl/v2/pkg/clientutil"
"github.com/containerd/nerdctl/v2/pkg/cmd/image"
"github.com/containerd/nerdctl/v2/pkg/imgutil/load"
)

func NewLoadCommand() *cobra.Command {
Expand Down Expand Up @@ -94,5 +94,6 @@ func loadAction(cmd *cobra.Command, _ []string) error {
}
defer cancel()

return image.Load(ctx, client, options)
_, err = load.FromArchive(ctx, client, options)
return err
}
2 changes: 2 additions & 0 deletions docs/command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ Run a command in a new container.
Usage: `nerdctl run [OPTIONS] IMAGE [COMMAND] [ARG...]`

:nerd_face: `ipfs://` prefix can be used for `IMAGE` to pull it from IPFS. See [`ipfs.md`](./ipfs.md) for details.
:nerd_face: `oci-archive://` prefix can be used for `IMAGE` to specify a local file system path to an OCI formatted tarball.

Basic flags:

Expand Down Expand Up @@ -423,6 +424,7 @@ Create a new container.
Usage: `nerdctl create [OPTIONS] IMAGE [COMMAND] [ARG...]`

:nerd_face: `ipfs://` prefix can be used for `IMAGE` to pull it from IPFS. See [`ipfs.md`](./ipfs.md) for details.
:nerd_face: `oci-archive://` prefix can be used for `IMAGE` to specify a local file system path to an OCI formatted tarball.

The `nerdctl create` command similar to `nerdctl run -d` except the container is never started. You can then use the `nerdctl start <container_id>` command to start the container at any point.

Expand Down
34 changes: 34 additions & 0 deletions pkg/cmd/container/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import (
"github.com/containerd/nerdctl/v2/pkg/flagutil"
"github.com/containerd/nerdctl/v2/pkg/idgen"
"github.com/containerd/nerdctl/v2/pkg/imgutil"
"github.com/containerd/nerdctl/v2/pkg/imgutil/load"
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
"github.com/containerd/nerdctl/v2/pkg/ipcutil"
"github.com/containerd/nerdctl/v2/pkg/labels"
Expand Down Expand Up @@ -123,6 +124,39 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa
}
opts = append(opts, platformOpts...)

if _, err := referenceutil.Parse(args[0]); errors.Is(err, referenceutil.ErrLoadOCIArchiveRequired) {
imageRef := args[0]

// Load and create the platform specified by the user.
// If none specified, fallback to the default platform.
platform := []string{}
if options.Platform != "" {
platform = append(platform, options.Platform)
}

images, err := load.FromOCIArchive(ctx, client, imageRef, types.ImageLoadOptions{
Stdout: options.Stdout,
GOptions: options.GOptions,
Platform: platform,
AllPlatforms: false,
Quiet: options.ImagePullOpt.Quiet,
})
if err != nil {
return nil, nil, err
} else if len(images) == 0 {
// This is a regression and should not occur.
return nil, nil, errors.New("OCI archive did not contain any images")
}

image := images[0].Name
// Multiple images loaded from the provided archive. Default to the first image found.
if len(images) != 1 {
log.L.Warnf("multiple images are found for the platform, defaulting to image %s...", image)
}

args[0] = image
}

var ensuredImage *imgutil.EnsuredImage
if !options.Rootfs {
var platformSS []string // len: 0 or 1
Expand Down
112 changes: 0 additions & 112 deletions pkg/cmd/image/load.go

This file was deleted.

Loading

0 comments on commit 0612a1d

Please sign in to comment.