In this post, I’ll propose some simplifactions to the Docker image created in the 1st part of the series. As uncle Bob says, we should leave the place cleaner than in your last visit.

Sometimes it invloves revisiting your own work.

Hopefully, the simplifications described below will help us streamline the process of building our site.

Prerequisites

  • Basic knowledge of NGINX
  • Docker

Initialize and Build the Site

The Improvements

This is our new Dockerfile:

FROM ruby:2.5.0-alpine3.7
RUN apk update && apk update
RUN apk add g++ gcc make musl-dev
RUN gem install jekyll bundler
WORKDIR /site

Compared to the version of the Dockerfile from the previous post, this one is shorter. Hence, it’s more readable and would be easier to maintain.

Initalizing the Site

Here we’ll follow Jekyll’s official documentation with only one difference - we’ll run all the commands on top of a container.

Create a Dockerfile and copy the instructions above into it. Then, run the commands specified below:

# Build the image
docker build -t site/initializer .
# Initialize the site. This will create a new 'blog' directory
docker run --name siteInit --rm -v $PWD:/site site/initializer jekyll new blog
# After the site's contents have been initialized, switch to its directory
cd blog

Improving on the Improvements

If you already have customized the site’s configurations and theme, you can perform the following change for the Dockerfile to build a new sitebuilder image. Below is the new version of the Dockerfile

FROM ruby:2.5.0-alpine3.7
RUN apk update && apk update
RUN apk add g++ gcc make musl-dev
RUN gem install jekyll bundler
WORKDIR /site
COPY Gemfile ./
RUN bundle install

The RUN bundle install statement will install all the dependencies provided in Gemfile that had been coped in the previous step.

By doing so, we ensure we have all our dependencies to run & build the site preinstalled.

Build a new version of the sitebuilder image:

docker build -t sitebuilder .

Now we can build the site and run it by typing the following commands:

docker run --name siteBuilder -v $PWD:/site -p 4000:4000 sitebuilder jekyll serve --host=0.0.0.0

Remember that Docker images are based on layers, where each instruction is a layer that’s being cached by Docker in order to be reused in subsequent image builds. The same layer can be reused in different and unrelated images.

Serving the Static Content with NGINX

NGINX is a lightweight application that can serve static content really well. Its functionality isn’t limited to only being a server for static files. It’s a highly versatile server that can perform various tasks, such as being a reverse proxy, load balancer, and etc. More info is available here.

In our case, I chose NGINX so it can serve the static files really fast without heavily impacting our computer (as it’s really fast and lightweight).

Here’s how we’ll do it.

The Configurations file

Let’s create a very simple nginx.conf file for the NGINX server:

events {}
http {
    include mime.types;
    server {
        listen 80 default_server;
        root /usr/share/nginx/html;
    }
}

In order to be valid, an NGINX configuration file should include the events directive. Wel’ll leave it empty to keep the things simple.

As for the http directive, we included the include mime.types directive, so NGINX adds a proper Content-Type header. Without the proper Content-Type header, the browser installed on our computer would not be able to parse the files’ contents served by the server properly.

As for the listen directive under the server context, the NGINX server will listen to all the incoming connections at the standard port 80.

As for the root directive, our local NGINX server will serve the files from that directory. We’ll mount the contents of the _site directory into this directory. NGINX will do the rest of the job for us.

Don’t Forget to Update Jekyll’s Config

Add the following item under the exlcude property in the Jekyll config file:

- nginx.conf

This will prevent Jekyll from including the NGINX configuration file under your site’s static contents.

Running the Server

Make sure you’re under your blog’s directory and the _site directory under it was created by Jekyll.

Now issue the following command:

docker run --name site -v $PWD/_site:/usr/share/nginx/html -v ./nginx.conf:/etc/nginx/nginx.conf:ro -p 80:80 nginx:1.21.4-alpine

Keep all the Things docker-compose

It’s cumbersome to type or search for the last command. Hence, we’ll write a docker-compose file with all the parameters ready. Let’s lay out a simple docker-compose.yml file:

version: "3"

services:
    site:
        image: nginx:1.21.4-alpine
        volumes:
          - $PWD/_site:/usr/share/nginx/html
          - ./nginx.conf:/etc/nginx/nginx.conf:ro
        ports:
          - 80:80
        container_name: site

By running the docker-compose up command we can bring our site up.

To test your site, go to http://localhost.

In order to shut it down, run the docker-compose down command.

Don’t forget to exclude this file either in the _config.yml file.

What We’ve Learnt So Far

To sum it up, we:

  1. Simplified the sitebuilder image.
  2. Initiazed and built the site with a series Jekyll commands that were run on top of the sitebuilder container instead of our computer.
  3. Used an NGINX-based container to serve the static content.
  4. Wrote a simple services map with docker-compose to serve the contents locally with NGINX

The source code is available here

To be continued…