The DockerContainer
library provides an interface and implementations to manage Docker containers programmatically.
It simplifies the creation, execution, and interaction with containers, such as adding network configurations, mapping
ports, setting environment variables, and executing commands inside containers.
Designed specifically to support unit tests and integration tests, the library enables developers to simulate
and manage containerized environments with minimal effort, ensuring a seamless testing workflow.
composer require tiny-blocks/docker-container
Creates a container from a specified image and optionally a name.
The from
method can be used to initialize a new container instance with an image and an optional name for
identification.
$container = GenericDockerContainer::from(image: 'php:8.3-fpm', name: 'my-container');
The run
method starts a container.
Optionally, it allows you to execute commands within the container after it has started and define a condition to wait
for using a ContainerWaitAfterStarted
instance.
Example with no commands or conditions:
$container->run();
Example with commands only:
$container->run(commands: ['ls', '-la']);
Example with commands and a wait condition:
$container->run(commands: ['ls', '-la'], waitAfterStarted: ContainerWaitForTime::forSeconds(seconds: 5));
The runIfNotExists
method starts a container only if it doesn't already exist.
Optionally, it allows you to execute commands within the container after it has started and define a condition to wait
for using a ContainerWaitAfterStarted
instance.
$container->runIfNotExists();
Example with commands only:
$container->runIfNotExists(commands: ['ls', '-la']);
Example with commands and a wait condition:
$container->runIfNotExists(commands: ['ls', '-la'], waitAfterStarted: ContainerWaitForTime::forSeconds(seconds: 5));
The withNetwork
method connects the container to a specified Docker network by name, allowing you to define the
network configuration the container will use.
$container->withNetwork(name: 'my-network');
Maps ports between the host and the container.
The withPortMapping
method maps a port from the host to a port inside the container.
$container->withPortMapping(portOnHost: 9000, portOnContainer: 9000);
Maps a volume from the host to the container.
The withVolumeMapping
method allows you to link a directory from the host to the container.
$container->withVolumeMapping(pathOnHost: '/path/on/host', pathOnContainer: '/path/in/container');
Sets environment variables inside the container.
The withEnvironmentVariable
method allows you to configure environment variables within the container.
$container->withEnvironmentVariable(key: 'XPTO', value: '123');
Prevents the container from being automatically removed when stopped.
By default, Docker removes containers after they stop.
The withoutAutoRemove
method disables this feature, keeping the container around even after it finishes its
execution.
$container->withoutAutoRemove();
Copies files or directories from the host machine to the container.
The copyToContainer
method allows you to transfer files from the host system into the container’s file system.
$container->copyToContainer(pathOnHost: '/path/to/files', pathOnContainer: '/path/in/container');
The withWaitBeforeRun
method allows the container to pause its execution until a specified condition is met before
starting.
$container->withWaitBeforeRun(wait: ContainerWaitForDependency::untilReady(condition: MySQLReady::from(container: $container)));
-
When running the containers from the library on a host (your local machine), you need to map the volume
/var/run/docker.sock:/var/run/docker.sock
. This ensures that the container has access to the Docker daemon on the host machine, allowing Docker commands to be executed within the container. -
In some cases, it may be necessary to add the
docker-cli
dependency to your PHP image. This enables the container to interact with Docker from within the container environment.
Before configuring and starting the MySQL container, a PHP container is set up to execute the tests and manage the integration process.
This container runs within a Docker network and uses a volume for the database migrations. The following commands are used to prepare the environment:
-
Create the Docker network:
docker network create tiny-blocks
-
Create the volume for migrations:
docker volume create test-adm-migrations
-
Run the PHP container:
docker run -u root --rm -it --network=tiny-blocks --name test-lib \ -v ${PWD}:/app \ -v ${PWD}/tests/Integration/Database/Migrations:/test-adm-migrations \ -v /var/run/docker.sock:/var/run/docker.sock \ -w /app gustavofreze/php:8.3 bash -c "composer tests"
The MySQL container is configured and started:
$mySQLContainer = MySQLDockerContainer::from(image: 'mysql:8.1', name: 'test-database')
->withNetwork(name: 'tiny-blocks')
->withTimezone(timezone: 'America/Sao_Paulo')
->withUsername(user: 'xpto')
->withPassword(password: '123')
->withDatabase(database: 'test_adm')
->withPortMapping(portOnHost: 3306, portOnContainer: 3306)
->withRootPassword(rootPassword: 'root')
->withGrantedHosts()
->withVolumeMapping(pathOnHost: '/var/lib/mysql', pathOnContainer: '/var/lib/mysql')
->withoutAutoRemove()
->runIfNotExists();
With the MySQL container started, it is possible to retrieve data, such as the address and JDBC connection URL:
$environmentVariables = $mySQLContainer->getEnvironmentVariables();
$jdbcUrl = $mySQLContainer->getJdbcUrl();
$database = $environmentVariables->getValueBy(key: 'MYSQL_DATABASE');
$username = $environmentVariables->getValueBy(key: 'MYSQL_USER');
$password = $environmentVariables->getValueBy(key: 'MYSQL_PASSWORD');
The Flyway container is configured and only starts and executes migrations after the MySQL container is ready:
$flywayContainer = GenericDockerContainer::from(image: 'flyway/flyway:11.0.0')
->withNetwork(name: 'tiny-blocks')
->copyToContainer(pathOnHost: '/test-adm-migrations', pathOnContainer: '/flyway/sql')
->withVolumeMapping(pathOnHost: '/test-adm-migrations', pathOnContainer: '/flyway/sql')
->withWaitBeforeRun(
wait: ContainerWaitForDependency::untilReady(
condition: MySQLReady::from(
container: $mySQLContainer
)
)
)
->withEnvironmentVariable(key: 'FLYWAY_URL', value: $jdbcUrl)
->withEnvironmentVariable(key: 'FLYWAY_USER', value: $username)
->withEnvironmentVariable(key: 'FLYWAY_TABLE', value: 'schema_history')
->withEnvironmentVariable(key: 'FLYWAY_SCHEMAS', value: $database)
->withEnvironmentVariable(key: 'FLYWAY_EDITION', value: 'community')
->withEnvironmentVariable(key: 'FLYWAY_PASSWORD', value: $password)
->withEnvironmentVariable(key: 'FLYWAY_LOCATIONS', value: 'filesystem:/flyway/sql')
->withEnvironmentVariable(key: 'FLYWAY_CLEAN_DISABLED', value: 'false')
->withEnvironmentVariable(key: 'FLYWAY_VALIDATE_MIGRATION_NAMING', value: 'true')
->run(
commands: ['-connectRetries=15', 'clean', 'migrate'],
waitAfterStarted: ContainerWaitForTime::forSeconds(seconds: 5)
);
Docker container is licensed under MIT.
Please follow the contributing guidelines to contribute to the project.