I have been using Atlassian products for quite a while now, both with clients and my own company.
Jira is an incredibly effective tool to aid a delivery lifecycle, and although it’s geared towards scrum and kanban agile methodologies, it can cater for so much more.
Confluence is a fantastic repository, allowing you to build informational and collaborative webpages and store documentation. It’s far more intuitive, less memory intensive, and more user friendly than Sharepoint.
Bitbucket is a graphical layer over git, and again is very straightforward for managing data and code repositories.
In the past, I have deployed these tools directly to Linux servers, and that hasn’t been so straightforward. Any updates to the core functionality was often fraught with issues, even if you built a script particular to your configuration to make sure the upgrade was successful.
Enter Docker. By using a Docker Compose script, you can deploy all three tools and a MySQL instance to support them. There is additional configuration that needs to be carried out for each tool, but rather than repeat documentation, I recommend that you read the help pages for each one.
Atlassian on Docker Documentation
I am assuming that you know enough about Atlassian products and Docker to do the basic configuration – this article simply explains how you can use a Docker Compose script to maintain them and include a healthcheck for each instance.
Running the Docker Compose File
If you just want to go ahead and run the Docker Compose file (using the command line, or something handy like Portainer) then you can copy the full script below.
However it is worth reading through the sections so you have a full understanding of the configuration, and the minimal tweaks that have been done to allow it to work with MySQL.
Environment Settings
Whilst similar values are used between Bitbucket, Confluence and Jira, for some reason the variables used by Bitbucket are different!
For Bitbucket, the JDBC settings specify the MySQL user and password to connect to the database, with the URL specifying the server, port, database name and parameters required for connection. For Confluence and Jira, these are specified as ATL_JDBC settings. I have used the particularly imaginative user name of “atlassian”, which you can of course change, but you do need to set your own password.
In all three cases, I have the servers running behind a reverse proxy so that I can connect to them using a domain name and SSL. So the SERVER_PROXY or ATL_PROXY settings define your domain, proxy port and whether you are using https or not (you should be!).
Confluence and Jira have some additional settings to specify the database type and which driver to use for MySQL. On top of that, they also specify the internal port used to connect to the application (typically 8090 for Confluence and 8080 for Jira).
Bitbucket Environment Settings
- JDBC_PASSWORD={password}
- JDBC_URL=jdbc:mysql://localhost:3306/bitbucketdb?useUnicode=true&characterEncoding=UTF8&sessionVariables=default_storage_engine=InnoDB&autoReconnect=true&useSSL=false
- JDBC_USER=atlassian
- SERVER_PROXY_NAME=bitbucket.yourdomain.com
- SERVER_PROXY_PORT=443
- SERVER_SCHEME=https
- SERVER_SECURE=true
Confluence and Jira Environment Settings
- ATL_DB_DRIVER=com.mysql.jdbc.Driver
- ATL_DB_TYPE=mysql
- ATL_JDBC_PASSWORD={password}
- ATL_JDBC_URL=jdbc:mysql://localhost:3306/confluencedb?useUnicode=true&autoReconnect=true&useSSL=false
- ATL_JDBC_USER=atlassian
- ATL_PROXY_NAME=confluence.yourdomain.com
- ATL_PROXY_PORT=443
- ATL_TOMCAT_PORT=8090
- ATL_TOMCAT_SCHEME=https
- ATL_TOMCAT_SECURE=true
The depends_on Parameter
The depends_on
parameter is really quite simple – it tells Docker Compose that the container that is being created (Bitbucket, Confluence or Jira) needs MySQL and if that isn’t available, the container can’t be created.
This doesn’t check to see that MySQL is up and running successfully however: just that the MySQL container exists. To perform extra validation, you need to run an external script, something that is beyond the scope of this article. Prior to version 3 of Docker Compose, you were able to use the term condition
, but that has since been deprecated.
Docker themselves do explain how it can be done.
- mysql
Atlassian Healthchecks
test: 'curl localhost:7990/status | grep -q RUNNING'
interval: 1m
start_period: 10m
timeout: 10s
I have added a section in to the Docker Compose file for each container which periodically checks to see if the container is up and running.
All Atlassian tools have an API that can be called which returns the status of the service, so by adding in a test
which calls the API and then checks to see if the response is “RUNNING”, we can determine if the container is healthy or not.
The interval
parameter tells Docker how often to carry out the check. For me, one minute is more than enough.
The start_period
parameter tells Docker to ignore the health check for the given period whilst the container starts up. As Atlassian tools can take a while to load up, I have set this to 10 minutes.
The last parameter, timeout
, tells Docker when to mark the container as unhealthy if it gets no response from the test.
MySQL Healthcheck
test: '/usr/bin/mysql --user=healthcheck --password=healthcheck --execute "SHOW DATABASES;"'
interval: 1m
start_period: 1m
timeout: 10s
start_period
to one minute.
For the test
parameter, I am calling the mysql command and logging in with a user called “healthcheck”. That user then simply runs a SHOW DATABASES
SQL command against the instance and if it gets a response, then the container is up and running.
The last thing you want is to include a user and password on a command line that has significant amounts of access to the database. So, once the MySQL database is up and running, you will want to run the following command, to just allow the “healthcheck” user to run the SHOW DATABASES
command and nothing else.
Granting Permission for the Healthcheck User in MySQL
CREATE USER 'healthcheck'@'localhost' IDENTIFIED BY 'healthcheck';
GRANT SHOW DATABASES ON *.* TO 'healthcheck'@'localhost';
FLUSH PRIVILEGES;
- /docker/bitbucket:/var/atlassian/application-data/bitbucket:rw
- /docker/configuration/mysql-connector-java-5.1.48-bin.jar:/var/atlassian/application-data/bitbucket/lib/mysql-connector-java-5.1.48-bin.jar:rw
Bitbucket Volumes
The Bitbucket volumes are straightforward: The first configures an external directory hosted on your client Linux server (in this case, found at /docker/bitbucket) to be used for any Bitbucket data files. This ensures that whenever you update the Bitbucket container, your data is not lost.
The second references the MySQL Java connector that is needed by Bitbucket to connect to MySQL. The version that can be used by Bitbucket is 5.1.* unlike Confluence and Jira, which can use newer versions.
Confluence and Jira Volumes
The first two volumes for Confluence and Jira are similar to Bitbucket, in that they point to the external directory for your data and the MySQL Java Connector respectively. I’ve pointed Confluence and Jira to a newer version of the connector than Bitbucket, but they will happily all run on a 5.1.* version.
The last volume for Confluence and Jira is to store the log files, which can be handy if you need to dig deeper into any issues that happen with the Atlassian tools.
- /docker/confluence:/var/atlassian/application-data/confluence:rw
- /docker/configuration/mysql-connector-java-8.0.21.jar:/opt/atlassian/confluence/confluence/WEB-INF/lib/mysql-connector-java-8.0.21.jar:rw
- /docker/confluence/logs:/opt/atlassian/confluence/logs:rw
MySQL Volumes
For MySQL, we are again creating a volume, in this case /docker/mysql, to store the MySQL data and databases.
The second parameter is one I have added for the mysql.cnf, which stores all the configuration values needed to allow the Atlassian tools to interoperate with MySQL.I found it convenient to keep this, along with the MySQL Java connectors in one place, so that they could easily be modified or updated if necessary.
- /docker/mysql:/var/lib/mysql:rw
- /docker/configuration/conf.d/mysql.cnf:/etc/mysql/conf.d/my.cnf:rw
MySQL mysql.cnf File for Atlassian
[mysqld]
# MySQL used for Atlassian services
# Atlassian Service Requirements
binlog_format=row
character_set_server=utf8mb4
collation_server=utf8mb4_bin
default_storage_engine=INNODB
innodb_log_file_size=2G
log-bin-trust-function-creators=1
max_allowed_packet=256M
transaction_isolation=READ-COMMITTED
# InnoDB Configuration
innodb_default_row_format=DYNAMIC
innodb_file_per_table=ON
lower_case_table_names=0
MySQL Root Password
The first time that the Docker Compose script is run, the MySQL database needs a root password set. This parameter is used once and then ignored in the future.
After the first run, and you have created the “atlassian” and “healthcheck” users in MySQL, remove this parameter from the Docker Compose script and redeploy.
The Atlassian tools will then correctly use the Atlassian user to connect to the MySQL database and you can complete the installation.
- MYSQL_ROOT_PASSWORD={password}
Granting Permissions for the Atlassian User in MySQL
CREATE USER 'atlassian'@'localhost' IDENTIFIED BY '{password}';
GRANT USAGE ON *.* TO 'atlassian'@'localhost';
GRANT EXECUTE, SELECT, SHOW VIEW, ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, INDEX, INSERT, REFERENCES, TRIGGER, UPDATE, LOCK TABLES ON `bitbucketdb`.* TO 'atlassian'@'localhost' WITH GRANT OPTION;
GRANT EXECUTE, SELECT, SHOW VIEW, ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, INDEX, INSERT, REFERENCES, TRIGGER, UPDATE, LOCK TABLES ON `confluencedb`.* TO 'atlassian'@'localhost' WITH GRANT OPTION;
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER ON `JIRADB`.* TO 'atlassian'@'localhost';
GRANT EXECUTE, SELECT, SHOW VIEW, ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, INDEX, INSERT, REFERENCES, TRIGGER, UPDATE, LOCK TABLES ON `jiradb`.* TO 'atlassian'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
The Docker Compose Script in its Entirety
And there you have it: Three Atlassian tools deployed in Docker and using MySQL with one Compose file. With luck, all your Containers will be showing as “healthy” (as it does in my Portainer view below).

