diff --git a/images/basic/docker/Dockerfile b/images/basic/docker/Dockerfile new file mode 100644 index 000000000..59c7cf670 --- /dev/null +++ b/images/basic/docker/Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:22.04 + +ENV DEBIAN_FRONTEND="noninteractive" +RUN apt-get update && apt-get install -y docker.io + +CMD bash -xec 'mount -t tmpfs cgroups /sys/fs/cgroup && \ + mkdir /sys/fs/cgroup/devices && \ + mount -t cgroup -o devices devices /sys/fs/cgroup/devices && \ + exec /usr/bin/dockerd --bridge=none --iptables=false --ip6tables=false -D' diff --git a/test/image/BUILD b/test/image/BUILD index af7fd04e1..4d744d0cf 100644 --- a/test/image/BUILD +++ b/test/image/BUILD @@ -27,6 +27,7 @@ go_test( deps = [ "//pkg/test/dockerutil", "//pkg/test/testutil", + "@com_github_docker_docker//api/types/mount:go_default_library", ], ) diff --git a/test/image/image_test.go b/test/image/image_test.go index 952264173..20bfc51cf 100644 --- a/test/image/image_test.go +++ b/test/image/image_test.go @@ -33,6 +33,7 @@ import ( "testing" "time" + "github.com/docker/docker/api/types/mount" "gvisor.dev/gvisor/pkg/test/dockerutil" "gvisor.dev/gvisor/pkg/test/testutil" ) @@ -319,6 +320,63 @@ func TestStdio(t *testing.T) { } } +func TestDocker(t *testing.T) { + if testutil.IsRunningWithHostNet() { + t.Skip("docker doesn't work with hostinet") + } + ctx := context.Background() + d := dockerutil.MakeContainer(ctx, t) + defer d.CleanUp(ctx) + + // Start the container. + opts := dockerutil.RunOpts{ + Image: "basic/docker", + Privileged: true, + Mounts: []mount.Mount{ + { + Target: "/var/lib/docker", + Type: mount.TypeTmpfs, + }, + }, + } + if err := d.Spawn(ctx, opts); err != nil { + t.Fatalf("docker run failed: %v", err) + } + + // Docker creates tmpfs mounts with the noexec flag. + output, err := d.Exec(ctx, + dockerutil.ExecOpts{Privileged: true}, + "mount", "-o", "remount,exec", "/var/lib/docker", + ) + if err != nil { + t.Fatalf("docker exec failed: %v\n%s", err, output) + } + // Wait for the docker daemon. + for i := 0; i < 10; i++ { + output, err := d.Exec(ctx, dockerutil.ExecOpts{}, "docker", "info") + t.Logf("== docker info ==\n%s", output) + if err != nil { + t.Logf("docker exec failed: %v", err) + time.Sleep(5 * time.Second) + continue + } + break + } + p, err := d.ExecProcess(ctx, dockerutil.ExecOpts{}, + "docker", "run", "--network", "host", "--rm", "alpine", "echo", "Hello World") + if err != nil { + t.Fatalf("docker exec failed: %v\n%s", err, output) + } + stdout, stderr, err := p.Read() + t.Logf("Container output: == stdout ==\n%s\n== stderr ==\n%s", stdout, stderr) + if err != nil { + t.Errorf("failed to read process output: %s", err) + } + if stdout != "Hello World\n" { + t.Errorf("Unexpected output: %#v", stdout) + } +} + func TestMain(m *testing.M) { dockerutil.EnsureSupportedDockerVersion() flag.Parse()