Header Image

Dockerizing Your Jekyll Site: A Senior Developer's Guide

Introduction

As a senior developer who has seen the evolution of development environments over the years, I can't stress enough the importance of containerization. Today, we're going to tackle a common challenge: setting up a consistent Jekyll development environment using Docker Compose. This approach eliminates the classic "it works on my machine" problem and ensures that anyone working on your Jekyll site can get up and running with minimal friction.

Problem Statement

Managing Ruby versions, gem dependencies, and Jekyll installations across different development machines can be a real headache. Whether you're working in a team or maintaining multiple Jekyll sites, ensuring consistency in your development environment is crucial. Docker Compose offers an elegant solution to this problem by containerizing your Jekyll site and its dependencies.

Solution Overview

We'll create a Docker Compose configuration that:

  • Uses official Ruby Alpine image for a lightweight container
  • Mounts your Jekyll site source code for live development
  • Handles Bundler dependencies efficiently
  • Enables live reload for development

Implementation

Let's start by creating our Docker Compose configuration. Create a new file called docker-compose.yml in your Jekyll project's root directory:

version: '3'
services:
  jekyll:
    image: ruby:3.1-alpine
    command: >
      sh -c "
        apk add --no-cache build-base &&
        bundle install &&
        bundle exec jekyll serve --host 0.0.0.0 --livereload"
    environment:
      - JEKYLL_ENV=development
    ports:
      - "4000:4000"
      - "35729:35729"
    volumes:
      - .:/srv/jekyll
      - ./vendor/bundle:/usr/local/bundle
    working_dir: /srv/jekyll

Configuration Breakdown

Let's examine each component of our Docker Compose configuration:

  • Base Image: We're using ruby:3.1-alpine for its small footprint while still providing everything we need.
  • Command: We install build dependencies, run bundle install, and start Jekyll with live reload enabled.
  • Ports:
    • 4000 - Jekyll's default server port
    • 35729 - Live reload functionality
  • Volumes:
    • Project files mounted to /srv/jekyll
    • Bundler dependencies cached in vendor/bundle

Usage and Best Practices

To start your Jekyll site using Docker Compose, simply run:

docker-compose up

Here are some pro tips for working with your Dockerized Jekyll site:

  • Development Workflow: The live reload feature will automatically refresh your browser when you make changes to your source files.
  • Dependency Management: When you update your Gemfile, Docker will automatically handle the bundle install on the next startup.
  • Cleaning Up: Use docker-compose down to stop and remove containers when you're done.
  • Performance Optimization: The cached bundle volume significantly improves startup times on subsequent runs.

For production builds, you might want to create a separate production configuration:

version: '3'
services:
  jekyll:
    image: ruby:3.1-alpine
    command: >
      sh -c "
        apk add --no-cache build-base &&
        bundle install &&
        JEKYLL_ENV=production bundle exec jekyll build"
    volumes:
      - .:/srv/jekyll
      - ./vendor/bundle:/usr/local/bundle
    working_dir: /srv/jekyll

Troubleshooting Common Issues

Here are some common issues you might encounter and their solutions:

  • Permission Issues: If you encounter permission problems with the bundle volume, you may need to adjust the ownership:
    chown -R 1000:1000 vendor/bundle
  • Live Reload Not Working: Ensure your firewall allows connections on port 35729
  • Slow Performance: On Windows or macOS, you might experience slower performance due to volume mounting. Consider using Docker's delegated volume mounting option:
    volumes:
      - .:/srv/jekyll:delegated

Conclusion

Dockerizing your Jekyll site might seem like overkill at first, but the benefits become apparent as your project grows or when working in a team. With this setup, you can ensure consistent behavior across different development environments, simplify onboarding for new team members, and maintain a clean separation between your development environment and host system.

Remember, the goal of containerization isn't just to follow the latest trend - it's about creating reproducible environments that make development more efficient and reliable. As you continue to work with this setup, you'll likely find ways to customize it further to match your specific needs.

Next Steps

Consider these advanced topics for further improvement:

  • Setting up multi-stage builds for production deployments
  • Implementing CI/CD pipelines with your Docker setup
  • Optimizing build times with layer caching
  • Adding additional services like search functionality
Happy containerizing, and remember: if it works in your container, it'll work in everyone's container!