- Overview
- Installation
- How to use
- Creating a container
- Running a container
- Running if not exists
- Pulling images in parallel
- Setting network
- Setting port mappings
- Setting volume mappings
- Setting environment variables
- Disabling auto-remove
- Copying files to a container
- Stopping a container
- Stopping on shutdown
- Executing commands after startup
- Wait strategies
- MySQL container
- Flyway container
- Usage examples
- License
- Contributing
Manage Docker containers programmatically, simplifying the creation, running, and interaction with containers.
The library provides interfaces and implementations for adding network configurations, mapping ports, setting environment variables, and executing commands inside containers. Designed to support unit tests and integration tests, it enables developers to manage containerized environments with minimal effort.
composer require tiny-blocks/docker-containerCreates a container from a specified image and an optional name.
$container = GenericDockerContainer::from(image: 'php:8.5-fpm', name: 'my-container');Starts a container. Optionally accepts commands to run on startup and a wait strategy applied after the container starts.
$container->run();With commands:
$container->run(commands: ['ls', '-la']);With commands and a wait strategy:
$container->run(commands: ['ls', '-la'], waitAfterStarted: ContainerWaitForTime::forSeconds(seconds: 5));Starts a container only if a container with the same name is not already running.
$container->runIfNotExists();Calling pullImage() starts downloading the image in the background via a non-blocking process. When run() or
runIfNotExists() is called, it waits for the pull to complete before starting the container.
To pull multiple images in parallel, call pullImage() on all containers before calling run() on any of
them. This way the downloads happen concurrently:
$mysql = MySQLDockerContainer::from(image: 'mysql:8.4', name: 'my-database')
->pullImage()
->withRootPassword(rootPassword: 'root');
$flyway = FlywayDockerContainer::from(image: 'flyway/flyway:12-alpine')
->pullImage()
->withMigrations(pathOnHost: '/path/to/migrations');
// Both images are downloading in the background.
// MySQL pull completes here, container starts and becomes ready.
$mySQLStarted = $mysql->runIfNotExists();
// Flyway pull already finished while MySQL was starting.
$flyway->withSource(container: $mySQLStarted, username: 'root', password: 'root')
->cleanAndMigrate();Sets the Docker network the container should join. The network is created automatically when the container is
started via run() or runIfNotExists(), if it does not already exist. Networks created by the library are
labeled with tiny-blocks.docker-container=true for safe cleanup.
$container->withNetwork(name: 'my-network');Maps a port from the host to the container.
$container->withPortMapping(portOnHost: 8080, portOnContainer: 80);After the container starts, both ports are available through the Address:
$ports = $started->getAddress()->getPorts();
$ports->firstExposedPort(); // 80 (container-internal)
$ports->firstHostPort(); // 8080 (host-accessible)Mounts a directory from the host into the container.
$container->withVolumeMapping(pathOnHost: '/host/data', pathOnContainer: '/container/data');Adds an environment variable to the container.
$container->withEnvironmentVariable(key: 'APP_ENV', value: 'testing');By default, containers are removed when stopped. This disables that behavior.
$container->withoutAutoRemove();Registers files or directories to be copied from the host into the container after it starts.
$container->copyToContainer(pathOnHost: '/path/to/files', pathOnContainer: '/path/in/container');Stops a running container. An optional timeout (in seconds) controls how long to wait before forcing the stop. The default timeout is 300 seconds.
$started = $container->run();
$result = $started->stop();With a custom timeout:
$result = $started->stop(timeoutInWholeSeconds: 60);Registers the container to be forcefully removed when the PHP process exits. On shutdown, the following cleanup is performed automatically:
- The container is killed and removed (
docker rm --force --volumes). - Anonymous volumes created by the container (e.g., MySQL's
/var/lib/mysql) are removed. - Unused networks created by the library are pruned.
Only resources labeled with tiny-blocks.docker-container=true are affected. Containers, volumes, and networks
from other environments are never touched.
$started = $container->run();
$started->stopOnShutdown();Runs commands inside an already-started container.
$started = $container->run();
$result = $started->executeAfterStarted(commands: ['php', '-v']);The returned ExecutionCompleted provides the command output and success status:
$result->getOutput();
$result->isSuccessful();Pauses execution for a specified number of seconds before or after starting a container.
$container->withWaitBeforeRun(wait: ContainerWaitForTime::forSeconds(seconds: 3));Blocks until a readiness condition is satisfied, with a configurable timeout. This is useful when one container depends on another being fully ready.
$mySQLStarted = MySQLDockerContainer::from(image: 'mysql:8.4')
->withRootPassword(rootPassword: 'root')
->run();
$container = GenericDockerContainer::from(image: 'my-app:latest')
->withWaitBeforeRun(
wait: ContainerWaitForDependency::untilReady(
condition: MySQLReady::from(container: $mySQLStarted),
timeoutInSeconds: 30
)
)
->run();MySQLDockerContainer provides a specialized container for MySQL databases. It extends the generic container with
MySQL-specific configuration and automatic readiness detection.
| Method | Parameter | Description |
|---|---|---|
withTimezone |
$timezone |
Sets the container timezone (e.g., America/Sao_Paulo). |
withUsername |
$user |
Sets the MySQL user created on startup. |
withPassword |
$password |
Sets the password for the MySQL user. |
withDatabase |
$database |
Sets the default database created on startup. |
withRootPassword |
$rootPassword |
Sets the root password for the MySQL instance. |
withGrantedHosts |
$hosts |
Sets hosts granted root privileges (default: ['%', '172.%']). |
$mySQLContainer = MySQLDockerContainer::from(image: 'mysql:8.4', name: 'my-database')
->withTimezone(timezone: 'America/Sao_Paulo')
->withUsername(user: 'app_user')
->withPassword(password: 'secret')
->withDatabase(database: 'my_database')
->withPortMapping(portOnHost: 3306, portOnContainer: 3306)
->withRootPassword(rootPassword: 'root')
->withGrantedHosts()
->run();Configures how long the MySQL container waits for the database to become ready before throwing a
ContainerWaitTimeout exception. The default timeout is 30 seconds.
$mySQLContainer = MySQLDockerContainer::from(image: 'mysql:8.4', name: 'my-database')
->withRootPassword(rootPassword: 'root')
->withReadinessTimeout(timeoutInSeconds: 60)
->run();After the MySQL container starts, connection details are available through the MySQLContainerStarted instance.
$address = $mySQLContainer->getAddress();
$ip = $address->getIp();
$hostname = $address->getHostname();
$ports = $address->getPorts();
$containerPort = $ports->firstExposedPort(); // e.g. 3306 (container-internal)
$hostPort = $ports->firstHostPort(); // e.g. 49153 (host-accessible)
$environmentVariables = $mySQLContainer->getEnvironmentVariables();
$database = $environmentVariables->getValueBy(key: 'MYSQL_DATABASE');
$username = $environmentVariables->getValueBy(key: 'MYSQL_USER');
$password = $environmentVariables->getValueBy(key: 'MYSQL_PASSWORD');
$jdbcUrl = $mySQLContainer->getJdbcUrl();Use firstExposedPort() when connecting from another container in the same network.
Use firstHostPort() when connecting from the host machine (e.g., tests running outside Docker).
FlywayDockerContainer provides a specialized container for running Flyway database migrations. It encapsulates
Flyway configuration, database source detection, and migration file management.
Configures the Flyway container to connect to a running MySQL container. Automatically detects the JDBC URL and
target schema from MYSQL_DATABASE, and sets the history table to schema_history.
$flywayContainer = FlywayDockerContainer::from(image: 'flyway/flyway:12-alpine')
->withNetwork(name: 'my-network')
->withMigrations(pathOnHost: '/path/to/migrations')
->withSource(container: $mySQLStarted, username: 'root', password: 'root');The schema and table can be overridden after calling withSource():
$flywayContainer
->withSource(container: $mySQLStarted, username: 'root', password: 'root')
->withSchema(schema: 'custom_schema')
->withTable(table: 'custom_history');Sets the host directory containing Flyway migration SQL files. The files are copied into the container at
/flyway/migrations.
$flywayContainer->withMigrations(pathOnHost: '/path/to/migrations');| Method | Parameter | Description |
|---|---|---|
withTable |
$table |
Overrides the history table name (default: schema_history). |
withSchema |
$schema |
Overrides the target schema (default: auto-detected from MySQL). |
withCleanDisabled |
$disabled |
Enables or disables Flyway's clean command. |
withConnectRetries |
$retries |
Sets the number of database connection retries. |
withValidateMigrationNaming |
$enabled |
Enables or disables migration naming validation. |
| Method | Flyway command | Description |
|---|---|---|
migrate() |
migrate |
Applies pending migrations. |
validate() |
validate |
Validates applied migrations against local. |
repair() |
repair |
Repairs the schema history table. |
cleanAndMigrate() |
clean migrate |
Drops all objects and re-applies migrations. |
$flywayContainer->migrate();
$flywayContainer->cleanAndMigrate();- When running the containers from the library on a host (your local machine), map the volume
/var/run/docker.sock:/var/run/docker.sockso the container has access to the Docker daemon on the host machine. - In some cases, it may be necessary to add the
docker-clidependency to your PHP image to interact with Docker from within the container.
Configure both containers and start image pulls in parallel before running either one:
$mySQLContainer = MySQLDockerContainer::from(image: 'mysql:8.4', name: 'test-database')
->pullImage()
->withNetwork(name: 'my-network')
->withTimezone(timezone: 'America/Sao_Paulo')
->withPassword(password: 'secret')
->withDatabase(database: 'test_adm')
->withRootPassword(rootPassword: 'root')
->withGrantedHosts();
$flywayContainer = FlywayDockerContainer::from(image: 'flyway/flyway:12-alpine')
->pullImage()
->withNetwork(name: 'my-network')
->withMigrations(pathOnHost: '/path/to/migrations')
->withCleanDisabled(disabled: false)
->withConnectRetries(retries: 5)
->withValidateMigrationNaming(enabled: true);
$mySQLStarted = $mySQLContainer->runIfNotExists();
$mySQLStarted->stopOnShutdown();
$flywayContainer
->withSource(container: $mySQLStarted, username: 'root', password: 'root')
->cleanAndMigrate();Docker container is licensed under MIT.
Please follow the contributing guidelines to contribute to the project.