Skip to content

Image name substitution

Testcontainers for Go supports automatic substitution of Docker image names.

This allows the replacement of an image name specified in test code with an alternative name - for example, to replace the name of a Docker Hub image dependency with an alternative hosted on a private image registry.

This is advisable to avoid Docker Hub rate limiting, and some companies will prefer this for policy reasons.

Info

As of November 2020 Docker Hub pulls are rate limited. As Testcontainers uses Docker Hub for standard images, some users may hit these rate limits and should mitigate accordingly. Suggested mitigations are noted in this issue in Testcontainers for Java at present.

This page describes two approaches for image name substitution:

Warning

It is assumed that you have already set up a private registry hosting all the Docker images your build requires.

Automatically modifying Docker Hub image names

Testcontainers for Go can be configured to modify Docker Hub image names on the fly to apply a prefix string.

Consider this if:

  • Developers and CI machines need to use different image names. For example, developers are able to pull images from Docker Hub, but CI machines need to pull from a private registry.
  • Your private registry has copies of images from Docker Hub where the names are predictable, and just adding a prefix is enough. For example, registry.mycompany.com/mirror/mysql:8.0.36 can be derived from the original Docker Hub image name (mysql:8.0.36) with a consistent prefix string: registry.mycompany.com/mirror

In this case, image name references in code are unchanged. i.e. you would leave as-is:

req := testcontainers.ContainerRequest{
    Image:      "alpine",
    Cmd:        []string{"echo", "-n", "I was not expecting this"},
    WaitingFor: wait.ForLog("I was expecting this").WithStartupTimeout(5 * time.Second),
}

You can then configure Testcontainers for Go to apply a given prefix (e.g. registry.mycompany.com/mirror) to every image that it tries to pull from Docker Hub. Important to notice that the prefix should not include a trailing slash. This can be done in one of two ways:

  • Setting the TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX=registry.mycompany.com/mirror environment variable.
  • Via config file, setting hub.image.name.prefix in the ~/.testcontainers.properties file in your user home directory.

Testcontainers for Go will automatically apply the prefix to every image that it pulls from Docker Hub - please verify that all the required images exist in your registry.

Testcontainers for Go will not apply the prefix to:

  • non-Hub image names (e.g. where another registry is set)
  • Docker Hub image names where the hub registry is explicitly part of the name (i.e. anything with a registry.hub.docker.com host part)

Developing a custom function for transforming image names on the fly

Consider this if:

  • You have complex rules about which private registry images should be used as substitutes, e.g.:
    • non-deterministic mapping of names meaning that a name prefix cannot be used, or
    • rules depending upon developer identity or location, or
  • you wish to add audit logging of images used in the build, or
  • you wish to prevent accidental usage of images that are not on an approved list.

In this case, image name references in code are unchanged. i.e. you would leave as-is:

req := testcontainers.ContainerRequest{
    Image:      "alpine",
    Cmd:        []string{"echo", "-n", "I was not expecting this"},
    WaitingFor: wait.ForLog("I was expecting this").WithStartupTimeout(5 * time.Second),
}

You can implement a custom image name substitutor by:

  • implementing the ImageNameSubstitutor interface, exposed by the testcontainers package.
  • configuring Testcontainers for Go to use your custom implementation, defined at the ContainerRequest level.

The following is an example image substitutor implementation prepending the registry.hub.docker.com/library/ prefix, used in the tests:

// ImageSubstitutor represents a way to substitute container image names
type ImageSubstitutor interface {
    // Description returns the name of the type and a short description of how it modifies the image.
    // Useful to be printed in logs
    Description() string
    Substitute(image string) (string, error)
}
type dockerImageSubstitutor struct{}

func (s dockerImageSubstitutor) Description() string {
    return "DockerImageSubstitutor (prepends registry.hub.docker.com)"
}

func (s dockerImageSubstitutor) Substitute(image string) (string, error) {
    return "registry.hub.docker.com/library/" + image, nil
}
ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
    ContainerRequest: testcontainers.ContainerRequest{
        Image:             "alpine:latest",
        ImageSubstitutors: []testcontainers.ImageSubstitutor{dockerImageSubstitutor{}},
    },
    Started: true,
})
defer func() {
    if err := testcontainers.TerminateContainer(ctr); err != nil {
        log.Printf("failed to terminate container: %s", err)
    }
}()

Images used by Testcontainers

As of the current version of Testcontainers (v0.34.0):