Home » DevOps » Docker » Docker Compose example

About Raquel Pau

Raquel Pau
Raquel has graduated from Computer Engineering in the Universitat Politecnica de Catalunya. She also holds a Master degree in Computation (Software Engineering) from the same university. She has an I+D profile focused about model driven development. Additionally, she is the project leader of Walkmod, an open source project to code conventions, which is part of the result of her interest in the model driven development. Currently, Raquel works as a Software Architect in the Sparsity-Technologies.

Docker Compose example

1. Introduction

Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you define in a configuration file the set of docker containers that application requires an specific machine. Then, using a single command, you create and start all the services in a single host.

Docker Compose is specially useful for the following use case scenarios:

  • Create a development environment with all the required services started only using your own machine. In other words, stop to prepare your development environment manually over and over again in your own or different machines.
  • Automate test environments with the same characteristics than the production environments and run integration tests.
  • Single hosts deployments– that is use a machine with different services as docker containers. The most recommended way to do so is using the Docker machine or Docker swarm because you can launch docker compose remotely from your laptop in a safe way without requiring SSH.
 
To use Docker Compose, you just need to create configuration file called docker-compose.yml, which contains the specification to create and run a set of docker containers. Let’s try to create an example with a web application that uses a redis database server.

docker-compose

docker-compose

2. Docker Toolbox setup

Docker compose is one of the included tools into the Docker toolbox. To install Docker toolbox, you just need to download the appropriate installer from here for your operative system and execute it.

Docker Toolbox contains the following tools:

  • Docker Compose : to create runtime environments with multiple docker containers in one machine.
  • Docker Machine : to dynamically run docker commands to remote machines or in the local/default one.
  • Docker Kitematic : to Build and run containers through a graphical user interface (GUI).
  • VirtualBox : to run Docker.
  • Docker client: to create and run docker containers.

Once you have finished the installation procedure, you should be able to run docker-compose --help, which prints the accepted subcommands.

3. Docker compose example: An HTTP server connected to Redis

This example is about a web application for create a TODO list using Redis with basically a three steps:

  1. Define how to run the web and database docker images in docker-compose.yml so they can be run together in an isolated environment.
  2. Create the web application and its Dockerfile to create the runtime environment anywhere.
  3. Lastly, run docker-compose up and Compose will start and run your entire app.

3.1 Creating the docker-compose.yml file

Create an empty project called todos and copy the following docker-compose.yml inside the project directory.

docker-compose.yml

web:
  build: .
  ports:
   - "8000:8000"
  links:
   - redis
redis:
  image: redis

This file specifies two containers: web, which contains our Java code to launch a web server and redis server. Notice that in the first case, appears the build property, whereas the second case, the image property. It means that in order web container needs to build a Docker image that appears in our local file system. However, for the redis server, the image is downloaded from the DockerHub repository.

With this docker-compose.yml file, Compose simulates two machines with different IP addresses in a same local network because they are linked (i.e link property). However, only the web is externally through the 8000 of our docker-machine and Docker creates a binding between this port and the container 8000 port.

3.2 Creating the web server

Now, let’s create the Dockerfile that Compose requires in the same directory than the docker-compose.yml file with the following contents.

Dockerfile

FROM ubuntu:14.04
MAINTAINER javacodegeeks

RUN apt-get update && apt-get install -y python-software-properties software-properties-common
RUN add-apt-repository ppa:webupd8team/java

RUN echo "oracle-java8-installer shared/accepted-oracle-license-v1-1 boolean true" | debconf-set-selections

RUN apt-get update && apt-get install -y oracle-java8-installer maven

ADD . /usr/local/todolist
RUN cd /usr/local/todolist && mvn assembly:assembly
CMD ["java", "-cp", "/usr/local/todolist/target/todolist-1.0-jar-with-dependencies.jar", "com.javacodegeeks.todolist.TodoServer"]

This Dockerfile builds our todolist project with Maven and starts an specific Java class. Thus, it is necessary to convert our todolist project into a Maven project. To do so, copy the following pom.xml in the project directory (the same place than Dockerfile and docker-compose.yml.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javacodegeeks</groupId>
	<artifactId>todolist</artifactId>
	<version>1.0</version>
	<dependencies>
		<dependency>
			<groupId>biz.paluch.redis</groupId>
			<artifactId>lettuce</artifactId>
			<version>3.3.2.Final</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.6.3</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<version>2.6</version>
				<configuration>
					<descriptorRefs>
						<descriptorRef>jar-with-dependencies</descriptorRef>
					/descriptorRefs>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

This POM file uses lettuce( a Java Redis client) and jackson and commons-io as a utility libraries for coding basic HTTP server in only one Java class. Create this class with the following code:

src/main/java/com/javacodegeeks/todolist/TodoServer.java

package com.javacodegeeks.todolist;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import org.apache.commons.io.IOUtils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lambdaworks.redis.RedisClient;
import com.lambdaworks.redis.RedisConnection;
import com.lambdaworks.redis.ValueScanCursor;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class TodoServer {

	public static void main(String[] args) throws Exception {
		HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
		server.createContext("/", new MyHandler(System.getenv("REDIS_PORT")));
		server.setExecutor(null); // creates a default executor
		server.start();
	}

	static class MyHandler implements HttpHandler {

		private RedisClient redisClient;
		private RedisConnection connection;
		private ObjectMapper mapper;

		public MyHandler(String redisURL) throws MalformedURLException {

			String hostPortURL = redisURL.substring("tcp://".length());
			int separator = hostPortURL.indexOf(':');
			redisClient = new RedisClient(hostPortURL.substring(0, separator),
					Integer.parseInt(hostPortURL.substring(separator + 1)));
			connection = redisClient.connect();
			mapper = new ObjectMapper();
		}

		public void handle(HttpExchange t) throws IOException {
			String method = t.getRequestMethod();
			OutputStream os = t.getResponseBody();
			String response = "";
			
			if (t.getRequestURI().getPath().equals("/todos")) {
				if (method.equals("GET")) {
					ValueScanCursor cursor = connection.sscan("todos");
					List tasks = cursor.getValues();
					response = mapper.writeValueAsString(tasks);

				} else if (method.equals("PUT")) {

					connection.sadd("todos", IOUtils.toString(t.getRequestBody()));
				}
			}

			t.sendResponseHeaders(200, response.length());
			os.write(response.getBytes());
			os.close();
		}

		@Override
		public void finalize() {
			connection.close();
			redisClient.shutdown();
		}
	}
}

Notice that the TodoServer is assuming that the Redis connection URL appears in an environment variable called REDIS_PORT. However, how to know the names of the available environment variables? Docker defines an standard way to do so here.

3.3 Lauching Docker Compose

All the elements for the example are ready now. So, open your prompt, go to the project directory and run:

Docker-Compose up command

docker-compose up

Voila! At this moment, we have an HTTP server connected with Redis in our default docker-machine. In order to discover the IP of the default docker-machine, run the following command.

Docker-Machine ip command

$docker-machine ip default
192.168.99.100

3.4 Testing the web server

Using the output of the previous command, we can test the web server using the curl command. The available options are:

  • Create new tasks:
     
    CURL command to create new tasks

    curl -X PUT --data "new task" http://192.168.99.100:8000/todos
  • List all tasks:
     
    CURL command to List all tasks

    curl -X GET http://192.168.99.100:8000/todos

4. Download the complete source code

This is an example of how running a Java program with Docker Compose.

Download
You can download the full source code of this example here: docker-compose example
(No Ratings Yet)
Start the discussion Views Tweet it!

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

 

Leave a Reply

avatar
  Subscribe  
Notify of