Setting up a devcontainer to work with Jekyll on Windows
In the previous post we set up the repository to work locally. In this post, I will show how to configure Visual Studio Code to work locally on a Windows machine by leveraging Linux containers running on Docker.
Current setup
My home computer is running the latest stable version of Windows 10, Windows 10 May 2020
also known as Windows 10 2004
.
Jekyll can’t run natively on Windows and their official documentation instructs using WSL to avoid issues.
Instead, I decided to use a Docker container as a full-featured development environment.
This setup gives me the flexibility to use any computer that meets the prerequisites to work locally or even use GitHub Codespaces in the future.
Prerequisites
The solution highlighted in this post has some requirements:
- Windows 10 must be running
Windows 10 2004
or later (earlier versions will be supported) - Windows Sybsystem for Linux must be installed and running version 2. You can follow this guide.
- Docker Desktop 2.3 or later
- Visual Studio Code must be installed on your machine
- The Remote Development extension pack must be installed
- git is correctly configured to access your GitHub repositories
When all the prerequisites are met, open Visual Studio Code in the folder where you checked out your repository.
Initialize the devcontainer
The first step to initialize the devcontainer is to create its configuration files.
By default, a devcontainer needs two files:
- A
devcontainer.json
containing the configuration of the development environment - A
Dockerfile
containing the configuration of the container
Both files are placed in folder called .devcontainer
in the root of the workspace.
The Remote Container extension, installed via the Remote Development extension pack, includes many default configurations that can be then customized.
In Visual Studio Code:
- press F1 to open the palette
- type and select
Remote-Containers: Add Development Container Configuration Files...
- type and select
Show All Definitions...
- type and select
Jekyll (Community)
The extension will then take care of creating the two files.
Visual Studio Code will show a popup asking if you want to reopen the workspace in the remote container. There is not need for it right now.
Before we start customizing the devcontainer setup, you might want to commit the current state.
PS> git add .devcontainers/
PS> git commit -m "Added default devcontainer config"
Here is a guide hosted on Visual Studio Code’s website on how to create a development container.
This page contains information for more advanced scenarios.
Configuring the devcontainer
Before we start using the devcontainer, there are some customizations that can be done.
Once you have done all the customizations you feel necessary, use the Visual Studio Code palette to run the command Remote-Containers: Reopen in Container
.
The process of building the container is quite lengthy the first time because the container images needs to be created, customized and the new container needs to be started.
Customization: Timezone
Jekyll uses an environemnt variable to select the timezone used when displaying timestamps.
By default, the container is setup to use America/Chicago
as current timezone.
This can be customized in the Dockerfile
.
I changed my ENV
directive to look like the following
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
TZ=Europe/Stockholm \
LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8 \
LANGUAGE=en_US
Note that I use the Europe/Stockholm
timezone now.
Here you can find a list of valid options.
Customization: Add GitHub CLI
I am particularly fond of the new GitHub CLI as it makes it working with a GitHub-backed repository extremely easy.
This guide explains how to quickly add it to a devcontainer.
- Add the content of this file in
.devcontainer/library-scripts/github-debian.sh
- Append the lines below at the end of the
Dockerfile
file
COPY library-scripts/github-debian.sh /tmp/library-scripts/
RUN apt-get update && bash /tmp/library-scripts/github-debian.sh
The commands above instruct Docker to download the GitHub CLI and install it when building the container image.
Customization: Markdown linter
Since Jekyll websites are based on Markdown, having a linter for this language can be helpful.
There is an handy extension for Visual Studio Code that enriches the editor with a Markdown linter.
Because it’s an extension that will work inside the devcontainer, we will instruct Visual Studio Code to add this extension to the process running in the container.
We can do this by customizing the devcontainer.json
file.
In the file, find the extensions
section and add this string to the list: davidanson.vscode-markdownlint
.
Here is how my extensions
section looks like
"extensions": [
"davidanson.vscode-markdownlint"
]
With this line in place, the next time we build the container, the extension will be added to Visual Studio Code.
Customization: GitHub token for Jekyll
When building a site to be hosted on GitHub Pages, Jekyll will query GitHub for some information regarding the hosting repository.
If the process is happening locally, Jekyll will complain that no authentication token has been provided with a warning.
GitHub Metadata: No GitHub API authentication could be found. Some fields may be missing or have incorrect data.
To solve this issue, we need to add an environment variable with a valid personal access token.
To begin with, create a new personal access token as explained in this guide and make sure to select the public_repo
permission.
Then, let’s create an environment variable on the local machine.
PS> [Environment]::SetEnvironmentVariable("JEKYLL_GITHUB_TOKEN", "<your-new-access-token>", 'User')
The command above will make sure the environment variable will persist after reboots.
Then, let’s modify the devcontainer.json
so that the local value is copied into the container.
To do so, we can add the following to the containerEnv
section
"containerEnv": {
"JEKYLL_GITHUB_TOKEN": "${localEnv:JEKYLL_GITHUB_TOKEN}"
}
This will tell Visual Studio Code to use the value of the local variable JEKYLL_GITHUB_TOKEN
and copy it into a variable in the container with the same name.
Customization: restore all packages on startup
When working with devcontainers, every time the container starts, it’s in a pristine state.
In the case of a Ruby application like Jekyll, it means that some dependencies specified in the Gemfile
might not be available in the container forcing the developer to run a bundle install
command after every restart.
Once again, we can leverage the devcontainer.json
to specify a list of commands to be executed after the container is created and the source code is mounted.
For this, it’s sufficient to leverage the postCreateCommand
section of the file.
"postCreateCommand": [
"bundle install"
]
Note that this will make starting up a fresh container slower. On the other hand, you will need to execute the command most of the times anyway.
Optional: Sharing git credentials to the container
When working inside a container, it might be use convenient let the container use the same git credentials installed on the local machine.
The Remote-Containers
extension has some built-in facilities to make it very smooth the transition into the container. For example, the extension will take care of copying the .gitconfig
file in your home directory in the home directory of the container user.
The next step is to configure the SSH agent of the local machine. The Remote-Containers
extension will take care of forwarding SSH request from inside the container to the agent running on the local machine.
In an elevated PowerShell console execute the following commands
# Make sure you're running as an Administrator
PS> Set-Service ssh-agent -StartupType Automatic
PS> Start-Service ssh-agent
PS> Get-Service ssh-agent
This will start the ssh-agent
service and will make sure it starts automatically on reboot.
Then add the public key to the SSH agent.
PS> cd ~
PS> ssh-add.exe .\.ssh\id_rsa
Once you have added the SSH key to your agent, the container should be able to access and push to your repositories without the need of authenticating at each container reboot.
Recap
In this post we have seen how to configure Visual Studio Code’s extension Remote-Containers to leverage a Docker container and make it easier to work with Jekyll sites on a Windows machine.
In the next post, we will finally see how to create a website with Jekyll, how to install a custom theme and how to customize it.
Support this blog
If you liked this article, consider supporting this blog by buying me a pizza!