In a previous post we were discussing about glassfish installation in a VM at ~okeanos or Digital Ocean.

But when we start developing we might need also a database side by side our application server. Docker Compose is very useful, especially if we don’t want to install all these components to our system or to maximise portability. Compose is a tool that is used to define and run multiple Docker applications.

Install Docker Compose

Before using Docker Compose make sure you have installed it on your system. Instructions based on your system are provided at Docker Compose.

Create docker-compose file and organise directories

To begin with, first create a file named docker-compose.yml and place it where you need your services to take place.

$docker>mkdir services
$docker>cd services
$services>touch docker-compose.yml

To organise our services, we will create two separate directories, one for the database and one for the application server.

$services>mkdir db
$services>mkdir ws

Database setup
Lets begin with the database. For the purposes of this post we use postgres but likewise other databases such as mySQL, mongoDB etc are available in the Docker repositories.
Also, we need to create an sql script that contains the schema of the database. Lets create one and place it within the db directory:

$services>cd db
$db>touch sample-setup.sql

With a text editor or pico/nano open sample.sql and paste the following lines:

-- sample db schema
CREATE DATABASE sample;
CREATE TABLE IF NOT EXISTS user (
  key   SERIAL PRIMARY KEY,
  username  CHAR(50) NOT NULL,
  password CHAR(50) NOT NULL
);

CREATE TABLE IF NOT EXISTS customer (
  key           SERIAL PRIMARY KEY,
  user_key   INTEGER references user(key),
  first_name    CHAR(50) NOT NULL,
  last_name     CHAR(50) NOT NULL
);

Save the file and exit. Then with a text editor or pico/nano open the docker-compose file and set the following lines:

version: '2'
services:
  db:
    image: library/postgres
    volumes:
      - ./db/pgdata:/pgdata
      - ./db/sample-setup.sql:/docker-entrypoint-initdb.d/sample-setup.sql
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=docker
      - POSTGRES_PASSWORD=docker
      - PGDATA=/pgdata

version: ‘2’ signifies Compose version services: this is where the section of the services starts. The lines in the yml file need to have the proper indentation for each section. So, all lines after a section, the line with the colon (:), should be indented by two spaces.
db: this is where the section for the db setup begins.
image: the image from the Docker repository to download
volumes: a mapping of the local directories (on the left of the colon) to the directories used by the container (on the right of the colon). - ./db/pgdata:/pgdata the local directory at ./db/pgdata will be mapped to /pgdata of the postgres. If the directory doesn’t exist then it creates it automatically. - ./db/sample-setup.sql:/docker-entrypoint-initdb.d/sample-setup.sql the sample-setup.sql will be the entrypoint when the docker initialises and creates the schema if it doesn’t exist. ports: the ports used by postgres. - “5432:5432” Here we map the default port 5432 of postgres’ container to the 5432 port of the host (host is on the left of the colon, container on the right). environment: In this section we set the postgres environmental variables. - POSTGRES_USER=docker the docker user - POSTGRES_PASSWORD=docker user’s password - PGDATA=/pgdata the pgdata directory
In this phase, we can run the docker-compose file and load our database:

$services>docker-compose up

The first time that docker-compose will run, it will download image for postgres, next it will create and finally run the container. In the first run it will create the directory pgdata and it will read and execute the sample-setup.sql to create the database. Then you can connect to the database with a client that you want and populate the database with data. To stop the container, just give Ctrl-C.
All local directories in the mappings are referred to the location of the docker-compose file.
The database will hold the data no matter how many times you will start and stop the postgres container, as long as you don’t change the position of the docker-compose file or the db/pgdata directory.
 
Application Server setup
Next, we will add the application server in the docker-compose file. As mentioned in the beginning, we will use the glassfish4 application server, who’s image can be found in the docker repository.
For a simple example we would just need a war file to deploy. But in this tutorial, since we already have setup the database in the docker-compose file, we will show how to connect the glassfish container with the postgres container.
First thing to do is to copy the sample.war file to the ws directory. Next, for letting glassfish to connect to postgres, the postgres driver is needed to be placed in the lib directory. So, we copy the jar file of the postgres driver postgresql-X.X.XXXX.jar at the ws directory. These two files (war and jar) will be mapped to the proper locations within the container at the docker-compose file.
So, open again the docker-compose file and add under the last line the following:

  ws:
    image: oracle/glassfish
    volumes:
      - ./ws/postgresql-9.4.1208.jre6.jar:/glassfish4/glassfish/domains/domain1/lib/ext/postgresql-9.4.1208.jre6.jar
      - ./ws/sample.war:/glassfish4/glassfish/domains/domain1/autodeploy/sample.war
    ports:
      - "4848:4848"
      - "8080:8080"
      - "8181:8181"
    links:
      - db

Don’t forget that since ws section is under services, like db, it should be indented by two spaces as well.
image describes the docker image of glassfish
volumes map local directories and files (left of the colon) to the container’s directories and files (right to the colon): - ./ws/postgresql-9.4.1208.jre6.jar:/glassfish4/glassfish/domains/domain1/lib/ext/postgresql-9.4.1208.jre6.jar maps the postgres driver to the proper file and location - ./ws/sample.war:/glassfish4/glassfish/domains/domain1/autodeploy/sample.war maps the war file to be deployed in the autodeploy directory of the container. ports are the ports used by the glassfish container (right member) mapped to the local host’s ports (left member) - “4848:4848” administrator’s page port - “8080:8080” glassfish port - “8181:8181” secure port links links the configuration of the ws to the configuration of the db.
Previously we had only one configuration (db) and the command docker-compose up would run only the db container. Now that we added the ws configuration, the same command will run both containers at the same time.
In case we need to run only the db container run the command:

$services>docker-compose run db

Since the ws configuration has link to the db configuration, it will complain if the db is not running.