summaryrefslogtreecommitdiff
path: root/integration
diff options
context:
space:
mode:
authorCory Snider <csnider@mirantis.com>2022-07-20 16:12:01 -0400
committerCory Snider <csnider@mirantis.com>2022-07-27 14:22:49 -0400
commit547da0d575519a197fbf4e0543555d508d176084 (patch)
tree9ed4da77350a474c6acb8581077028eeefd248a9 /integration
parent7624f8aeb1836cd75a0912d9614930e8a59eaf4e (diff)
downloaddocker-547da0d575519a197fbf4e0543555d508d176084.tar.gz
daemon: support other containerd runtimes (MVP)
Contrary to popular belief, the OCI Runtime specification does not specify the command-line API for runtimes. Looking at containerd's architecture from the lens of the OCI Runtime spec, the _shim_ is the OCI Runtime and runC is "just" an implementation detail of the io.containerd.runc.v2 runtime. When one configures a non-default runtime in Docker, what they're really doing is instructing Docker to create containers using the io.containerd.runc.v2 runtime with a configuration option telling the runtime that the runC binary is at some non-default path. Consequently, only OCI runtimes which are compatible with the io.containerd.runc.v2 shim, such as crun, can be used in this manner. Other OCI runtimes, including kata-containers v2, come with their own containerd shim and are not compatible with io.containerd.runc.v2. As Docker has not historically provided a way to select a non-default runtime which requires its own shim, runtimes such as kata-containers v2 could not be used with Docker. Allow other containerd shims to be used with Docker; no daemon configuration required. If the daemon is instructed to create a container with a runtime name which does not match any of the configured or stock runtimes, it passes the name along to containerd verbatim. A user can start a container with the kata-containers runtime, for example, simply by calling docker run --runtime io.containerd.kata.v2 Runtime names which containerd would interpret as a path to an arbitrary binary are disallowed. While handy for development and testing it is not strictly necessary and would allow anyone with Engine API access to trivially execute any binary on the host as root, so we have decided it would be safest for our users if it was not allowed. It is not yet possible to set an alternative containerd shim as the default runtime; it can only be configured per-container. Signed-off-by: Cory Snider <csnider@mirantis.com>
Diffstat (limited to 'integration')
-rw-r--r--integration/container/run_linux_test.go57
-rw-r--r--integration/internal/container/ops.go7
2 files changed, 64 insertions, 0 deletions
diff --git a/integration/container/run_linux_test.go b/integration/container/run_linux_test.go
index e0316dde3b..0325c4050e 100644
--- a/integration/container/run_linux_test.go
+++ b/integration/container/run_linux_test.go
@@ -5,6 +5,7 @@ import (
"context"
"io"
"os"
+ "os/exec"
"path/filepath"
"strings"
"testing"
@@ -15,7 +16,9 @@ import (
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/integration/internal/container"
net "github.com/docker/docker/integration/internal/network"
+ "github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/system"
+ "github.com/docker/docker/testutil/daemon"
"golang.org/x/sys/unix"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -214,3 +217,57 @@ func TestRunConsoleSize(t *testing.T) {
assert.Equal(t, strings.TrimSpace(b.String()), "123 57")
}
+
+func TestRunWithAlternativeContainerdShim(t *testing.T) {
+ skip.If(t, testEnv.IsRemoteDaemon)
+ skip.If(t, testEnv.DaemonInfo.OSType != "linux")
+
+ realShimPath, err := exec.LookPath("containerd-shim-runc-v2")
+ assert.Assert(t, err)
+ realShimPath, err = filepath.Abs(realShimPath)
+ assert.Assert(t, err)
+
+ // t.TempDir() can't be used here as the temporary directory returned by
+ // that function cannot be accessed by the fake-root user for rootless
+ // Docker. It creates a nested hierarchy of directories where the
+ // outermost has permission 0700.
+ shimDir, err := os.MkdirTemp("", t.Name())
+ assert.Assert(t, err)
+ t.Cleanup(func() {
+ if err := os.RemoveAll(shimDir); err != nil {
+ t.Errorf("shimDir RemoveAll cleanup: %v", err)
+ }
+ })
+ assert.Assert(t, os.Chmod(shimDir, 0777))
+ shimDir, err = filepath.Abs(shimDir)
+ assert.Assert(t, err)
+ assert.Assert(t, os.Symlink(realShimPath, filepath.Join(shimDir, "containerd-shim-realfake-v42")))
+
+ d := daemon.New(t,
+ daemon.WithEnvVars("PATH="+shimDir+":"+os.Getenv("PATH")),
+ daemon.WithContainerdSocket(""), // A new containerd instance needs to be started which inherits the PATH env var defined above.
+ )
+ d.StartWithBusybox(t)
+ defer d.Stop(t)
+
+ client := d.NewClientT(t)
+ ctx := context.Background()
+
+ cID := container.Run(ctx, t, client,
+ container.WithImage("busybox"),
+ container.WithCmd("sh", "-c", `echo 'Hello, world!'`),
+ container.WithRuntime("io.containerd.realfake.v42"),
+ )
+
+ poll.WaitOn(t, container.IsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond))
+
+ out, err := client.ContainerLogs(ctx, cID, types.ContainerLogsOptions{ShowStdout: true})
+ assert.NilError(t, err)
+ defer out.Close()
+
+ var b bytes.Buffer
+ _, err = stdcopy.StdCopy(&b, io.Discard, out)
+ assert.NilError(t, err)
+
+ assert.Equal(t, strings.TrimSpace(b.String()), "Hello, world!")
+}
diff --git a/integration/internal/container/ops.go b/integration/internal/container/ops.go
index 0d94a4ebf7..f3101a816c 100644
--- a/integration/internal/container/ops.go
+++ b/integration/internal/container/ops.go
@@ -234,3 +234,10 @@ func WithConsoleSize(width, height uint) func(*TestContainerConfig) {
c.HostConfig.ConsoleSize = [2]uint{height, width}
}
}
+
+// WithRuntime sets the runtime to use to start the container
+func WithRuntime(name string) func(*TestContainerConfig) {
+ return func(c *TestContainerConfig) {
+ c.HostConfig.Runtime = name
+ }
+}