The Final Docker Compose Script
version: '3'
services:
atlassian-bitbucket:
container_name: Bitbucket
environment:
- JDBC_PASSWORD={password}
- JDBC_URL=jdbc:mysql://localhost:3306/bitbucketdb?useUnicode=true&characterEncoding=UTF8&sessionVariables=default_storage_engine=InnoDB&autoReconnect=true&useSSL=false
- JDBC_USER=atlassian
- SERVER_PROXY_NAME=bitbucket.yourdomain.com
- SERVER_PROXY_PORT=443
- SERVER_SCHEME=https
- SERVER_SECURE=true
depends_on:
- mysql
healthcheck:
test: 'curl localhost:7990/status | grep -q RUNNING'
interval: 1m
start_period: 10m
timeout: 10s
image: 'atlassian/bitbucket:latest'
network_mode: bridge
ports:
- '7990:7990'
- '7999:7999'
restart: unless-stopped
volumes:
- /docker/bitbucket:/var/atlassian/application-data/bitbucket:rw
- /docker/configuration/mysql-connector-java-5.1.48-bin.jar:/var/atlassian/application-data/bitbucket/lib/mysql-connector-java-5.1.48-bin.jar:rw
atlassian-confluence:
container_name: Confluence
environment:
- ATL_DB_DRIVER=com.mysql.jdbc.Driver
- ATL_DB_TYPE=mysql
- ATL_JDBC_PASSWORD={password}
- ATL_JDBC_URL=jdbc:mysql://localhost:3306/confluencedb?useUnicode=true&autoReconnect=true&useSSL=false
- ATL_JDBC_USER=atlassian
- ATL_PROXY_NAME=confluence.yourdomain.com
- ATL_PROXY_PORT=443
- ATL_TOMCAT_PORT=8090
- ATL_TOMCAT_SCHEME=https
- ATL_TOMCAT_SECURE=true
depends_on:
- mysql
healthcheck:
test: 'curl localhost:8090/status | grep -q RUNNING'
interval: 1m
start_period: 10m
timeout: 10s
image: 'atlassian/confluence:latest'
network_mode: bridge
ports:
- '8090:8090'
- '8091:8091'
restart: unless-stopped
volumes:
- /docker/confluence:/var/atlassian/application-data/confluence:rw
- /docker/configuration/mysql-connector-java-8.0.21.jar:/opt/atlassian/confluence/confluence/WEB-INF/lib/mysql-connector-java-8.0.21.jar:rw
- /docker/confluence/logs:/opt/atlassian/confluence/logs:rw
atlassian-jira:
container_name: Jira
environment:
- ATL_DB_DRIVER=com.mysql.jdbc.Driver
- ATL_DB_TYPE=mysql
- ATL_JDBC_PASSWORD={password}
- ATL_JDBC_URL=jdbc:mysql://localhost:3306/jiradb?useUnicode=true&autoReconnect=true&useSSL=false
- ATL_JDBC_USER=atlassian
- ATL_PROXY_NAME=jira.yourdomain.com
- ATL_PROXY_PORT=443
- ATL_TOMCAT_PORT=8080
- ATL_TOMCAT_SCHEME=https
- ATL_TOMCAT_SECURE=true
depends_on:
- mysql
healthcheck:
test: 'curl localhost:8080/status | grep -q RUNNING'
interval: 1m
start_period: 10m
timeout: 10s
image: 'atlassian/jira-software:latest'
network_mode: bridge
ports:
- '8080:8080'
restart: unless-stopped
volumes:
- /docker/jira:/var/atlassian/application-data/jira:rw
- /docker/configuration/mysql-connector-java-8.0.21.jar:/opt/atlassian/jira/lib/mysql-connector-java-8.0.21.jar:rw
- /docker/jira/log:/opt/atlassian/jira/logs:rw
mysql:
container_name: MySQL
environment:
- MYSQL_ROOT_PASSWORD={password}
healthcheck:
test: '/usr/bin/mysql --user=healthcheck --password=healthcheck --execute "SHOW DATABASES;"'
interval: 1m
start_period: 1m
timeout: 10s
image: 'mysql:latest'
network_mode: bridge
ports:
- '3306:3306'
restart: unless-stopped
volumes:
- /docker/mysql:/var/lib/mysql:rw
- /docker/configuration/conf.d/mysql.cnf:/etc/mysql/conf.d/my.cnf:rw
networks:
default:
external:
name: bridge
0 Comments