How to Dockerize JIRA with Postgres: Step-by-Step Guide

adminUncategorized

Introduction

I discovered a docker world not a long time ago. In our work, we face some testing routines almost every day. We need to test our product on different JIRA versions with different databases.

  • Of course, we can have a standalone
  • JIRA and a database installed on our machine,
  • but this approach provides complexity when we need, for example, to change the database version, port for the JIRA, run the JVM with debug support, etc. In this blog post, I want to dockerize the JIRA and database, provide the ability to debug JIRA in a docker container, and also provide some initial database state (in my case, create a database and a user).

 

Postgres service

Let’s create the docker-compose file and describe our postgres service in it. First of all, we need the postgres image. We can create it or use the official image from Docker Hub. I will choose the easiest way and use the official one for the latest 9.6.3 postgres.

version: '3'
services:
  jirapostgres:
    container_name: my_postgres_for_jira
    image: postgres:9.6.3
    ports:
      - "65432:5432"
    volumes:
      - /var/lib/postgresql/data
    networks:
      - network
 
networks:
  network:
    driver: bridge

Our docker-compose file is ready. Let’s look into it. We described the service with the name “jirapostgres”, set the container name, and chose the image for it. We define two ports. The first one is the external port. We could use it from the host machine to communicate with our postgres service. The second one is the internal port. We can use this port inside the container to access our postgres. Because each docker image is based on some Linux distributive we defined the volume where we will store our postres data. We defined the network with a bridge driver to communicate with our host machine and join our postgres service to it. Now we can start our container using the following command:

docker-compose up

We will download the image in case we didn’t download it before and start the postgres. We can check the state of our container using the command below:

docker ps

We will see something similar to this:

docker ps

But currently, we don’t have any tables in our postgres database. To create one, I need to execute commands inside my container or provide a script that can initialize the tables which will be executed by docker whenever the container starts. In the first case, I would need to do this operation each time I clean my container volumes. I don’t want to do this. I want to create the database and user when my postgres is starting. Based on the description for postgres image on the Docker Hub we need just to put some .sh or .sql file in the /docker-entrypoint-initdb.d folder inside the container. But how can we do this. To be honest, it’s quite easy. We will map a file from our host machine to some file in the container. But firstly, let’s create the config folder near our docker-compose file and create the init.sql file inside it. Also, in the future, we will need to use postgres with JIRA so it would be better to use the initialization queries from Connect Postgres With JIRA.

CREATE ROLE admin WITH LOGIN ENCRYPTED PASSWORD 'admin' SUPERUSER;
CREATE DATABASE jira WITH OWNER admin ENCODING 'UNICODE' LC_COLLATE 'C' LC_CTYPE 'C' TEMPLATE template0;
GRANT ALL PRIVILEGES ON DATABASE jira TO admin;

Now let’s map this init.sql:

version: '3'
services:
  jirapostgres:
    container_name: my_postgres_for_jira
    image: postgres:9.6.3
    ports:
      - "65432:5432"
    volumes:
      - /var/lib/postgresql/data
      - ./config/init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - network
 
networks:
  network:
    driver: bridge

Now we need to stop our container and run it again. I would recommend cleaning all the containers and volumes. You can do this with the help of:

docker-compose stop
docker-compose rm -v

When our container is up, we can check whether we have successfully created the database and user admin. We can use the pgAdmin to do this, or go to the container and check there. But I don’t like that I hard-coded the database name, user name, and password. I want to declare some environment variables in the compose file and use them as parameters in the database query. We can achieve this by switching from init.sql to init.sh script. Also, in the shell script we can place an additional check, that database we want to create doesn’t exist. Let’s do this. Firstly, we will update the compose file by replacing the SQL script with sh and providing the environment variables.

version: '3'
services:
  jirapostgres:
    container_name: my_postgres_for_jira
    image: postgres:9.6.3
    ports:
      - "65432:5432"
    volumes:
      - /var/lib/postgresql/data
      - ./config/init.sh:/docker-entrypoint-initdb.d/init.sh
    environment:
      - DB_PASS=admin
      - DB_NAME=jira
      - DB_USER=admin
    networks:
      - network
 
networks:
  network:
    driver: bridge

Now we need to transform our SQL script to shell script:

#!/bin/bash
 
EXISTS=`
psql -U postgres <<-EOSQL
  SELECT 1 FROM pg_database WHERE datname='$DB_NAME'
EOSQL
`
 
if [[ $EXISTS == "1" ]]; then
  echo "******DOCKER DATABASE ALREADY CONFIGURED******"
else
  echo "******CONFIGURING DOCKER DATABASE******"
 
  echo "Creating user"
