preloader

How to Containerize Your Docusaurus (And Why You Should)

Learn how to get your Docusaurus docs containerized for local development with Docker Compose, and why this simple task can make life easier for your whole team.

/images/blog/cover-images/docker-docusaurus.png
Write a Docker Compose file for your Docusaurus docs

by on

Containerizing your project’s documentation might be one of the easiest ways you can remove friction from iterating. Your docs are also probably one of the easiest things you can containerize. Here’s how you can get your docs up and running with Docker Compose in just a few minutes.

Why should I containerize my docs?

Simply put, containerizing your docs lets you hit the ground running when writing documentation.

Here are a few QoL improvements that come with doing this:

  • No need to install/update/manage dependencies
  • Work with the same development environment across machines
  • Start developing with just a single command

In short, it’s just easier. You don’t have to think about building and running the dev server, you can just open your terminal and your IDE, then start writing. When writing docs, you’re likely iterating often and adding small chunks at a time, so it makes sense to optimize your local dev environment to spin up as efficiently as possible.

Containerizing your Docusaurus build

At Shipyard, we’re big fans of Docusaurus. We’ve been using it to write our public documentation for three years. We’ve also been using Docker Compose for local docs development just as long. A lesson we’ve learned is that sometimes the best tools are the ones we’re already using. We were using Docker Compose for everything else, why not extend it to our docs?

Writing the Dockerfile

Since Docusaurus is Node-based, the Dockerfile is pretty standard. You might need to swap in your docs’ custom run commands.

FROM node:16-alpine

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

CMD ["npm", "start"]

This Dockerfile Explained

If you’re newer to Docker, here’s a line-by-line rundown of what this Dockerfile is doing:

  1. Start with a Node base image
  2. Create and set the working directory within the container
  3. Copy the Node dependencies to the working directory
  4. Install dependencies within container
  5. Copy the rest of the repo’s contents to the working directory
  6. Run the Node project’s start command

Setting the host

In order to make the application accessible from outside the container (e.g. from your web browser), you’ll want to set the --host option to 0.0.0.0.

This can be done from your package.json:

 "scripts": {
	"docusaurus": "docusaurus",
	"start": "docusaurus start --host 0.0.0.0",

Or in your Dockerfile as an argument to your project’s start command:

CMD ["npm", "start", “--host”, 0.0.0.0]

Writing the Docker Compose file

Now that we have the Dockerfile, we can write a single-service Compose file to leverage it. Here, we’ll specify any Docker config options (so we don’t need to remember them for complex docker build and docker run commands).

version: '3'

services:
  docusaurus:
    build:
      context: .
    ports:
      - '3000:3000'
    volumes:
      - './docs:/app/docs'
      - './src:/app/src'
      - './static:/app/static'
      - './docusaurus.config.js:/app/docusaurus.config.js'
      - './sidebars.js:/app/sidebars.js'

Because we’re optimizing this Compose file for local development, we’ll want to define bind mounts from any files and directories that we plan to edit. This way, any local changes will be reflected in the Docker container.

In this example, I have a few bind mounts defined under the volumes option. The syntax for this involves specifying the local path (relative to the build context), followed by a colon, then followed by the corresponding location in the container.

Bonus: Writing the .dockerignore

Docker images tend to run pretty large, so writing a .dockerignore can help slim them down by weeding out any files irrelevant to your Docker build.

To exclude any Markdown files in the root directory (e.g. your README.md and LICENSE.md, but not your actual Markdown doc pages), you can use this glob pattern in the .dockerignore:

/*.md

Your Docker build also doesn’t need to include the Dockerfile or the Compose file. These glob patterns will match most naming conventions for those:

*compose*
*Dockerfile*

You can also exclude node_modules (likely the biggest bloat culprit):

node_modules

Docs that work right out of the box

Now that you’ve containerized your Docusaurus docs, you can spin them up locally with docker compose up and start editing.

Thanks for reading!

If you enjoyed this Docker Compose tutorial, check out this post I made a few months ago on how to write a Compose file for a Wordle clone.

Try Shipyard today

Get isolated, full-stack ephemeral environments on every PR.

What is Shipyard?

Shipyard is the Ephemeral Environment Self-Service Platform.

Automated review environments on every pull request for Developers, Product, and QA teams.

Stay connected

Latest Articles