Deploy Ghost and MySQL using Docker Compose

Lorenz Vanthillo
6 min readMar 20, 2018

Ghost is an open source publishing platform which is beautifully designed, easy to use, and free for everyone. We will deploy a Ghost and a MySQL Docker container by using Docker Compose. Docker Compose makes it possible to deploy a whole Docker stack by just executing one command.

-

Create the persistent MySQL container

We need to create a persistent MySQL container before we will start our Ghost. We will create a docker-compose.yaml which will be extended during this post. To make the data persistent we will use a named Docker volume called mysql-volume. The data from /var/lib/mysql (path inside our MySQL container) will be mounted in the volume.
We use the official MySQL Docker image which offers us the possibility to use environment variables.

content of docker-compose.yaml:

We can deploy the MySQL container:

$ docker-compose -p "ghost-platform" up -d
Creating network "ghostplatform_default" with the default driver
Creating volume "ghostplatform_mysql-volume" with default driver
Creating mysql ... done

We can verify already if our credentials work and if the database db is created.

$ docker exec -it mysql bash
root@792728b8eaf7:/# mysql -u blog-user -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.20 MySQL Community Server (GPL)
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db |
+--------------------+
2 rows in set (0.00 sec)

This works. We can bring the environment down using docker-compose -p "ghost-platform" down and start extending our docker-compose.yaml.

Create the Ghost Docker image

Let’s first create our Ghost image. There is an existing Ghost Docker image but this image will create a database inside the same container as where ghost is running. This means you’ll have one container for multiple services. This is against the rules of Docker.
That’s why we will extend the official image of Ghost.
We will install:

  • MySQL client: Ghost will use this client to connect with the MySQL container.
  • wait-for-it.sh: Ghost will use this script to check if the MySQL service inside the MySQL container is already running, before it will connect.

We will start with the wait-for-it.sh script. When you start a MySQL container this does not mean that the MySQL service inside the container is started immediately. This script will check when the MySQL service is up and running before trying to make the connection from Ghost. If we don't use this script we will risk a 'crash' of our Ghost container because it can not find the MySQL service.

The content of wait-for-it.sh (be careful with just copying from here):

This script will try to connect to the MySQL service. If it fails it will sleep 1 second and try again, till the MySQL service is up and running and ghost can connect. Our mysql-client is used here.
Don't forget to make your script executable using chmod +x.

Our Dockerfile for the ghost image is derived form the official Ghost image:

FROM ghost:1.20.0
RUN apt-get update -y && \
apt-get install -y mysql-client
COPY ./wait-for-it.sh /usr/local/bin/wait-for-it.sh

After installing the mysql-client we will copy our wait-for-it.sh script inside our container.
This is the current tree of our project. We will store the Dockerfile and our script in a folder called ghost:

├── docker-compose.yaml
└── ghost
├── Dockerfile
└── wait-for-it.sh

Extend docker-compose.yaml

In the last step we need to add the Ghost configuration to our docker-compose.yaml.
We will tell compose to build an image called lvthillo/ghost:1.20.0 from the content inside the ghost folder.
We will host our blog on port 80 of our host. Again we can use environment variables. This time they are used to make the connection to our MySQL database. Our 2 containers will be deployed by default inside the same Docker network which means we can connect by using the service name mysql. Be sure you specify the same credentials as you did for your MySQL container.

We will also persist Ghost specific data like the Ghost template which you are using. Data about users and posts are kept in MySQL and persisted there.

The entrypoint will execute the wait-for-it.sh script. When the connection can be established, it will execute the command to start the Ghost service.

We can create our environment again:

$ docker-compose -p "ghost-platform" up -d$ docker ps
CONTAINER ID IMAGE COMMAND PORTS NAMES
cfef948cf7ef lvthillo/ghost:1.20.0 "wait-for-it.sh mysq…" 0.0.0.0:80->2368/tcp ghost
9dafdd9f1f98 mysql:5.7 "docker-entrypoint.s…" 3306/tcp mysql

Check the logs of your ghost container. It executes the wait-for-it.sh script. It tries to connect, sleeps and tries again, till it works. Then it will start creating the right tables and models.

$ docker logs ghost
MySQL is unavailable - sleeping
ERROR 2003 (HY000): Can't connect to MySQL server on 'mysql' (111)
MySQL is unavailable - sleeping
ERROR 2003 (HY000): Can't connect to MySQL server on 'mysql' (111)
MySQL is unavailable - sleeping
MySQL is up - executing command
[2018-01-27 12:28:02] INFO Creating table: posts
[2018-01-27 12:28:02] INFO Creating table: users
[2018-01-27 12:28:02] INFO Creating table: roles
[2018-01-27 12:28:02] INFO Creating table: roles_users
[2018-01-27 12:28:02] INFO Creating table: permissions
[2018-01-27 12:28:02] INFO Creating table: permissions_users

Test your environment

Open your browser and connect to your host on port 80. You will access your ghost platform. I’ve deployed it on my localhost.

Default Ghost layout

You can configure your ghost by visiting http://localhost/ghost and create your user, your blog and posts!

Create account (skip invite team)

Create your first post and publish it.

And there it is. Your first blog:

At last we can check again if our data is stored inside the MySQL container.

mysql> use db;
Database changed
mysql> select name, email from users;
+----------+--------------------------+
| name | email |
+----------+--------------------------+
| lvthillo | lvthillo@mail.com |
| Ghost | ghost-author@example.com |
+----------+--------------------------+
2 rows in set (0.00 sec)
mysql> select title from posts;
+-----------------------------------+
| title |
+-----------------------------------+
| Super vacation |
+-----------------------------------+
8 rows in set (0.00 sec)

Conclusion

We have created a Ghost publishing platform inside docker. Its data is stored in a persistent MySQL database. Bring your environment down, and up again. Your blog, posts and users will still exist! Hope you enjoyed it and you’re ready to create blogs.. in Docker! You can also find everything on my GitHub.
Hope you enjoyed it!

If it really helped you… :)

--

--

Lorenz Vanthillo

AWS Community Builder | DevOps | Docker Certified Associate | 5x AWS Certified | CKA Certified | https://lvthillo.com