psql -U postgres <<-EOSQL
  CREATE ROLE $DB_USER WITH LOGIN ENCRYPTED PASSWORD '${DB_PASS}' SUPERUSER;
EOSQL
 
  echo "Creating table"
psql -U postgres <<-EOSQL
  CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UNICODE' LC_COLLATE 'C' LC_CTYPE 'C' TEMPLATE template0;
EOSQL
 
  echo "Granting privileges to user"
psql -U postgres <<-EOSQL
  GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;
EOSQL
 
  echo "******DOCKER DATABASE CONFIGURED******"
fi

In the shell script, we cannot execute the SQL query directly so we need to use the postgres tool psql to do it. Also, we will execute all these queries as postgres users. The query placed inside the <<-EOSQL … EOSQL will be used as a command for psql. Also, we add the EXISTS variable to check that our database wasn’t created. Now let’s clean our container and run it one more time. We can see that we created the database and user as before with the help of sql script. But now to create another database or change the user or password we can just change the environment variables in our compose file. Now the postgres service is done. Let’s switch to JIRA service and add it to our compose file.

JIRA service

We need to create or find the existing image for JIRA. As with the postgres I will use the existing image for JIRA 7.3.6.

version: '3'
services:
 
  jiraseven:
    container_name: jira_seven_postgres
    image: cptactionhank/atlassian-jira:7.3.6
    ports:
      - "9090:8080"
    depends_on:
      - jirapostgres
    volumes:
      - /opt/jira
    networks:
      - network
 
  jirapostgres:
    container_name: my_postgres_for_jira
    image: postgres:9.6.3
    expose:
      - "5432"
    volumes:
      - /var/lib/postgresql/data
      - ./config/init.sh:/docker-entrypoint-initdb.d/init.sh
    environment:
      - DB_PASS=admin
      - DB_NAME=jira
      - DB_USER=admin
    networks:
      - network
 
networks:
  network:
    driver: bridge

You can see that the JIRA service declaration is quite the same as the jirapostgres. The new things here are that I replace the ports in jirapostgres to expose. This means that the postgres won’t be available from the host machine, but in the container network, I could use port 5432 to connect my JIRA service with postgres database. Also, currently my JIRA service depends_on jirapostgres. It means that JIRA won’t start before the postgres container. Now when we clean up and run our compose, we will see two containers upped. We can access the JIRA using localhost:9090, and configure our postgres database in JIRA. Note that inside the container to access another service we can use the service name + port. For example, in the database configuration for JIRA we can access our database by using jirapostgres as hostname and 5432 as port.

The last thing I want to do is to start JIRA in debug mode. To do this, I need to allow the JVM to be remotely bebugged. JIRA has the setenv.sh script so I just need to add the following command into some variable in it.

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

I will copy the already existing setenv.sh from JIRA service. I’ve updated it on my host side and mapped it the same way as we did it with init.sh script for the database. Also, I will need to add the additional 5005 port to my JIRA service to access it from the host machine.

Copy the setenv.sh from the container:

#execute the bash command on container
docker exec -it jira_seven_postgres bash
 
#search the file
find / -name "setenv.sh"
#result /opt/atlassian/jira/bin/setenv.sh
 
 
#exit from the container
exit
 
 
#copy from container to config folder
docker cp jira_seven_postgres:/opt/atlassian/jira/bin/setenv.sh  {path_to_docker_compose}/config

Now I will just update one line in the setenv.sh file:

JVM_SUPPORT_RECOMMENDED_ARGS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"

Add the port and map local setenv.sh. That’s it. Now when we restart our docker image, JIRA will run in debug mode and we would be able to connect to it from the host machine using 5005 port. This is the final docker-compose file, that I will use to run JIRA in debug mode and connect the postgres database to it.

version: '3'
services:
 
  jiraseven:
    container_name: jira_seven_postgres
    image: cptactionhank/atlassian-jira:7.3.6
    ports:
      - "9090:8080"
      - "5005:5005"
    depends_on:
      - jirapostgres
    volumes:
      - /opt/jira
      - ./config/setenv.sh:/opt/atlassian/jira/bin/setenv.sh
    networks:
      - network
 
  jirapostgres:
    container_name: my_postgres_for_jira
    image: postgres:9.6.3
    expose:
      - "5432"
    volumes:
      - /var/lib/postgresql/data
      - ./config/init.sh:/docker-entrypoint-initdb.d/init.sh
    environment:
      - DB_PASS=admin
      - DB_NAME=jira
      - DB_USER=admin
    networks:
      - network
 
networks:
  network:
    driver: bridge

 by Artur Meshcheriakov