Comprehensive APIs for building Docker container images programmatically. Testcontainers provides multiple approaches to image building: from existing Dockerfiles, programmatic Dockerfile generation, and Google Jib-based builds for Java applications.
Build a Docker image from a Dockerfile and use it in tests. Supports adding files from various sources, customizing the build, and integrating dependency image handling.
/**
* Build a Docker image from a Dockerfile for use in tests.
* Supports adding files from various sources and customizing the build.
* Extends LazyFuture to support asynchronous image building and implements
* multiple traits for composable file management and Dockerfile handling.
*/
public class ImageFromDockerfile
extends LazyFuture<String>
implements BuildContextBuilderTrait<ImageFromDockerfile>,
ClasspathTrait<ImageFromDockerfile>,
FilesTrait<ImageFromDockerfile>,
StringsTrait<ImageFromDockerfile>,
DockerfileTrait<ImageFromDockerfile> {
/**
* Create an image builder with a temporary auto-generated name.
* The image will be automatically deleted on exit.
*/
public ImageFromDockerfile();
/**
* Create an image builder with a specific tag.
* The image will be automatically deleted on exit.
*
* @param imageTag the image tag (e.g., "myapp:test", "localhost/myapp:1.0")
*/
public ImageFromDockerfile(String imageTag);
/**
* Create an image builder with a tag and deletion policy.
*
* @param imageTag the image tag (e.g., "myapp:test")
* @param deleteOnExit whether to delete the image when the JVM exits
*/
public ImageFromDockerfile(String imageTag, boolean deleteOnExit);
/**
* Set the Dockerfile path in the build context.
* Deprecated in favor of withDockerfile(Path) for better .dockerignore support.
*
* @param relativePathFromBuildContextDirectory path to Dockerfile relative to build context
* @return this builder for method chaining
* @deprecated Use {@link #withDockerfile(Path)} instead for .dockerignore support
*/
@Deprecated
public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildContextDirectory);
/**
* Set the Dockerfile using a Path object.
* Honors .dockerignore files for efficient build context transfer.
* Additionally, supports Dockerfiles that depend upon images from authenticated private registries.
*
* @param dockerfile path to the Dockerfile on the test host
* @return this builder for method chaining
*/
public ImageFromDockerfile withDockerfile(Path dockerfile);
/**
* Add a file to the build context from a host filesystem path.
* The file is added at containerPath in the Docker build context.
*
* @param containerPath path in the build context (e.g., "app/config.json")
* @param hostPath path on the host filesystem
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromPath(String containerPath, Path hostPath);
/**
* Add a file to the build context with explicit POSIX file mode.
* Allows setting permissions for the copied file (e.g., executable scripts).
*
* @param containerPath path in the build context
* @param hostPath path on the host filesystem
* @param mode octal POSIX file mode (0-777), or null for default (644)
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromPath(String containerPath, Path hostPath, Integer mode);
/**
* Add a file to the build context from a Java classpath resource.
* Classpath resources are resolved relative to the test classpath.
*
* @param containerPath path in the build context
* @param resourcePath classpath resource path (e.g., "resources/config.json")
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromClasspath(String containerPath, String resourcePath);
/**
* Add a file to the build context with content provided as a string.
* Useful for inline Dockerfiles, configuration files, or scripts.
*
* @param containerPath path in the 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 object.
* Transferable provides low-level control over content and metadata.
*
* @param containerPath path in the build context
* @param transferable transferable content object
* @return this builder for method chaining
*/
public ImageFromDockerfile withFileFromTransferable(String containerPath, Transferable transferable);
/**
* Set a single build argument for the Docker build.
* Build arguments can be referenced in the Dockerfile using $VARIABLE or ${VARIABLE}.
*
* @param key argument name (e.g., "VERSION")
* @param value argument value (e.g., "1.0.0")
* @return this builder for method chaining
*/
public ImageFromDockerfile withBuildArg(String key, String value);
/**
* Set multiple build arguments at once.
* More efficient than calling withBuildArg multiple times.
*
* @param buildArgs map of build argument key-value pairs
* @return this builder for method chaining
*/
public ImageFromDockerfile withBuildArgs(Map<String, String> buildArgs);
/**
* Set the build target for multi-stage Dockerfiles.
* Only the specified stage will be built.
*
* @param target the target stage name (e.g., "development", "production")
* @return this builder for method chaining
*/
public ImageFromDockerfile withTarget(String target);
/**
* Modify the Docker build command before execution.
* Provides low-level access to BuildImageCmd for advanced customization.
* Warning: may change outside of Testcontainers control as it exposes docker-java API.
*
* @param modifier consumer that modifies the BuildImageCmd
* @return this builder for method chaining
*/
public ImageFromDockerfile withBuildImageCmdModifier(Consumer<BuildImageCmd> modifier);
/**
* Get the Docker image name that will be built.
*
* @return the image tag/name
*/
public String getDockerImageName();
/**
* Get all transferable files that will be added to the build context.
*
* @return map of path to Transferable objects
*/
public Map<String, Transferable> getTransferables();
/**
* Get all build arguments that will be used in the build.
*
* @return map of build argument key-value pairs
*/
public Map<String, String> getBuildArgs();
}Usage Examples:
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.containers.GenericContainer;
import java.nio.file.Paths;
// Simple build from existing Dockerfile
ImageFromDockerfile simpleImage = new ImageFromDockerfile()
.withDockerfile(Paths.get("Dockerfile"))
.withFileFromPath(".", Paths.get("."));
GenericContainer<?> container1 = new GenericContainer<>(simpleImage)
.withExposedPorts(8080);
// Build with inline Dockerfile content
ImageFromDockerfile inlineImage = new ImageFromDockerfile("myapp:test")
.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)
.withDockerfile(Paths.get("Dockerfile"))
.withBuildArg("VERSION", "1.0.0")
.withBuildArg("ENVIRONMENT", "test")
.withFileFromPath(".", Paths.get("./"));
// Multi-stage build targeting specific stage
ImageFromDockerfile multiStage = new ImageFromDockerfile()
.withDockerfile(Paths.get("Dockerfile"))
.withTarget("development")
.withFileFromPath(".", Paths.get("./"));
// Complex build with multiple file sources
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);
// Build with custom file permissions (for scripts)
ImageFromDockerfile withScript = new ImageFromDockerfile()
.withFileFromString("Dockerfile",
"FROM alpine:latest\n" +
"COPY script.sh /app/\n" +
"RUN chmod +x /app/script.sh\n" +
"ENTRYPOINT [\"/app/script.sh\"]"
)
.withFileFromPath("script.sh", Paths.get("src/test/resources/script.sh"), 0755);
// Build with custom Docker build command modifiers
ImageFromDockerfile customBuild = new ImageFromDockerfile()
.withDockerfile(Paths.get("Dockerfile"))
.withBuildImageCmdModifier(cmd -> cmd.withNetworkMode("host"));Migration from Deprecated withDockerfilePath():
The withDockerfilePath(String) method is deprecated in favor of withDockerfile(Path) for better .dockerignore support and authentication with private registries. Here's how to migrate:
// OLD (deprecated approach):
new ImageFromDockerfile()
.withDockerfilePath("src/main/docker/Dockerfile")
.withFileFromPath(".", Paths.get("."));
// NEW (recommended approach):
new ImageFromDockerfile()
.withDockerfile(Paths.get("src/main/docker/Dockerfile"))
.withFileFromPath(".", Paths.get("."));Benefits of Path-based API:
Example with .dockerignore benefits:
// With Path-based API, .dockerignore is automatically honored
new ImageFromDockerfile()
.withDockerfile(Paths.get("Dockerfile"))
.withFileFromPath(".", Paths.get(".")); // Only sends non-ignored files
// Your .dockerignore file:
// node_modules/
// .git/
// *.log
// target/Programmatically build Dockerfile content using a fluent API. All Dockerfile instructions are supported with proper formatting and escaping.
/**
* Programmatic Dockerfile builder with fluent API.
* Supports all standard Dockerfile instructions.
* Implements all statement traits for instruction methods.
*/
public class DockerfileBuilder
implements DockerfileBuilderTrait<DockerfileBuilder>,
FromStatementTrait<DockerfileBuilder>,
AddStatementTrait<DockerfileBuilder>,
CopyStatementTrait<DockerfileBuilder>,
RunStatementTrait<DockerfileBuilder>,
CmdStatementTrait<DockerfileBuilder>,
WorkdirStatementTrait<DockerfileBuilder>,
EnvStatementTrait<DockerfileBuilder>,
LabelStatementTrait<DockerfileBuilder>,
ExposeStatementTrait<DockerfileBuilder>,
EntryPointStatementTrait<DockerfileBuilder>,
VolumeStatementTrait<DockerfileBuilder>,
UserStatementTrait<DockerfileBuilder> {
/**
* Create a new Dockerfile builder instance.
*/
public DockerfileBuilder();
/**
* FROM instruction - set the base image.
* Must be the first instruction in a valid Dockerfile.
*
* @param baseImage the base image name (validated)
* @return this builder for method chaining
* @throws IllegalArgumentException if baseImage is invalid
*/
public DockerfileBuilder from(String baseImage);
/**
* RUN instruction - execute command during build.
* Can accept a single command string or multiple parts that form a command.
*
* @param command the command to run (single string)
* @return this builder for method chaining
*/
public DockerfileBuilder run(String command);
/**
* RUN instruction - execute command with multiple parts.
* Parts are combined appropriately for shell execution.
*
* @param commandParts parts of the command
* @return this builder for method chaining
*/
public DockerfileBuilder run(String... commandParts);
/**
* CMD instruction - default command to run when container starts.
* Can accept a single command string or multiple parts (exec form).
*
* @param command the default command
* @return this builder for method chaining
*/
public DockerfileBuilder cmd(String command);
/**
* CMD instruction - default command in exec form.
* Each part becomes a separate JSON array element.
*
* @param commandParts parts of the command (executable and parameters)
* @return this builder for method chaining
*/
public DockerfileBuilder cmd(String... commandParts);
/**
* ENTRYPOINT instruction - executable to run when container starts.
* Can accept a single command string or multiple parts (exec form).
*
* @param entrypoint the entrypoint command
* @return this builder for method chaining
*/
public DockerfileBuilder entryPoint(String entrypoint);
/**
* ENTRYPOINT instruction - executable in exec form.
* Each part becomes a separate JSON array element.
*
* @param entrypointParts parts of the entrypoint
* @return this builder for method chaining
*/
public DockerfileBuilder entryPoint(String... entrypointParts);
/**
* EXPOSE instruction - document which ports the container listens on.
* Ports listed here are informational; they don't actually publish ports.
*
* @param ports port numbers to expose
* @return this builder for method chaining
*/
public DockerfileBuilder expose(Integer... ports);
/**
* ENV instruction - set an environment variable.
* Variable is available during build and at runtime.
*
* @param key variable name
* @param value variable value
* @return this builder for method chaining
*/
public DockerfileBuilder env(String key, String value);
/**
* ENV instruction - set multiple environment variables.
* More efficient than calling env(String, String) multiple times.
*
* @param entries map of variable key-value pairs
* @return this builder for method chaining
*/
public DockerfileBuilder env(Map<String, String> entries);
/**
* ADD instruction - add file to image from build context or remote URL.
* Performs automatic extraction of compressed files.
*
* @param source source path (in build context or URL)
* @param destination destination path in image
* @return this builder for method chaining
*/
public DockerfileBuilder add(String source, String destination);
/**
* COPY instruction - copy file from build context to image.
* Simpler and more predictable than ADD; preferred when not extracting archives.
*
* @param source source path in build context
* @param destination destination path in image
* @return this builder for method chaining
*/
public DockerfileBuilder copy(String source, String destination);
/**
* VOLUME instruction - create a mount point in the image.
* Indicates that the container should use a volume at this path.
*
* @param volumes volume mount point paths
* @return this builder for method chaining
*/
public DockerfileBuilder volume(String... volumes);
/**
* USER instruction - set the user that subsequent commands run as.
* Can be a username or numeric UID.
*
* @param user the user name or UID
* @return this builder for method chaining
*/
public DockerfileBuilder user(String user);
/**
* WORKDIR instruction - set the working directory for subsequent commands.
* If the directory doesn't exist, it will be created.
*
* @param workdir the working directory path
* @return this builder for method chaining
*/
public DockerfileBuilder workDir(String workdir);
/**
* LABEL instruction - add metadata label to the image.
* Labels can be queried at runtime.
*
* @param key label key
* @param value label value
* @return this builder for method chaining
*/
public DockerfileBuilder label(String key, String value);
/**
* LABEL instruction - add multiple metadata labels.
* More efficient than calling label(String, String) multiple times.
*
* @param entries map of label key-value pairs
* @return this builder for method chaining
*/
public DockerfileBuilder label(Map<String, String> entries);
/**
* Build the Dockerfile as a string.
* Returns complete Dockerfile content ready to be written to a file or used inline.
*
* @return the Dockerfile content as a String
*/
public String build();
/**
* Get all statements that have been added to this builder.
* Used internally for building the final Dockerfile.
*
* @return list of Statement objects
*/
public List<Statement> getStatements();
}Formatting Notes:
The build() method returns a String containing properly formatted Dockerfile instructions:
ENV "KEY"="value"LABEL "key"="value"CMD ["executable","param1","param2"]ENTRYPOINT ["executable","param1"]EXPOSE 8080 8081Usage Example:
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;
import org.testcontainers.images.builder.ImageFromDockerfile;
import java.nio.file.Paths;
// Build Dockerfile programmatically
String dockerfile = new DockerfileBuilder()
.from("openjdk:11-jre")
.workDir("/app")
.copy("app.jar", ".")
.expose(8080)
.env("JAVA_OPTS", "-Xmx512m")
.label("version", "1.0")
.label("maintainer", "team@example.com")
.cmd("java", "-jar", "app.jar")
.build();
// Generated Dockerfile output:
// FROM openjdk:11-jre
// WORKDIR /app
// COPY app.jar .
// EXPOSE 8080
// ENV "JAVA_OPTS"="-Xmx512m"
// LABEL "version"="1.0"
// LABEL "maintainer"="team@example.com"
// 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);
// Multi-stage example
String multiStageDockerfile = new DockerfileBuilder()
.from("maven:3.8-openjdk-11 AS builder")
.workDir("/build")
.copy("pom.xml", ".")
.copy("src", "src")
.run("mvn clean package -DskipTests")
.from("openjdk:11-jre")
.workDir("/app")
.copy("--from=builder", "/build/target/app.jar", ".")
.expose(8080)
.cmd("java", "-jar", "app.jar")
.build();Low-level interface for providing custom content to the Docker build context. Used internally by higher-level traits and can be implemented for custom content sources.
/**
* Interface for transferable content to Docker build context.
* Provides abstraction over content source and destination in build context.
*/
public interface Transferable {
/**
* Default file mode for transferred files (0100644 - regular file, read-write for owner).
*/
int DEFAULT_FILE_MODE = 0100644;
/**
* Default mode for transferred directories (040755 - directory, rwx for owner, rx for others).
*/
int DEFAULT_DIR_MODE = 040755;
/**
* Create a Transferable from a string.
* String is encoded as UTF-8 bytes.
*
* @param string content as string
* @return Transferable instance
*/
static Transferable of(String string);
/**
* Create a Transferable from a string with custom file mode.
* String is encoded as UTF-8 bytes.
*
* @param string content as string
* @param fileMode octal POSIX file mode (0-777)
* @return Transferable instance
*/
static Transferable of(String string, int fileMode);
/**
* Create a Transferable from a byte array.
* Uses default file mode.
*
* @param bytes content as bytes
* @return Transferable instance
*/
static Transferable of(byte[] bytes);
/**
* Create a Transferable from a byte array with custom file mode.
*
* @param bytes content as bytes
* @param fileMode octal POSIX file mode (0-777)
* @return Transferable instance
*/
static Transferable of(byte[] bytes, int fileMode);
/**
* Get the file mode for this transferable.
* Default is 0100644 (regular file with 644 permissions).
*
* @return octal POSIX file mode
*/
default int getFileMode();
/**
* Get the size of this transferable in bytes.
*
* @return size in bytes
*/
long getSize();
/**
* Transfer content to TAR archive output stream.
* Called by framework to write content to build context.
* Default implementation creates TAR entry and writes bytes.
*
* @param tarArchiveOutputStream the TAR output stream
* @param destination path in the build context where content will be written
*/
default void transferTo(TarArchiveOutputStream tarArchiveOutputStream, String destination);
/**
* Get the byte content of this transferable.
* Default implementation returns empty array; override for actual content.
*
* @return byte array containing content
*/
default byte[] getBytes();
/**
* Get a description of this transferable for logging.
* Default implementation returns empty string.
*
* @return description string
*/
default String getDescription();
/**
* Update a checksum with this transferable's content.
* Used for content verification.
*
* @param checksum the checksum to update
*/
default void updateChecksum(Checksum checksum);
}Factory Method Examples:
import org.testcontainers.images.builder.Transferable;
import org.testcontainers.images.builder.ImageFromDockerfile;
// Create Transferable from string
Transferable scriptContent = Transferable.of(
"#!/bin/bash\necho 'Hello World'"
);
// Create Transferable with custom file mode (executable)
Transferable executableScript = Transferable.of(
"#!/bin/bash\necho 'Hello World'",
0755 // Executable permissions
);
// Create Transferable from byte array
byte[] binaryData = new byte[] { 0x00, 0x01, 0x02, 0x03 };
Transferable binary = Transferable.of(binaryData);
// Create Transferable with custom file mode
Transferable binaryWithMode = Transferable.of(binaryData, 0644);
// Use with ImageFromDockerfile
ImageFromDockerfile image = new ImageFromDockerfile()
.withFileFromTransferable("script.sh", executableScript)
.withFileFromTransferable("data.bin", binary)
.withFileFromString("Dockerfile",
"FROM alpine:latest\n" +
"COPY script.sh /app/\n" +
"COPY data.bin /app/\n" +
"RUN chmod +x /app/script.sh\n" +
"ENTRYPOINT [\"/app/script.sh\"]"
);Testcontainers uses a trait-based design pattern for composable behavior in image builders. Traits are interfaces that add specific functionality through default methods. ImageFromDockerfile implements multiple traits for flexible file management.
Base trait for adding files to Docker build context from various sources.
/**
* Base trait for BuildContextBuilder functionality.
* Provides the foundation for all other trait composition.
*/
public interface BuildContextBuilderTrait<SELF extends BuildContextBuilderTrait<SELF>> {
/**
* Add a file to the build context from a Transferable.
* Low-level method that all other file addition methods delegate to.
*
* @param path path in the build context where file will be written
* @param transferable the transferable content
* @return this builder for method chaining
*/
SELF withFileFromTransferable(String path, Transferable transferable);
}Add files from Java classpath resources to the Docker build context.
/**
* 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.
* Resource is resolved from the Java classpath (e.g., src/test/resources).
*
* @param path destination path in build context
* @param resourcePath classpath resource path (e.g., "config/app.yml")
* @return this builder for method chaining
*/
default SELF withFileFromClasspath(String path, String resourcePath);
}Usage:
new ImageFromDockerfile()
.withFileFromClasspath("config.yml", "resources/config.yml")
.withFileFromClasspath("app.properties", "config/app.properties")Add files from filesystem paths (NIO Path API) to the build context.
/**
* 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.
* Uses NIO Path API for file handling.
*
* @param path destination path in build context
* @param filePath source file path on host filesystem
* @return this builder for method chaining
*/
default SELF withFileFromPath(String path, Path filePath);
/**
* Add a file from filesystem path with custom POSIX file mode.
* Allows setting permissions for the copied file.
*
* @param path destination path in build context
* @param filePath source file path on host filesystem
* @param mode octal POSIX file mode (0-777), or null for default
* @return this builder for method chaining
*/
default SELF withFileFromPath(String path, Path filePath, Integer mode);
/**
* Add a file from File object to the build context.
* Convenience method for File API.
*
* @param path destination path in build context
* @param file source file
* @return this builder for method chaining
*/
default SELF withFileFromFile(String path, File file);
/**
* Add a file from File object with custom POSIX file mode.
*
* @param path destination path in build context
* @param file source file
* @param mode octal POSIX file mode (0-777), or null for default
* @return this builder for method chaining
*/
default SELF withFileFromFile(String path, File file, Integer mode);
}Usage:
import java.nio.file.Paths;
new ImageFromDockerfile()
.withFileFromPath("app.jar", Paths.get("target/app.jar"))
.withFileFromPath("script.sh", Paths.get("scripts/run.sh"), 0755)
.withFileFromFile("config.xml", new File("src/main/resources/config.xml"))Add files from string content to the build context.
/**
* 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.
* String is encoded as UTF-8 bytes.
*
* @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/")
.withFileFromString("config.yml", "server:\n port: 8080\n host: 0.0.0.0")
.withFileFromString("index.html", "<h1>Hello World</h1>")Add or customize Dockerfile content using various approaches.
/**
* Trait for working with Dockerfiles in image builders.
*/
public interface DockerfileTrait<SELF extends DockerfileTrait<SELF> & StringsTrait<SELF> & BuildContextBuilderTrait<SELF>> {
/**
* Set the Dockerfile path (relative to build context).
* Deprecated in favor of withDockerfile(Path).
*
* @param relativePathFromBuildRoot path to Dockerfile
* @return this builder for method chaining
* @deprecated Use {@link ImageFromDockerfile#withDockerfile(Path)} instead
*/
@Deprecated
SELF withDockerfilePath(String relativePathFromBuildRoot);
/**
* Provide Dockerfile content from a Consumer that uses DockerfileBuilder.
* Allows programmatic Dockerfile generation using fluent API.
* Content is generated lazily when the image is built.
*
* @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/")
.expose(8080)
.cmd("java", "-jar", "/app/app.jar")
)These traits provide Dockerfile instruction methods for DockerfileBuilder. Each trait corresponds to a Dockerfile instruction and is implemented using Statement objects internally.
Base trait that provides the foundation for statement-based Dockerfile building.
/**
* Base trait for DockerfileBuilder statement functionality.
*/
public interface DockerfileBuilderTrait<SELF extends DockerfileBuilderTrait<SELF>> {
/**
* Get the statements list (for internal framework use).
*
* @return list of Statement objects
*/
List<Statement> getStatements();
/**
* Add a statement to the builder.
* Used internally by statement traits.
*
* @param statement the statement to add
* @return this builder for method chaining
*/
default SELF withStatement(Statement statement);
}Add FROM instruction to specify base image.
public interface FromStatementTrait<SELF extends FromStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add FROM instruction (must be first instruction).
* @param dockerImageName base image name (validated)
* @return this builder for method chaining
*/
default SELF from(String dockerImageName);
}Add RUN instructions for executing commands during build.
public interface RunStatementTrait<SELF extends RunStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add RUN instruction with single command.
* @param command the shell command to execute
* @return this builder for method chaining
*/
default SELF run(String command);
/**
* Add RUN instruction with command parts.
* Parts are combined for shell execution.
* @param commandParts parts of the command
* @return this builder for method chaining
*/
default SELF run(String... commandParts);
}Add CMD instruction for default container command.
public interface CmdStatementTrait<SELF extends CmdStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add CMD instruction (single form).
* @param command the default command
* @return this builder for method chaining
*/
default SELF cmd(String command);
/**
* Add CMD instruction (exec form).
* Each argument becomes a separate JSON array element.
* @param commandParts command executable and parameters
* @return this builder for method chaining
*/
default SELF cmd(String... commandParts);
}Add ENTRYPOINT instruction for container executable.
public interface EntryPointStatementTrait<SELF extends EntryPointStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add ENTRYPOINT instruction (single form).
* @param command the entrypoint command
* @return this builder for method chaining
*/
default SELF entryPoint(String command);
/**
* Add ENTRYPOINT instruction (exec form).
* Each argument becomes a separate JSON array element.
* @param entrypointParts entrypoint executable and parameters
* @return this builder for method chaining
*/
default SELF entryPoint(String... entrypointParts);
}Add EXPOSE instructions for documenting container ports.
public interface ExposeStatementTrait<SELF extends ExposeStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add EXPOSE instruction.
* Ports are space-separated in the generated Dockerfile.
* @param ports port numbers to expose
* @return this builder for method chaining
*/
default SELF expose(Integer... ports);
}Add ENV instructions for environment variables.
public interface EnvStatementTrait<SELF extends EnvStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add ENV instruction (single variable).
* @param key environment variable name
* @param value environment variable value
* @return this builder for method chaining
*/
default SELF env(String key, String value);
/**
* Add ENV instruction (multiple variables).
* @param entries map of variable key-value pairs
* @return this builder for method chaining
*/
default SELF env(Map<String, String> entries);
}Add ADD instructions for adding files from build context or remote URLs.
public interface AddStatementTrait<SELF extends AddStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add ADD instruction.
* Automatically extracts compressed files (.tar.gz, .zip, etc).
* @param source source path (in build context or URL)
* @param destination destination path in image
* @return this builder for method chaining
*/
default SELF add(String source, String destination);
}Add COPY instructions for copying files from build context.
public interface CopyStatementTrait<SELF extends CopyStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add COPY instruction.
* Simpler and more predictable than ADD.
* @param source source path in build context
* @param destination destination path in image
* @return this builder for method chaining
*/
default SELF copy(String source, String destination);
}Add VOLUME instructions for declaring mount points.
public interface VolumeStatementTrait<SELF extends VolumeStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add VOLUME instruction.
* Declares mount points for persistent data.
* @param volumes volume mount point paths
* @return this builder for method chaining
*/
default SELF volume(String... volumes);
}Add USER instructions for setting execution user.
public interface UserStatementTrait<SELF extends UserStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add USER instruction.
* @param user username or numeric UID
* @return this builder for method chaining
*/
default SELF user(String user);
}Add WORKDIR instructions for setting working directory.
public interface WorkdirStatementTrait<SELF extends WorkdirStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add WORKDIR instruction.
* Sets working directory for subsequent commands.
* @param workDir working directory path
* @return this builder for method chaining
*/
default SELF workDir(String workDir);
}Add LABEL instructions for image metadata.
public interface LabelStatementTrait<SELF extends LabelStatementTrait<SELF> & DockerfileBuilderTrait<SELF>> {
/**
* Add LABEL instruction (single label).
* @param key label key
* @param value label value
* @return this builder for method chaining
*/
default SELF label(String key, String value);
/**
* Add LABEL instruction (multiple labels).
* @param entries map of label key-value pairs
* @return this builder for method chaining
*/
default SELF label(Map<String, String> entries);
}// 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)
// UserStatementTrait
.user("appuser")
// CmdStatementTrait
.cmd("java", "-jar", "app.jar")
.build();Build Docker images using Google Jib (Java Image Builder) for optimized Java application containerization. Jib builds images without requiring a Docker daemon and provides better layer caching.
/**
* Build container images using Google Jib.
* Provides faster builds and better layer optimization for Java applications.
* Does not require Docker daemon for building (but does for Testcontainers use).
*/
public class JibImage extends LazyFuture<String> {
/**
* Create a Jib image builder.
* The builder function is applied to customize the Jib container builder.
*
* @param baseImage the base image name (e.g., "eclipse-temurin:11-jre")
* @param jibContainerBuilderFn function to configure JibContainerBuilder
* (receives base builder, returns customized 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.JibContainerBuilder;
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);
container.start();
// ... use container ...
container.stop();
// More complex Jib example with layers
JibImage complexJib = new JibImage(
"eclipse-temurin:11-jre",
builder -> builder
.addLayer(
List.of(Paths.get("target/dependencies/*.jar")),
AbsoluteUnixPath.get("/app/lib/")
)
.addLayer(
List.of(Paths.get("target/app.jar")),
AbsoluteUnixPath.get("/app/")
)
.addEnvironmentVariable("JAVA_TOOL_OPTIONS", "-Xmx512m")
.setEntrypoint("java", "-jar", "/app/app.jar")
.addLabel("version", "1.0")
.addLabel("maintainer", "team@example.com")
);Advantages of JibImage:
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;
import org.testcontainers.images.builder.Transferable;
import org.testcontainers.jib.JibImage;
import org.testcontainers.utility.DockerImageName;
import java.nio.file.Paths;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers
public class ImageBuildingExample {
/**
* Example 1: Build from existing Dockerfile with additional files
*/
@Test
public void testBuildFromExistingDockerfile() {
ImageFromDockerfile customImage = new ImageFromDockerfile("myapp:test")
.withDockerfile(Paths.get("Dockerfile"))
.withFileFromPath(".", Paths.get("src/main/resources"))
.withFileFromPath("target/app.jar", Paths.get("target/app.jar"));
GenericContainer<?> container = new GenericContainer<>(customImage)
.withExposedPorts(8080)
.withEnv("LOG_LEVEL", "DEBUG");
container.start();
// Test container
container.stop();
}
/**
* Example 2: Build with programmatic Dockerfile generation
*/
@Test
public void testBuildWithProgrammaticDockerfile() {
String dockerfile = new DockerfileBuilder()
.from("maven:3.8-openjdk-11")
.workDir("/app")
.copy("pom.xml", ".")
.run("mvn dependency:resolve")
.copy("src", "src")
.run("mvn clean package -DskipTests")
.expose(8080)
.cmd("java", "-jar", "target/app.jar")
.build();
ImageFromDockerfile image = new ImageFromDockerfile("maven-build:test")
.withFileFromString("Dockerfile", dockerfile)
.withFileFromPath("pom.xml", Paths.get("pom.xml"))
.withFileFromPath("src", Paths.get("src"));
GenericContainer<?> container = new GenericContainer<>(image)
.withExposedPorts(8080);
container.start();
container.stop();
}
/**
* Example 3: Multi-stage build with build arguments
*/
@Test
public void testMultiStageDockerfileBuild() {
String multiStageDockerfile = new DockerfileBuilder()
.from("maven:3.8-openjdk-11 AS builder")
.workDir("/build")
.copy("pom.xml", ".")
.copy("src", "src")
.run("mvn clean package -DskipTests")
.from("openjdk:11-jre AS runtime")
.workDir("/app")
.copy("--from=builder", "/build/target/app.jar", ".")
.expose(8080)
.user("appuser")
.cmd("java", "-jar", "app.jar")
.build();
ImageFromDockerfile image = new ImageFromDockerfile("multiapp:test")
.withFileFromString("Dockerfile", multiStageDockerfile)
.withFileFromPath("pom.xml", Paths.get("pom.xml"))
.withFileFromPath("src", Paths.get("src"))
.withBuildArg("JAVA_VERSION", "11")
.withBuildArg("MAVEN_VERSION", "3.8");
GenericContainer<?> container = new GenericContainer<>(image)
.withExposedPorts(8080);
container.start();
container.stop();
}
/**
* Example 4: Build with inline files and custom scripts
*/
@Test
public void testBuildWithInlineFiles() {
String entrypoint = "#!/bin/bash\n" +
"set -e\n" +
"echo 'Starting application...'\n" +
"exec java -jar /app/app.jar\n";
ImageFromDockerfile image = new ImageFromDockerfile()
.withFileFromString("Dockerfile",
"FROM openjdk:11-jre-slim\n" +
"WORKDIR /app\n" +
"COPY app.jar .\n" +
"COPY entrypoint.sh .\n" +
"RUN chmod +x entrypoint.sh\n" +
"EXPOSE 8080\n" +
"ENTRYPOINT [\"/app/entrypoint.sh\"]\n"
)
.withFileFromPath("app.jar", Paths.get("target/app.jar"))
.withFileFromPath("entrypoint.sh", Paths.get("scripts/entrypoint.sh"), 0755);
GenericContainer<?> container = new GenericContainer<>(image)
.withExposedPorts(8080)
.withEnv("JAVA_OPTS", "-Xmx512m");
container.start();
container.stop();
}
/**
* Example 5: Build using Jib for Java applications
*/
@Test
public void testBuildWithJib() {
JibImage jibImage = new JibImage(
"eclipse-temurin:11-jre",
builder -> builder
.addLayer(
java.util.List.of(Paths.get("target/app.jar")),
com.google.cloud.tools.jib.api.buildplan.AbsoluteUnixPath.get("/app/")
)
.setEntrypoint("java", "-jar", "/app/app.jar")
.addExposedPort(8080)
.addEnvironmentVariable("JAVA_OPTS", "-Xmx512m")
.addLabel("version", "1.0")
);
GenericContainer<?> container = new GenericContainer<>(jibImage)
.withExposedPorts(8080);
container.start();
container.stop();
}
/**
* Example 6: Complex build with mixed file sources
*/
@Test
public void testComplexBuild() {
String dockerfile = new DockerfileBuilder()
.from("openjdk:11-jre")
.workDir("/app")
.copy("app.jar", ".")
.copy("config", "config")
.env("CONFIG_DIR", "/app/config")
.expose(8080, 8081)
.label("app-name", "testapp")
.label("version", "1.0")
.user("appuser")
.cmd("java", "-jar", "app.jar")
.build();
ImageFromDockerfile image = new ImageFromDockerfile("complex-app:test", true)
.withFileFromString("Dockerfile", dockerfile)
.withFileFromPath("app.jar", Paths.get("target/app.jar"))
.withFileFromPath("config", Paths.get("src/main/resources/config"))
.withFileFromClasspath("application.yml", "application.yml")
.withBuildArg("BUILD_DATE", java.time.LocalDate.now().toString());
GenericContainer<?> container = new GenericContainer<>(image)
.withExposedPorts(8080, 8081)
.withEnv("LOG_LEVEL", "INFO")
.withEnv("ENVIRONMENT", "test");
container.start();
// Verify container is running
assert container.isRunning();
container.stop();
}
}This documentation covers all the primary image building APIs available in Testcontainers, with detailed method signatures, parameter documentation, and practical examples demonstrating various use cases from simple file additions to complex multi-stage builds with programmatic Dockerfile generation.