Containerizing Gatsby

paint swatches

I want to start very clearly. The following is not a post on how to get started with Docker and Gatsby. It is to document the path I took to containerize this blog.

Given what I learned in the previous post, I started with a .dockerignore file that looked something like this:

.cache
.dockerignore
.git
.gitlab-ci.yml
node_modules/
public
dockerfile

Knowing that I would not be attempting to use the node_modules from my Windows machine in a Linux container before starting the Dockerfile eased my mind. Next was to create the Dockerfile. First, I wanted to start with the correct Node container. Locally I am using Node v14, and it made sense to choose node:14-alpine as the base content to build off. Next, define the working directory and copy the package.json file into the working directory. Some file copying and executing the gatsby build command resulted in the following Dockerfile;

FROM node:14-apline
WORKDIR /opt/
COPY ./package.json .
RUN npm i
COPY ./ .
RUN npm run build

Lastly, the container needs a port to expose and a command to start the server. We can achieve this by appending EXPOSE 9000 and CMD ["npm", "run", "serve" ] to the end of the above file.

It was time to build the container by issuing the command docker build -t blog:test .. Then run the container with the command docker run -d -p 2233:9000 blog:test.

At first glance, the logs appeared as expected. What came out on the other end was different from what I wanted. This approach did not yield a working site at port 2233. Digging into the command npm run serve, this was not the correct command for production hosting anyways. In the long term, this approach would not be satisfactory. So, it was time to approach the problem differently.

I learned some time ago that a single Dockerfile could contain multiple steps and base container references, each with its role. I also know that there is a web server Nginx I could use to host the site. Moving the output of the Gatsby build to be hosted by the Nginx webserver is a viable option. With some adjustments to the Dockerfile and the addition of the Nginx container. Out came this:

FROM node:14-alpine as build
WORKDIR /opt/
COPY ./package.json .
RUN npm i
COPY ./ .
RUN npm run build

FROM nginx:latest as host
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY --from=build ./opt/public .
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

The first portion of the definition is to build static assets of the blog. We then clean the host directory, adding the static site to the newly cleaned location from the building container. Finally, expose port 80 outside the host container and issue the command to start the web server.

Issue the same command to build the container as before docker build -t blog:test ..Lastly, start the container with docker run -d -p 2233:80 blog:test. Viola! A containerized Gatsby blog.