Deploying Docker Containers On A Raspberry Pi Device

Recently I’ve been using a good amount of Docker for various deployment pipelines.  As everyone knows, I’m a huge Raspberry Pi fan, so I figured it would be a cool idea to bring the two together.  After all, Docker was built using Golang which is cross architecture.

We’re going to see how to create Docker containers on a Raspberry Pi and figure out the limitations of using Docker on IoT based architectures.

Before getting too invested, it is important to note that not all Docker images will work on a Raspberry Pi.  This is because most images were designed for PC architectures, not ARM.  However, Docker Hub, has quite a few that are available and that number is growing every day.  We’re going to limit our use of the pre-built images in this guide and build our own.

The goal here will be to create a Docker container that uses Node.js and runs a Ghost blogging application.

The Requirements

There are a few requirements that must be met in order to be successful in this guide.

  • Raspberry Pi 3
  • Debian Linux, Jessie or higher

I imagine Docker will work on multiple versions of the Raspberry Pi, but for convenience we’re going to use the latest which is the third generation.  The flavor of Linux that you use shouldn’t matter, but we’re going to be using Debian.  The assumption is that Debian is installed and configured on the Raspberry Pi.  For instructions towards doing this, check out a previous article I wrote on the subject.

Installing and Configuring Docker

Before we begin to create containers on our Raspberry Pi, Docker needs to be installed and configured.  From here on out, either SSH into your Raspberry Pi, or execute the following from a Terminal window on the Raspberry Pi.

From the Terminal, execute the following:

After Docker installs it is probably a good idea to tell Docker to start automatically whenever the Raspberry Pi is powered on.  This can be done by executing the following:

Reboot your Raspberry Pi, and when it starts back up, you are now able to create containers on your device.

Creating a Container Image for the Ghost Blogging Platform

There are many ways to do this, and in all honesty the way you see now probably isn’t the easiest.  The reason I’ve chosen to explain it this way is because of the limited pre-built images.

On the Raspberry Pi, create a directory called ghost.  It doesn’t really matter where you create it, but this directory will be where the Docker configurations reside for the particular container that we want to create.  The ghost directory should contain the following files:

  • Dockerfile
  • configure-ghost.sh

The Dockerfile file has the image we plan to use and any setup that will happen.  The configure-ghost.sh file is a script that the Dockerfile will execute to install things like Node.js and Ghost.

Open the Dockerfile file and include the following lines:

The first line says we are going to use the armhf/debian image found on Docker Hub.  In this image we’re going to copy the configure-ghost.sh script to the containers /opt directory.  The script likely won’t have the correct permissions so we’re going to make sure it has execute permissions with the chmod command.

Finally, when we run our container it will run all the commands found in the configure-ghost.sh script.

So what does this configuration script look like?

Open the configure-ghost.sh file and include the following lines of Bash code:

There is a lot going on in the above script.  This is because the armhf/debian image we chose to use is pretty basic.  It won’t have anything we need for running Ghost.

The first thing we’re doing is updating all the package repositories in the container.  The Node.js and Ghost we want isn’t in the standard apt-get repositories so we’ll have to install them manually.  This requires packages like cURL, unzip, and build-essential.

With the appropriate Debian packages in place we can install Node.js:

Ghost is just a Node.js application so what we want to do is download the latest ZIP archive, extract it, configure it, and run it.  When looking at our script, probably the most important line is the following:

We want to be able to access Ghost from our host machine.  By default, Ghost will run on 127.0.0.1, but localhost to the container is not localhost to the Raspberry Pi.  Instead we replace all occurances of 127.0.0.1 with 0.0.0.0 in the Ghost configuration example file.  This file eventually is renamed during the setup process.

Finally, Ghost is run in production mode.

Building the Container Image and Running the Image

Up until now we haven’t actually created the Docker container image.  We put down the foundation which will be used next.

Execute the following to build the image based on the Dockerfile file and the configure-ghost.sh file:

In the above command we’re naming the the image ghost.  It will download the armhf/debian image and the other commands found in the Dockerfile file.

You can verify that the ghost image was added by executing the following:

To start the container based on our new image, execute the following:

The above command says to run the container in detached background mode with a port mapping of 2368.  We are mapping this port because this is the port that Ghost operates on.  If you have a domain name configured, you’ll probably want to open port 80 as well.  The container will use the ghost image and the container will have a name of ghost.

After you run the above command, it is very important to note that it is not instant.  The Raspberry Pi is not the fastest machine and there are a lot of commands in the configure-ghost.sh script.  To track the status of your container, execute the following:

When the script finishes, navigate to http://localhost:2368 from your Raspberry Pi web browser.  If you’re in headless mode, first find the IP address of your Raspberry Pi and navigate to http://IP:2368 from some other device on your network.

Conclusion

You just saw how to install Docker on a Raspberry Pi and add a container running the Ghost blogging platform.  Like I said, the method we used to install Node.js and Ghost was not the easiest option we could have taken.  For example, there is an armhf/node image we could have tried.  However, we wanted to see creating our own via script.

Have your own variation of what was done in this guide, share it in the comments.  It will give readers options towards getting the job done.

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in Java, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Apache Cordova. Nic writes about his development experiences related to making web and mobile development easier to understand.

  • Rob Little

    So I’ve been trying this for the last day or so, and I am not having luck duplicating it – particularly when doing the Build, I am getting an error when it attempts to perform the chmod on the configure-ghost.sh script (“The command ‘/bin/sh -c chmod 755 /opt/configure-ghost.sh’ returned a non-zero code: 139”. Any thoughts on what I might be overlooking?

    • That response is new to me. What if you do ‘chmod +x’ instead of ‘chmod 775’? As a last resort, you can make the script executable on the host and it will be copied as such into the image. Then you can just remove the ‘chmod’ part.

      • Rob Little

        Those changes didn’t fix things either. I’m wondering if there is something off with the current armhf/debian images. I tried to open it in a shell session (using docker run -t -i armhf/debian /bin/sh) and it wouldn’t successfully launch, which signals to me that the image might be the problem.