One of the easiest ways of deploying pretty much any application is by using Docker Container. There is a plethora of hosting sites that offer container hosting, or you can choose to host your service on your own, using a dedicated server or VPS. Manually maintaining a few different docker containers with environment variables, mapped ports and volumes can be quite tedious. Here comes Docker Compose.

Docker Compose

As Docker documentation states:

Compose is a tool for defining and running multi-container Docker applications.

This means that we will be able to easily create, run and manage multiple containerized applications. For the purpose of this article, we will be creating two services: a PlayFramework backend server and PostgreSQL database. If you need to host some frontend application or some kind of administration panel you can add more services to yourdocker-compose file.

Database service – PostgreSQL

First thing we will need to do is create a docker-compose.yml file. After that we can start configuration. First thing that we need to add is a top level element: services in the first line of our file. The first service that we will create will be our database. For this we will use the PostgreSQL image. The service will be called db. Make sure your service is one indent deeper than services element and all other elements have the same number of indents as in example below.

db:
    image: postgres
    container_name: db
    restart: always
    ports:
        - "5432:5432"
    volumes:
        - ./docker/volumes/db:/var/lib/postgresql/data
    environment:
        - POSTGRES_USER=user
        - POSTGRES_PASSWORD=password
        - POSTGRES_DB=database-name 

Let’s explain this configuration:

  • db: – name of service
  • image: postgres – specifies the image that we want to use. In this instance it’s postgres.
  • container_name: db – name of the container that will be created
  • restart: always – sets restart policy for container
  • ports – maps container ports to host machine ports
  • volumes – creates a Docker volume, to store database data on the host machine
  • environment – sets container’s environment variables. PostgreSQL image allows us to create user and database on container initialization by setting environment variables.

PlayFramework server application service

Next service that we will need is our Play backend server. For this we will use a Play application image. If you don’t know how to create one, you can check out this article. We will call this service play.

play:
    image: your-apps-name:latest
    container_name: your-apps-name
    restart: always
    ports:
        - "9000:9000"
    volumes:
        - ./conf:/opt/docker/conf
        - ./docker/volumes/play/files:/opt/docker/your-app-name_files
        - ./docker/volumes/play/logs:/opt/docker/logs
    environment:
        - POSTGRES_USER=user
        - POSTGRES_PASSWORD=password
        - POSTGRES_DB=database-name
    depends_on:
        - db 

In this service we have one new element: depends_on. It will ensure that our play application will start after db, which is our database container. If you don’t know why something is set as it is in this service, you will probably find the answer in this article where we show you how to create a Play server image.

Since we use environment variables to pass database credentials and name to our Play server container, we need to change Play’s configuration file to use these variables.

 default.driver = "org.postgresql.Driver"
default.url = "jdbc:postgresql://db:5432/"${?POSTGRES_DB}
default.username = ${?POSTGRES_USER}
default.password = ${?POSTGRES_PASSWORD} 

The above database configuration will place specified variables in specific locations. First, since we are using a PostgreSQL database we need to set the correct driver. Next, in the url we want to connect to the database hosted by db service on port 5432. We can just use our service’s name with a specified port as part of our url. Then by putting ${?POSTGRES_DB} we will append the database name from environment variable to url "jdbc:postgresql://db:5432/". We will set the databases username and password in the same way – by using ${?VARIABLE_NAME}.

Environment Variables

As you may notice we had to duplicate database credentials in both services. We can simplify this by using environment variables in our docker-compose.yml file. To do this we will create .env file in the same directory as the previous file. It should look like this:

POSTGRES_USER=user

POSTGRES_PASSWORD=password

POSTGRES_DB=database-name



APP_NAME=play-app-server

 

The last variable APP_NAME will store the Play application’s name.

Now we need to tweak the docker-compose file so it will use these variables. We need to substitute database credentials with ${?VARIABLE_NAME}. Your whole docker-compose file should look similar to the one in the example below.

 services:
    db:
        image: postgres
        container_name: db
        restart: always
        ports:
            - "5432:5432"
        volumes:
            - ./docker/volumes/db:/var/lib/postgresql/data
        environment:
            - POSTGRES_USER=${POSTGRES_USER}
            - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
            - POSTGRES_DB=${POSTGRES_DB}
        play:
        image: rakbud-server:latest
        container_name: ${APP_NAME}
        restart: always
        ports:
            - "9000:9000"
        volumes:
        - ./conf:/opt/docker/conf
        - ./docker/volumes/play/files:/opt/docker/your-app-name_files
        - ./docker/volumes/play/logs:/opt/docker/logs
        environment:
            - POSTGRES_USER=${POSTGRES_USER}
            - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
            - POSTGRES_DB=${POSTGRES_DB}
        depends_on:
            - db 

 

Last step is to open our terminal, type cd into directory with docker-compose file and run:

 docker-compose config 

This command will check if the created docker-compose is correct. If it is, it will print it to terminal, where you can check if environment variables were set correctly.

Now that we have a correct docker-compose file, we can run

 docker-compose up -d 

This comment will spin up our containers in detached mode, meaning it will run containers in the background. In order to get logs from containers you need to run:

 docker-compose logs