Jekyll in a container
Related recipe - Jekyll in the Container section.
This flow runs a Docker container. If you don’t want to use Docker, see Jekyll Ruby Action, which is a light approach.
It runs Jekyll inside a container that is run as a binary (using docker
CLI but no Dockerfile
needed). So it can be used as a drop-in replacement for running jekyll
directly.
Plus, the container takes care of Ruby and Jekyll dependencies and installing project gems. This builder
image even includes Node.js.
Based on jekyll.yml - a starter workflow provided by GitHub.
main.yml
name: GH Pages deploy on: push: branches: main paths-ignore: - README.md pull_request: branches: main paths-ignore: - README.md jobs: build-deploy: name: Build and deploy runs-on: ubuntu-latest steps: - name: Checkout 🛎️ uses: actions/checkout@v2 - name: Build Jekyll site run: | docker run \ -v ${{ github.workspace }}:/srv/jekyll \ jekyll/builder:4.2.0 \ /bin/bash -c 'chmod 777 /srv/jekyll && bundle exec jekyll build --future' - name: Deploy to GH Pages 🚀 if: ${{ github.event_name != 'pull_request' }} uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: _site
You can use jekyll COMMAND
or bundle exec jekyll COMMAND
. The latter is probably safer, using the project Jekyll instead of the global Jekyll (at least global inside the container).
Make sure that the image tag Jekyll version matches the Jekyll version in Gemfile
. Though, you could even leave Jekyll out of Gemfile
, but I wouldn’t recommend it, so you can still run it outside a container.
See jekyll/builder tags available.
If you want to use say Jekyll 4.3
in your Gemfile and the Docker image tag is not available, you could use bundle exec jekyll build
as the command passed to the container. To ensure the project Jekyll gets used, instead of the container’s global Jekyll.
About the approach
This builds the site using a Docker container step. This means you don’t need to use any Action from the marketplace to set up your Ruby and Jekyll environment. The container image is ready to go. When you run it, it will even install your gems for you using Bundler.
I think this is great - I don’t know why there are so many Jekyll actions out there. Maybe if you really need control over the environment or build steps. Some actions include Jekyll and GH Pages in one - I don’t think it is a good idea to mix those together in one inseparable step.
Another advantage is that you can run the exact same container locally - which is great for debugging and for running your application locally on any OS without requiring Ruby, Bundler and gems installed.
An advantage of using Docker here is that you can run the same command locally - no Ruby or Jekyll needed. You can move the full docker command to a Makefile
too to make it easier to run as make build
.
Caching note
A disadvantage of using Docker here is that the image is not cached and so must be downloaded each time. I found an action which supports caching of Docker images, but adds extra steps and complexity. Maybe the plain cache action can work for Docker cache directory?
Also, the gems have to be downloaded and installed each time, which be avoided by adding the cache action, even if it doesn’t cache the image.
Notes on the workflow
- Using the Docker step alone output would get thrown away after the build. If you want to persist as a GH Pages site, just add on the last section as below, using a generic GH Pages action.
- You can pick a tag like
4
to get a recent version in4.x
range. I’d avoidlatest
as one day you’ll suddenly get5
. GH Pages normally limits you to3.9
. - The
--future
flag is to publish future-dated posts.
Original workflow
The workflow is based on the one generated by the GitHub when it suggests a Jekyll workflow for your project.
My changes
- Use Jekyll version
4
instead oflatest
, to avoid upgrading to 5 by accident. Also, you can use4.2
etc. if such as tag exists. - Add GH Pages at the end to persist on
gh-pages
branch. I’ve also set up this deploy step only runs on the main branch, not feature branches. - Remove a volume.
I tried to use $PWD
instead of ${{ github.workspace }}
I but got a permissions error. Just make sure to use $PWD
for local use. i.e. -v "$PWD:/srv/jekyll"
See related notes below.
Permissions note
Note use of chmod 777
for the directory (not for the files in it).
If this is not included, then the container logs that it is installing gems which fails because of no permissions to write to Gemfile.lock
.
There was an error while trying to write to `/srv/jekyll/Gemfile.lock`. It is
I don’t know how this works though. The entry-point command given to the container is only meant to run after the docker has set up gems internally.
Volume note
Note that GitHub’s own starter workflow mounts two volumes, when only one is needed.
Here it is anyway with _site
as a volume.
-v ${{ github.workspace }}:/srv/jekyll \
-v ${{ github.workspace }}/_site:/srv/jekyll/_site \
The second is unnecessary as it is already covered by the first as a nested directory with the identical name in and outside the container.