Johann is a simple Java library that communicates with docker-compose CLI.
Just add Johann as a maven/gradle dependency and start using it. See Example usage for more information.
Maven dependency:
<dependency>
<groupId>io.brachu</groupId>
<artifactId>johann</artifactId>
<version>2.0.0</version>
</dependency>
Gradle dependency:
implementation 'io.brachu:johann:2.0.0'
- JDK8+ environment
- Docker Engine 17.06+
- Docker Compose 1.18+
DockerCompose compose=DockerCompose.builder().classpath().build();
DockerCompose compose=DockerCompose.builder().classpath("/custom-compose-file.yml").build();
DockerCompose compose=DockerCompose.builder().classpath("/path/to/docker-compose.yml").build();
DockerCompose compose=DockerCompose.builder().absolute("/path/to/docker-compose.yml").build();
DockerCompose compose=DockerCompose.builder()
.classpath()
.workDir("/my/custom/compose/workdir")
.build();
All relative paths in a compose file are resolved against working directory of docker-compose process. By default working directory is set to null
which means that it will be the same as working directory of Java process that starts the docker-compose process.
compose.up();
compose.waitForCluster(1,TimeUnit.MINUTES);
Calling up
method is equivalent to executing docker-compose up -d
command.
waitForCluster
method waits for all containers within a cluster to be either healthy or, if they have no health check, running.
For most consistent results in integration tests, all your containers should implement health checks.
You can read more about container health checks here.
you can customize behaviour of up
method by supplying it with a UpConfig
object.
UpConfig
object has following properties:
Property | CLI equivalent | default value |
---|---|---|
forceBuild |
--build |
false |
Example usage:
UpConfig config=UpConfig.defaults().withForceBuild(true);
compose.up(config);
compose.down();
Calling down
method is equivalent to executing docker-compose down -v
command.
You can customize behaviour of down
method by supplying it with a DownConfig
object.
DownConfig
object has following properties:
Property | CLI equivalent | default value |
---|---|---|
removeImages |
--rmi |
NONE |
removeVolumes |
-v |
true |
removeOrphans |
--remove-orphans |
false |
timeoutSeconds |
-t |
10 |
Example usage:
DownConfig config=DownConfig.defaults().withRemoveVolumes(false);
compose.down(config);
compose.kill();
Calling kill
method is equivalent to executing docker-compose kill
command.
compose.stop("postgresql");
compose.start("postgresql");
compose.waitForService("postgresql",1,TimeUnit.MINUTES);
You can stop and start multiple services at once by using varargs-flavoured stop
& start
methods. There are also stopAll
& startAll
methods
available that can stop and start all services defined in your docker-compose file.
// Order of services matters. Rabbitmq service will be stopped before postgresql.
compose.stop("rabbitmq","postgresql");
// Postgresql will start before rabbitmq
compose.start("postgresql","rabbitmq");
compose.stopAll()
compose.startAll()
DockerCompose compose=DockerCompose.builder()
.classpath()
.env("MY_ENV_VAR","my value")
.env("ANOTHER_VAR","another value")
.build();
By default, Johann uses implicitly generated project name and passes it to docker-compose
command via -p
switch.
You can override this behaviour by passing your own project name to the builder:
DockerCompose compose=DockerCompose.builder()
.classpath()
.projectName("customprojectname")
.build();
When running docker-compose up
without -p
switch, your compose cluster will be assigned a project name equal to the name of directory containing your
docker-compose.yml
file. This may lead to problems when running multiple clusters at once. Johann tries to handle this case by always passing
a project name to docker-compose
CLI. This project name can be given explicitly via builder pattern or can be generated implicitly.
The sources of implicit project name are given below, ordered by priority:
System.getProperty("maven.dockerCompose.project")
(will be used if returned value is not blank)System.getenv("COMPOSE_PROJECT_NAME")
(will be used if returned value is not blank)- Random ASCII string generator
Assuming following docker-compose.yml file:
version: '2.3'
services:
rabbitmq:
image: rabbitmq:3.6.10-alpine
ports:
- "5672"
You can easily retrieve container's IP address for rabbitmq service:
String ip=compose.containerIp("rabbitmq");
If a container is bound to multiple networks, you can pass the network name as a second argument to the ip
method:
String ip=compose.containerIp("rabbitmq","my_custom_network");
Assuming following docker-compose.yml file:
version: '2.3'
services:
rabbitmq:
image: rabbitmq:3.6.10-alpine
ports:
- "5672"
You can retrieve a host port bound to container's 5672 port by invoking Johann's port
method:
ContainerPort containerPort=compose.port("rabbitmq",5672);
int port=containerPort.getPort();
You can even use ContainerPort::format
method to create proper URL address with one-liner:
String url=compose.port("rabbitmq",5672).format("tcp://$HOST:$PORT");
compose.up();
compose.followLogs();
Logs from containers will be passed to System.out
and System.err
of currently running JVM until cluster is shut down or currently running JVM
exits.
Note that cluster should be up before calling followLogs
method. It may return prematurely otherwise and won't capture any logs.
PrintStream out = new PrintStream(...);
PrintStream err = new PrintStream(...);
compose.up();
compose.followLogs(out, err);
Johann can connect to a remote Docker Engine if DOCKER_HOST
environment variable is passed to the Java process that runs Johann.
DOCKER_TLS_VERIFY
and DOCKER_CERT_PATH
variables are also supported.
You can read more about these variables here.
Running tests located in this repository requires you to install docker and docker-compose on your local machine. Also, assuming you are running Linux distro,
user running the tests must be added to the docker
group. Version requirements are posted at the top of this README.