Skip to content

Build from Dockerfile

Testcontainers for Go gives you the ability to build an image and run a container from a Dockerfile.

You can do so by specifying a Context (the filepath to the build context on your local filesystem) and optionally a Dockerfile (defaults to "Dockerfile") like so:

FromDockerfile: FromDockerfile{
    Context:    "testdata",
    Dockerfile: "echo.Dockerfile",
    Repo:       "test-repo",
    Tag:        "test-tag",
},

As you can see, you can also specify the Repo and Tag optional fields to use for the image. If not passed, the image will be built with a random name and tag.

If your Dockerfile expects build args:

FROM alpine@sha256:51b67269f354137895d43f3b3d810bfacd3945438e94dc5ac55fdac340352f48

ARG FOO
You can specify them like:

ba := "build args value"
req := ContainerRequest{
    FromDockerfile: FromDockerfile{
        Context:    filepath.Join(".", "testdata"),
        Dockerfile: "args.Dockerfile",
        BuildArgs: map[string]*string{
            "FOO": &ba,
        },
    },
    ExposedPorts: []string{"8080/tcp"},
    WaitingFor:   wait.ForLog("ready"),
}

Dynamic Build Context

If you would like to send a build context that you created in code (maybe you have a dynamic Dockerfile), you can send the build context as an io.Reader since the Docker Daemon accepts it as a tar file, you can use the tar package to create your context.

To do this you would use the ContextArchive attribute in the FromDockerfile struct.

var buf bytes.Buffer
tarWriter := tar.NewWriter(&buf)
// ... add some files
if err := tarWriter.Close(); err != nil {
    // do something with err
}
reader := bytes.NewReader(buf.Bytes())
fromDockerfile := testcontainers.FromDockerfile{
    ContextArchive: reader,
}

Please Note if you specify a ContextArchive this will cause Testcontainers for Go to ignore the path passed in to Context.

Ignoring files in the build context

The same as Docker has a .dockerignore file to ignore files in the build context, Testcontainers for Go also supports this feature. A .dockerignore living in the root of the build context will be used to filter out files that should not be sent to the Docker daemon. The .dockerignore file won't be sent to the Docker daemon either.

Note

At this moment, Testcontainers for Go does not support Dockerfile-specific .dockerignore files.

Images requiring auth

If you are building a local Docker image that is fetched from a Docker image in a registry requiring authentication (e.g., assuming you are fetching from a custom registry such as myregistry.com), Testcontainers for Go will automatically discover the credentials for the given Docker image from the Docker config, as described here.

req := ContainerRequest{
    FromDockerfile: testcontainers.FromDockerfile{
        Context: "/path/to/build/context",
        Dockerfile: "CustomDockerfile",
    },
}

Keeping built images

Per default, built images are deleted after being used. However, some images you build might have no or only minor changes during development. Building them for each test run might take a lot of time. You can avoid this by setting KeepImage in FromDockerfile. If the image is being kept, cached layers might be reused during building or even the whole image.

req := ContainerRequest{
    FromDockerfile: testcontainers.FromDockerfile{
        // ...
        KeepImage: true,
    },
}

Advanced usage

In the case you need to pass additional arguments to the docker build command, you can use the BuildOptionsModifier attribute in the FromDockerfile struct.

This field holds a function that has access to Docker's ImageBuildOptions type, which is used to build the image. You can use this modifier on your own risk to modify the build options with as many options as you need.

c, err := GenericContainer(ctx, GenericContainerRequest{
    ContainerRequest: ContainerRequest{
        FromDockerfile: FromDockerfile{
            Context:    "testdata",
            Dockerfile: "target.Dockerfile",
            KeepImage:  false,
            BuildOptionsModifier: func(buildOptions *types.ImageBuildOptions) {
                buildOptions.Target = "target2"
            },
        },
    },
    Started: true,
})
FROM alpine AS target0
CMD ["echo", "target0"]

FROM target0 AS target1
CMD ["echo", "target1"]

FROM target1 AS target2
CMD ["echo", "target2"]