My Site Project: Part 2 - Simplifying the Image and Serving the Site with NGINX
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:
- Simplified the sitebuilder image.
- Initiazed and built the site with a series Jekyll commands that were run on top of the sitebuilder container instead of our computer.
- Used an NGINX-based container to serve the static content.
- Wrote a simple services map with docker-compose to serve the contents locally with NGINX
The source code is available here
To be continued…