Image pull policies and programmatic image building for Testcontainers. Provides control over when Docker images are pulled from registries and enables building custom images from Dockerfiles or using Google Jib.
See also:
Represents a Docker image that may need to be pulled from a registry.
/**
* Represents a Docker image from a registry that will be pulled if needed.
* Extends LazyFuture to support asynchronous image pulling.
*/
public class RemoteDockerImage extends LazyFuture<String> {
/**
* Create a remote Docker image reference.
*
* @param imageName the image name (e.g., "redis:7.0")
* @deprecated Use {@link #RemoteDockerImage(DockerImageName)} instead
*/
@Deprecated
public RemoteDockerImage(String imageName);
/**
* Create a remote Docker image reference from repository and tag.
*
* @param repository the repository name
* @param tag the image tag
* @deprecated Use {@link #RemoteDockerImage(DockerImageName)} instead
*/
@Deprecated
public RemoteDockerImage(String repository, String tag);
/**
* Create a remote Docker image reference.
*
* @param imageName the parsed Docker image name
*/
public RemoteDockerImage(DockerImageName imageName);
/**
* Create a remote Docker image reference from a Future.
*
* @param imageFuture future that resolves to an image name
*/
public RemoteDockerImage(Future<String> imageFuture);
/**
* Set the image pull policy.
*
* @param imagePullPolicy the pull policy to use
* @return this instance for method chaining
*/
public RemoteDockerImage withImagePullPolicy(ImagePullPolicy imagePullPolicy);
/**
* Set the image name substitutor.
*
* @param imageNameSubstitutor the substitutor to use for transforming image names
* @return this instance for method chaining
*/
public RemoteDockerImage withImageNameSubstitutor(ImageNameSubstitutor imageNameSubstitutor);
}Usage Example:
import org.testcontainers.images.RemoteDockerImage;
import org.testcontainers.utility.DockerImageName;
// Create a remote image reference
RemoteDockerImage image = new RemoteDockerImage(
DockerImageName.parse("postgres:15-alpine")
);
// Use with GenericContainer
GenericContainer<?> container = new GenericContainer<>(image)
.withExposedPorts(5432);Build a Docker image from a Dockerfile and use it in tests.
/**
* Build a Docker image from a Dockerfile for use in tests.
* Supports adding files from various sources and customizing the build.
*/
public class ImageFromDockerfile extends LazyFuture<String>
implements BuildContextBuilderTrait, ClasspathTrait, FilesTrait,
StringsTrait, DockerfileTrait {
/**
* Create an image builder with a temporary name.
*/
public ImageFromDockerfile();
/**
* Create an image builder with a specific tag.
*
* @param imageTag the image tag (e.g., "myapp:test")
*/
public ImageFromDockerfile(String imageTag);
/**
* Create an image builder with a tag and deletion policy.
*
* @param imageTag the image tag
* @param deleteOnExit whether to delete the image when done
*/
public ImageFromDockerfile(String imageTag, boolean deleteOnExit);
/**
* Set the Dockerfile path in the build context.
*
* @param path path to Dockerfile (relative to build context root)
* @return this builder for method chaining
* @deprecated Use {@link #withDockerfile(Path)} instead for better type safety
*/
@Deprecated
public ImageFromDockerfile withDockerfilePath(String path);
/**
* Set the Dockerfile using a Path object.
*
* @param dockerfile path to the Dockerfile
* @return this builder for method chaining
*/
public ImageFromDockerfile withDockerfile(Path dockerfile);
/**
* Add a file to the build context from a host path.
*
* @param containerPath path in build context (e.g., "app/config.json")
* @param hostPath path on host filesystem
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromPath(String containerPath, Path hostPath);
/**
* Add a file to the build context from a host path with specific file mode.
*
* @param path path in build context
* @param filePath path on host filesystem
* @param mode Unix file mode (e.g., 0755 for executable)
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromPath(String path, Path filePath, Integer mode);
/**
* Add a file to the build context from a File object with specific file mode.
*
* @param path path in build context
* @param file file to add
* @param mode Unix file mode (e.g., 0755 for executable)
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromFile(String path, File file, Integer mode);
/**
* Add a file to the build context from the classpath.
*
* @param containerPath path in build context
* @param resourcePath classpath resource path
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromClasspath(String containerPath, String resourcePath);
/**
* Add a file to the build context from a string.
*
* @param containerPath path in build context
* @param content file content as string
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromString(String containerPath, String content);
/**
* Add a file to the build context from a Transferable.
*
* @param containerPath path in build context
* @param transferable transferable content
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromTransferable(String containerPath, Transferable transferable);
/**
* Set a build argument.
*
* @param key argument name
* @param value argument value
* @return this builder for method chaining
*/
public ImageFromDockerfile withBuildArg(String key, String value);
/**
* Set multiple build arguments.
*
* @param buildArgs map of build arguments
* @return this builder for method chaining
*/
public ImageFromDockerfile withBuildArgs(Map<String, String> buildArgs);
/**
* Set the build target for multi-stage Dockerfiles.
*
* @param target the target stage name
* @return this builder for method chaining
*/
public ImageFromDockerfile withTarget(String target);
/**
* Modify the Docker build command before execution.
*
* @param modifier consumer that modifies the BuildImageCmd
* @return this builder for method chaining
*/
public ImageFromDockerfile withBuildImageCmdModifier(Consumer<BuildImageCmd> modifier);
}Usage Examples:
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.MountableFile;
import java.nio.file.Paths;
// Build from existing Dockerfile
ImageFromDockerfile simpleImage = new ImageFromDockerfile()
.withDockerfilePath("Dockerfile")
.withFileFromPath(".", Paths.get("./"));
GenericContainer<?> container1 = new GenericContainer<>(simpleImage)
.withExposedPorts(8080);
// Build with inline Dockerfile (using withFileFromString for Dockerfile content)
ImageFromDockerfile inlineImage = new ImageFromDockerfile()
.withFileFromString("Dockerfile",
"FROM nginx:alpine\n" +
"COPY index.html /usr/share/nginx/html/\n" +
"EXPOSE 80"
)
.withFileFromClasspath("index.html", "web/index.html");
// Build with build arguments
ImageFromDockerfile withArgs = new ImageFromDockerfile("myapp:test", true)
.withDockerfilePath("Dockerfile")
.withBuildArg("VERSION", "1.0.0")
.withBuildArg("ENVIRONMENT", "test")
.withFileFromPath(".", Paths.get("./"));
// Multi-stage build targeting specific stage
ImageFromDockerfile multiStage = new ImageFromDockerfile()
.withDockerfilePath("Dockerfile")
.withTarget("development")
.withFileFromPath(".", Paths.get("./"));
// Complex build with multiple files
ImageFromDockerfile complex = new ImageFromDockerfile("webapp:test")
.withFileFromString("Dockerfile",
"FROM openjdk:11-jre\n" +
"WORKDIR /app\n" +
"COPY app.jar .\n" +
"COPY config.yml .\n" +
"CMD [\"java\", \"-jar\", \"app.jar\"]"
)
.withFileFromPath("app.jar", Paths.get("target/app.jar"))
.withFileFromString("config.yml", "port: 8080\nenv: test");
GenericContainer<?> app = new GenericContainer<>(complex)
.withExposedPorts(8080);Programmatically build Dockerfile content using a fluent API.
/**
* Programmatic Dockerfile builder with fluent API.
* Supports all standard Dockerfile instructions.
*/
public class DockerfileBuilder {
/**
* FROM instruction - set base image.
*
* @param baseImage the base image
* @return this builder for method chaining
*/
public DockerfileBuilder from(String baseImage);
/**
* RUN instruction - execute command during build.
*
* @param command the command to run
* @return this builder for method chaining
*/
public DockerfileBuilder run(String... command);
/**
* CMD instruction - default command to run.
*
* @param command the command
* @return this builder for method chaining
*/
public DockerfileBuilder cmd(String... command);
/**
* ENTRYPOINT instruction - executable to run.
*
* @param entrypoint the entrypoint
* @return this builder for method chaining
*/
public DockerfileBuilder entryPoint(String... entrypoint);
/**
* EXPOSE instruction - expose ports.
*
* @param ports the ports to expose
* @return this builder for method chaining
*/
public DockerfileBuilder expose(Integer... ports);
/**
* ENV instruction - set environment variable.
*
* @param key variable name
* @param value variable value
* @return this builder for method chaining
*/
public DockerfileBuilder env(String key, String value);
/**
* ADD instruction - add file to image.
*
* @param source source path
* @param destination destination path
* @return this builder for method chaining
*/
public DockerfileBuilder add(String source, String destination);
/**
* COPY instruction - copy file to image.
*
* @param source source path
* @param destination destination path
* @return this builder for method chaining
*/
public DockerfileBuilder copy(String source, String destination);
/**
* VOLUME instruction - create mount point.
*
* @param volumes volume paths
* @return this builder for method chaining
*/
public DockerfileBuilder volume(String... volumes);
/**
* USER instruction - set user.
*
* @param user the user name or UID
* @return this builder for method chaining
*/
public DockerfileBuilder user(String user);
/**
* WORKDIR instruction - set working directory.
*
* @param workdir the working directory
* @return this builder for method chaining
*/
public DockerfileBuilder workDir(String workdir);
/**
* LABEL instruction - add metadata label.
*
* @param key label key
* @param value label value
* @return this builder for method chaining
*/
public DockerfileBuilder label(String key, String value);
/**
* Build the Dockerfile as a string.
*
* @return the Dockerfile content
*/
public String build();
}Usage Example:
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;
import org.testcontainers.images.builder.ImageFromDockerfile;
// Build Dockerfile programmatically
String dockerfile = new DockerfileBuilder()
.from("openjdk:11-jre")
.workDir("/app")
.copy("app.jar", ".")
.expose(8080)
.env("JAVA_OPTS", "-Xmx512m")
.cmd("java", "-jar", "app.jar")
.build();
// The build() method returns a String containing the generated Dockerfile:
// FROM openjdk:11-jre
// WORKDIR /app
// COPY app.jar .
// EXPOSE 8080
// ENV "JAVA_OPTS"="-Xmx512m"
// CMD ["java","-jar","app.jar"]
// Use with ImageFromDockerfile
ImageFromDockerfile image = new ImageFromDockerfile()
.withFileFromString("Dockerfile", dockerfile)
.withFileFromPath("app.jar", Paths.get("target/app.jar"));
GenericContainer<?> container = new GenericContainer<>(image)
.withExposedPorts(8080);Output Format Notes:
The build() method returns a String containing Dockerfile instructions. Note the following formatting:
ENV "KEY"="value"LABEL "key"="value"CMD ["executable","param1","param2"]ENTRYPOINT ["executable","param1"]EXPOSE 8080 8081Testcontainers uses a trait-based design pattern for composable behavior in image builders. Traits are interfaces that add specific functionality through default methods.
These traits provide methods for adding files to the Docker build context.
Base trait for adding files to build context from various sources.
/**
* Base trait for BuildContextBuilder functionality.
*/
public interface BuildContextBuilderTrait<SELF extends BuildContextBuilderTrait<SELF>> {
/**
* Add a file to the build context from a Transferable.
*
* @param path path in the build context
* @param transferable the transferable content
* @return this builder for method chaining
*/
SELF withFileFromTransferable(String path, Transferable transferable);
}Add files from Java classpath resources.
/**
* Trait for adding classpath resources to build context.
*/
public interface ClasspathTrait<SELF extends ClasspathTrait<SELF>
& BuildContextBuilderTrait<SELF> & FilesTrait<SELF>> {
/**
* Add a file from classpath to the build context.
*
* @param path destination path in build context
* @param resourcePath classpath resource path
* @return this builder for method chaining
*/
default SELF withFileFromClasspath(String path, String resourcePath);
}Usage:
new ImageFromDockerfile()
.withFileFromClasspath("config.json", "/resources/config.json")Add files from filesystem paths.
/**
* Trait for adding files from filesystem to build context.
*/
public interface FilesTrait<SELF extends FilesTrait<SELF> & BuildContextBuilderTrait<SELF>> {
/**
* Add a file from filesystem path to the build context.
*
* @param path destination path in build context
* @param filePath source file path
* @return this builder for method chaining
*/
default SELF withFileFromPath(String path, Path filePath);
}Usage:
new ImageFromDockerfile()
.withFileFromPath("app.jar", Paths.get("target/app.jar"))Add files from string content.
/**
* Trait for adding string content as files to build context.
*/
public interface StringsTrait<SELF extends StringsTrait<SELF> & BuildContextBuilderTrait<SELF>> {
/**
* Add a file from string content to the build context.
*
* @param path destination path in build context
* @param content string content
* @return this builder for method chaining
*/
default SELF withFileFromString(String path, String content);
}Usage:
new ImageFromDockerfile()
.withFileFromString("Dockerfile", "FROM nginx:latest\nCOPY index.html /usr/share/nginx/html/")Add or customize Dockerfile content.
/**
* Trait for working with Dockerfiles.
*/
public interface DockerfileTrait<SELF extends DockerfileTrait<SELF> & StringsTrait<SELF> & BuildContextBuilderTrait<SELF>> {
/**
* Set the Dockerfile path (relative to build context).
*
* @param relativePathFromBuildRoot path to Dockerfile
* @return this builder for method chaining
* @deprecated Use withDockerfile(Path) instead
*/
@Deprecated
SELF withDockerfilePath(String relativePathFromBuildRoot);
/**
* Provide Dockerfile content from a Consumer that uses DockerfileBuilder.
*
* @param builderConsumer consumer that builds Dockerfile programmatically
* @return this builder for method chaining
*/
default SELF withDockerfileFromBuilder(Consumer<DockerfileBuilder> builderConsumer);
}Usage:
new ImageFromDockerfile()
.withDockerfileFromBuilder(builder -> builder
.from("openjdk:11-jre")
.copy("app.jar", "/app/")
.cmd("java", "-jar", "/app/app.jar")
)These traits provide Dockerfile instruction methods for DockerfileBuilder.
public interface FromStatementTrait<SELF extends FromStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add FROM instruction.
* @param dockerImageName base image name
*/
default SELF from(String dockerImageName);
}public interface RunStatementTrait<SELF extends RunStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add RUN instruction (exec form).
* @param commandParts the command parts
*/
default SELF run(String... commandParts);
/**
* Add RUN instruction (shell form).
* @param command the shell command
*/
default SELF run(String command);
}public interface CmdStatementTrait<SELF extends CmdStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add CMD instruction (shell form).
* @param command the shell command
*/
default SELF cmd(String command);
/**
* Add CMD instruction (exec form).
* @param commandParts command arguments
*/
default SELF cmd(String... commandParts);
}public interface EntryPointStatementTrait<SELF extends EntryPointStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add ENTRYPOINT instruction (shell form).
* @param command the shell command
*/
default SELF entryPoint(String command);
/**
* Add ENTRYPOINT instruction (exec form).
* @param commandParts entrypoint arguments
*/
default SELF entryPoint(String... commandParts);
}public interface ExposeStatementTrait<SELF extends ExposeStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add EXPOSE instruction.
* @param ports ports to expose
*/
default SELF expose(Integer... ports);
}public interface EnvStatementTrait<SELF extends EnvStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add ENV instruction.
* @param key environment variable name
* @param value environment variable value
*/
default SELF env(String key, String value);
}public interface AddStatementTrait<SELF extends AddStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add ADD instruction.
* @param source source path
* @param destination destination path
*/
default SELF add(String source, String destination);
}public interface CopyStatementTrait<SELF extends CopyStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add COPY instruction.
* @param source source path
* @param destination destination path
*/
default SELF copy(String source, String destination);
}public interface VolumeStatementTrait<SELF extends VolumeStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add VOLUME instruction.
* @param volumes volume mount points
*/
default SELF volume(String... volumes);
}public interface UserStatementTrait<SELF extends UserStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add USER instruction.
* @param user username or UID
*/
default SELF user(String user);
}public interface WorkdirStatementTrait<SELF extends WorkdirStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add WORKDIR instruction.
* @param workDir working directory path
*/
default SELF workDir(String workDir);
}public interface LabelStatementTrait<SELF extends LabelStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add LABEL instruction.
* @param key label key
* @param value label value
*/
default SELF label(String key, String value);
}// ImageFromDockerfile implements all build context traits
ImageFromDockerfile image = new ImageFromDockerfile()
// StringsTrait
.withFileFromString("Dockerfile", "...")
// ClasspathTrait
.withFileFromClasspath("config.yml", "/config.yml")
// FilesTrait
.withFileFromPath("app.jar", Paths.get("target/app.jar"))
// BuildContextBuilderTrait
.withFileFromTransferable("script.sh", Transferable.of("#!/bin/bash\necho hello"));
// DockerfileBuilder implements all statement traits
String dockerfile = new DockerfileBuilder()
// FromStatementTrait
.from("openjdk:11-jre")
// WorkdirStatementTrait
.workdir("/app")
// CopyStatementTrait
.copy("app.jar", ".")
// EnvStatementTrait
.env("JAVA_OPTS", "-Xmx512m")
// ExposeStatementTrait
.expose(8080)
// CmdStatementTrait
.cmd("java", "-jar", "app.jar")
.build();The Transferable interface provides a flexible way to add content to Docker build contexts with precise control over file permissions.
/**
* Represents content that can be transferred into a container or Docker build context.
* Supports both file and byte array content with customizable Unix file permissions.
*/
public interface Transferable {
/**
* Default file mode for regular files (0644 = rw-r--r--).
*/
int DEFAULT_FILE_MODE = 0100644;
/**
* Default directory mode (040755 = rwxr-xr-x).
*/
int DEFAULT_DIR_MODE = 040755;
/**
* Create a Transferable from string content with default file permissions.
*
* @param string the string content
* @return Transferable instance with default file mode
*/
static Transferable of(String string);
/**
* Create a Transferable from string content with custom file permissions.
*
* @param string the string content
* @param mode Unix file mode (e.g., 0755 for executable)
* @return Transferable instance with specified mode
*/
static Transferable of(String string, int mode);
/**
* Create a Transferable from byte array with default file permissions.
*
* @param bytes the byte array content
* @return Transferable instance with default file mode
*/
static Transferable of(byte[] bytes);
/**
* Create a Transferable from byte array with custom file permissions.
*
* @param bytes the byte array content
* @param mode Unix file mode (e.g., 0755 for executable)
* @return Transferable instance with specified mode
*/
static Transferable of(byte[] bytes, int mode);
/**
* Get the file mode for this transferable.
*
* @return Unix file mode
*/
int getFileMode();
/**
* Get the size of the content in bytes.
*
* @return size in bytes
*/
long getSize();
/**
* Get the content as a byte array.
* Default implementation returns empty byte array.
*
* @return byte array of the content
*/
default byte[] getBytes();
/**
* Get a human-readable description of this transferable.
* Default implementation returns empty string.
*
* @return description string
*/
default String getDescription();
}Usage Examples:
import org.testcontainers.images.builder.Transferable;
import org.testcontainers.images.builder.ImageFromDockerfile;
// Create executable script with custom permissions
Transferable script = Transferable.of(
"#!/bin/bash\necho 'Hello from script'",
0755 // Make executable
);
ImageFromDockerfile image = new ImageFromDockerfile()
.withFileFromString("Dockerfile",
"FROM ubuntu:22.04\n" +
"COPY startup.sh /usr/local/bin/\n" +
"CMD [\"/usr/local/bin/startup.sh\"]"
)
.withFileFromTransferable("startup.sh", script);
// Create read-only configuration file
Transferable config = Transferable.of(
"setting1=value1\nsetting2=value2",
0444 // Read-only
);
// Use default permissions (0644)
Transferable readme = Transferable.of("# README\nProject documentation");
// Binary content with custom mode
byte[] binaryData = loadBinaryData();
Transferable binary = Transferable.of(binaryData, 0755);File Mode Reference:
Common Unix file modes (octal notation):
0644 (rw-r--r--) - Default for regular files, owner can write0755 (rwxr-xr-x) - Executable files, owner can write0444 (r--r--r--) - Read-only for all users0600 (rw-------) - Private file, only owner can read/write0777 (rwxrwxrwx) - Full permissions for all (use with caution)Control when Docker images are pulled from registries.
/**
* Policy interface for determining when images should be pulled.
*/
public interface ImagePullPolicy {
/**
* Determine if an image should be pulled.
*
* @param imageData metadata about the image
* @return true if the image should be pulled
*/
boolean shouldPull(DockerImageName imageName);
}
/**
* Image metadata for pull policy decisions.
* Generated by Lombok @Value and @Builder annotations.
* Only contains creation timestamp; image name is passed separately.
*/
@Value
@Builder
public class ImageData {
/**
* Get when the image was created.
* Field is accessible via Lombok-generated getter.
*
* @return image creation timestamp
*/
public Instant getCreatedAt();
/**
* Get a builder for creating ImageData instances.
* Generated by Lombok @Builder annotation.
*
* @return Builder for ImageData
*/
public static ImageDataBuilder builder();
/**
* Create ImageData from Docker inspect response.
* NOTE: This is a package-private internal API, not part of the public API.
*
* @param inspectImageResponse Docker image inspection response
* @return ImageData instance
*/
static ImageData from(InspectImageResponse inspectImageResponse);
/**
* Create ImageData from Docker image object.
* NOTE: This is a package-private internal API, not part of the public API.
*
* @param image Docker image object
* @return ImageData instance
*/
static ImageData from(Image image);
}Factory class for creating common pull policies.
/**
* Factory for creating image pull policies.
*/
public class PullPolicy {
/**
* Get the default pull policy.
* Pulls if image doesn't exist locally or has no version tag.
*
* @return default pull policy
*/
public static ImagePullPolicy defaultPolicy();
/**
* Always pull images from registry.
*
* @return always pull policy
*/
public static ImagePullPolicy alwaysPull();
/**
* Pull images older than the specified age.
*
* @param maxAge maximum age before pulling
* @return age-based pull policy
*/
public static ImagePullPolicy ageBased(Duration maxAge);
}Usage Examples:
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.images.PullPolicy;
import org.testcontainers.utility.DockerImageName;
import java.time.Duration;
// Use default policy
GenericContainer<?> container1 = new GenericContainer<>(DockerImageName.parse("redis:7.0"))
.withImagePullPolicy(PullPolicy.defaultPolicy());
// Always pull fresh image
GenericContainer<?> container2 = new GenericContainer<>(DockerImageName.parse("nginx:latest"))
.withImagePullPolicy(PullPolicy.alwaysPull());
// Pull if image is older than 7 days
GenericContainer<?> container3 = new GenericContainer<>(DockerImageName.parse("postgres:15"))
.withImagePullPolicy(PullPolicy.ageBased(Duration.ofDays(7)));NOTE: The following classes (DefaultPullPolicy, AlwaysPullPolicy, AgeBasedPullPolicy) are package-private implementation classes used internally by the PullPolicy factory. They are not part of the public API. Use the factory methods in PullPolicy class instead (e.g., PullPolicy.defaultPolicy(), PullPolicy.alwaysPull(), PullPolicy.ageBased()).
/**
* Default pull policy implementation.
* Pulls images without a version tag or if not present locally.
* Package-private - use PullPolicy.defaultPolicy() instead.
*/
class DefaultPullPolicy extends AbstractImagePullPolicy {
@Override
public boolean shouldPull(DockerImageName imageName);
@Override
protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData);
}
/**
* Always pull images from registry.
* Package-private - use PullPolicy.alwaysPull() instead.
*/
class AlwaysPullPolicy implements ImagePullPolicy {
@Override
public boolean shouldPull(DockerImageName imageName);
}
/**
* Pull images based on age threshold.
* Package-private - use PullPolicy.ageBased(Duration) instead.
*/
class AgeBasedPullPolicy extends AbstractImagePullPolicy {
/**
* Create an age-based pull policy.
*
* @param maxAge maximum age before pulling
*/
public AgeBasedPullPolicy(Duration maxAge);
@Override
public boolean shouldPull(DockerImageName imageName);
@Override
protected boolean shouldPullCached(DockerImageName imageName, ImageData localImageData);
}
/**
* Abstract base class for custom pull policies.
*/
public abstract class AbstractImagePullPolicy implements ImagePullPolicy {
@Override
public boolean shouldPull(DockerImageName imageName);
/**
* Decide whether to pull an image that exists locally.
* Override this method in custom policies to implement custom pull logic.
*
* @param imageName the Docker image name
* @param localImageData metadata about the locally available image
* @return true if the locally available image should be pulled again
*/
protected abstract boolean shouldPullCached(DockerImageName imageName, ImageData localImageData);
}Custom Pull Policy Example:
import org.testcontainers.images.AbstractImagePullPolicy;
import org.testcontainers.images.ImageData;
import java.time.Duration;
import java.time.Instant;
// Custom policy: pull development images daily, production images weekly
public class EnvironmentBasedPullPolicy extends AbstractImagePullPolicy {
@Override
protected boolean shouldPullCached(DockerImageName imageName, ImageData imageData) {
String tag = imageName.getVersionPart();
Instant createdAt = imageData.getCreatedAt();
Instant now = Instant.now();
if (tag.contains("dev") || tag.contains("snapshot")) {
// Pull if older than 1 day
return Duration.between(createdAt, now).compareTo(Duration.ofDays(1)) > 0;
} else {
// Pull if older than 7 days
return Duration.between(createdAt, now).compareTo(Duration.ofDays(7)) > 0;
}
}
}
// Usage
GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("myapp:dev"))
.withImagePullPolicy(new EnvironmentBasedPullPolicy());Build images using Google Jib (Java Image Builder) for Java applications.
/**
* Build container images using Google Jib.
* Provides faster builds and better layer optimization for Java apps.
*/
public class JibImage extends LazyFuture<String> {
/**
* Create a Jib image builder.
*
* @param baseImage the base image name
* @param jibContainerBuilderFn function to configure the Jib container builder
*/
public JibImage(String baseImage, Function<JibContainerBuilder, JibContainerBuilder> jibContainerBuilderFn);
}Usage Example:
import org.testcontainers.jib.JibImage;
import org.testcontainers.containers.GenericContainer;
import com.google.cloud.tools.jib.api.Jib;
import com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath;
import java.nio.file.Paths;
import java.util.List;
// Build Java application image with Jib
JibImage jibImage = new JibImage(
"eclipse-temurin:11-jre",
builder -> builder
.addLayer(
List.of(Paths.get("target/app.jar")),
AbsoluteUnixPath.get("/app/app.jar")
)
.setEntrypoint("java", "-jar", "/app/app.jar")
.addExposedPort(8080)
);
GenericContainer<?> container = new GenericContainer<>(jibImage)
.withExposedPorts(8080);Parse and analyze Dockerfile content to extract metadata such as base image dependencies.
/**
* Representation of a Dockerfile, with partial parsing for extraction of a minimal set of data.
*/
@Slf4j
public class ParsedDockerfile {
/**
* Constructor that parses a Dockerfile from a path.
*
* @param dockerFilePath path to the Dockerfile
*/
public ParsedDockerfile(Path dockerFilePath);
/**
* Get all base images referenced in the Dockerfile FROM statements.
*
* @return set of dependency image names as strings
*/
public Set<String> getDependencyImageNames();
}Usage Example:
// Parse a Dockerfile to extract dependencies
Path dockerfilePath = Paths.get("./Dockerfile");
ParsedDockerfile parsed = new ParsedDockerfile(dockerfilePath);
// Get all base images from FROM statements
Set<String> baseImages = parsed.getDependencyImageNames();
System.out.println("Base images: " + baseImages);
// Output: Base images: [openjdk:11-jre, nginx:alpine]Testcontainers provides specialized callbacks for monitoring and controlling image pull operations.
Callback with improved logging of pull progress, showing layer download status and statistics.
/**
* PullImageResultCallback with improved logging of pull progress.
* Package-private - used internally by Testcontainers.
*/
class LoggedPullImageResultCallback extends PullImageResultCallback {
/**
* Constructor with logger.
*
* @param logger the logger to use for progress messages
*/
LoggedPullImageResultCallback(Logger logger);
@Override
public void onStart(Closeable stream);
@Override
public void onNext(PullResponseItem item);
@Override
public void onComplete();
}Features:
Enhanced pull callback with a watchdog timer to prevent hanging pulls.
/**
* PullImageResultCallback with improved logging of pull progress and a 'watchdog'
* which will abort the pull if progress is not being made, to prevent a hanging test.
*/
public class TimeLimitedLoggedPullImageResultCallback extends LoggedPullImageResultCallback {
/**
* Constructor with logger.
*
* @param logger the logger to use for progress messages
*/
public TimeLimitedLoggedPullImageResultCallback(Logger logger);
@Override
public TimeLimitedLoggedPullImageResultCallback awaitCompletion() throws InterruptedException;
@Override
public boolean awaitCompletion(long timeout, TimeUnit timeUnit) throws InterruptedException;
@Override
public void onNext(PullResponseItem item);
@Override
public void onStart(Closeable stream);
@Override
public void onError(Throwable throwable);
@Override
public void onComplete();
}Features:
testcontainers.pull.pause.timeout propertyUsage Note:
These callbacks are used internally by Testcontainers when pulling images. The timeout behavior can be configured:
// Configure pull pause timeout in testcontainers.properties:
// testcontainers.pull.pause.timeout=60
// Or via system property:
System.setProperty("testcontainers.pull.pause.timeout", "60");import org.testcontainers.containers.GenericContainer;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;
import org.testcontainers.images.PullPolicy;
import org.testcontainers.utility.DockerImageName;
import java.nio.file.Paths;
import java.time.Duration;
public class ImageManagementExample {
public void testWithCustomImage() {
// Build custom image with inline Dockerfile
String dockerfile = new DockerfileBuilder()
.from("nginx:alpine")
.copy("nginx.conf", "/etc/nginx/nginx.conf")
.copy("html", "/usr/share/nginx/html")
.expose(80)
.build();
ImageFromDockerfile customImage = new ImageFromDockerfile("test-nginx:latest", true)
.withFileFromString("Dockerfile", dockerfile)
.withFileFromClasspath("nginx.conf", "nginx/nginx.conf")
.withFileFromPath("html", Paths.get("src/test/resources/html"));
GenericContainer<?> nginx = new GenericContainer<>(customImage)
.withExposedPorts(80);
nginx.start();
// Use container
nginx.stop();
}
public void testWithPullPolicies() {
// Production container - use cached images
GenericContainer<?> database = new GenericContainer<>(
DockerImageName.parse("postgres:15.2"))
.withImagePullPolicy(PullPolicy.defaultPolicy())
.withExposedPorts(5432);
// Development container - always pull latest
GenericContainer<?> devApp = new GenericContainer<>(
DockerImageName.parse("myapp:dev"))
.withImagePullPolicy(PullPolicy.alwaysPull())
.withExposedPorts(8080);
// Test container - pull if older than 3 days
GenericContainer<?> testApp = new GenericContainer<>(
DockerImageName.parse("myapp:test"))
.withImagePullPolicy(PullPolicy.ageBased(Duration.ofDays(3)))
.withExposedPorts(8080);
}
public void testMultiStageDockerfile() {
// Build from multi-stage Dockerfile, targeting specific stage
ImageFromDockerfile devImage = new ImageFromDockerfile()
.withDockerfilePath("Dockerfile")
.withTarget("development")
.withBuildArg("BUILD_ENV", "test")
.withFileFromPath(".", Paths.get("."));
GenericContainer<?> container = new GenericContainer<>(devImage)
.withExposedPorts(8080, 9090);
container.start();
}
}