Iâve been adding development containers to several of my projects with the news that GitHub Codespaces is coming out of beta soon. Codespaces is a browser-based code environment - itâs wicked cool! It works by creating a Docker-based container in the cloud, and then loading VS Code in the browser to write code with. I didnât have a lot of experience with Docker before playing around with Codespaces this week, and was intimidated going into it - but it turned out customizing the development containers wasnât that complicated!
Microsoft has created a lot of stellar presets that you can use to get started with. Iâve used these for several projects, but began creating my own so I could exercise greater control over the environment and use my preferred tools (for instance, using Volta instead of NVM).
Why create a devcontainer?
The VS Code documentation on devcontainers describes the feature as âa local-quality development experience â including full IntelliSense (completions), code navigation, and debugging â regardless of where your tools (or code) are located.â
There are several benefits to using devcontainers instead of developing locally, but chief among them is you have complete control over the environment your project runs in. For Aquarius developers need to have a PostgreSQL database running, have Node.js >14.9 installed, and also run several scripts to configure the projectâs codebase before they can begin coding. There is a lot of room for things to go haywire here. On macOS, getting PostgreSQL to run is a breeze; on WSL2, it is not. Rather than leaving the environment as a potential barrier to entry, I can create a devcontainer and setup PostgreSQL and Node.js for the user in the way Aquarius needs.
Setting up your Computer and VS Code
To make a devcontainer we need to create a docker image and a devcontainer.json
file that tells VS Code how to load it. To begin, you'll need to install the following:
- Docker: I use Docker Desktop on Windows and macOS - you can find the installation instructions here. Docker Desktop for Windows also comes with a bridge for WSL2 - it's fantastic!
- Remote Development Pack: This is the VS Code extension that loads devcontainers. It will enable VS Code to work with WSL2, SSH connections, and Docker containers.
Creating the devcontainer directory
Now letâs start creating our container! To start, make a .devcontainer
directory in the root of your codebase. Weâll be putting all the files below into it.
Creating the Dockerfile
The Dockerfile defines the virtual machine your code runs on. If you're new to Docker (like I am!), there are a bunch of fantastic images you can use as a base to build on top of - it makes this step pretty easy as long as you don't need a bunch of custom components.
To make one, create a .devcontainer/Dockerfile
file that pulls in the image you need. For my Ruby on Rails applications, I'm using this:
.devcontainer/Dockerfiledocker
123456789101112131415161718192021
This is a modified version of the presets Microsoft has published - I've removed parts that weren't necessary for my setup.
If youâre using Node.js, it might start like this instead:
docker
ARG VARIANT=14.9FROM node:${VARIANT}
Adding Databases with Docker Compose
Docker Compose is a great way of adding services to your environment. If your application needs a database for instance, an easy way to add it to your devcontainer is creating a .devcontainer/docker-compose.yml
file that loads it in an image. For PostgreSQL, that looks like this:
.devcontainer/docker-compose.ymlyml
1234567891011121314151617181920212223242526272829303132333435
Piecing it together with a Devcontainer File
Now for the final part! We can piece it all together with a .devcontainer/devcontainer.json
file that creates our Docker image and configures VS Code for us.
First, letâs add the basics on how to start the devcontainer:
.devcontainer/devcontainer.jsonjson
12345678
If you're using Docker Compose, this will be slightly different:
.devcontainer/devcontainer.jsonjson
1234567
Change the
forwardPorts
as needed - I used 3000 since it is the default ports for Rails, Express, and Next.js. If youâre running a Rails or Next.js app in your devcontainer, loadinghttp://localhost:3000
through your local browser will load the code running in the devcontainer!
Next, add some default VS Code settings and extensions to install automatically by adding this to the file:
.devcontainer/devcontainer.jsonjson
12345678910111213141516171819202122232425262728293031323334
When VS Code loads this devcontainer it will automatically install the extensions and use the configured settings - itâs a great way to help new contributors get set up by including defaults like ESLint and Prettier.
Some apps might also have initialization scripts that need to be run after the repository is cloned - for instance, npm install
or bin/setup
are common ones. You can automate that step by adding:
json
"postCreateCommand": "npm install",
Check out the official documentation to learn more about what's possible!
My complete devcontainer.json
for Aquarius:
.devcontainer/devcontainer.jsonjson
123456789101112131415161718192021222324252627282930313233343536373839
Setup Scripts
This step is optional, but I like to run a script that installs shared utilities and finishes configuring the environment as part of my Docker image. For my setup scripts, I start by copying common-debian.sh
from Microsoft's official containers and then modifying it to include tools I want and removing those I donât.
Install your dotfiles!
Finally, let's tell VS Code to automatically clone and install our dotfiles when opening a devcontainer. This step is pretty easy - there are extension settings that let you configure your dotfile repository location and installation script. Mine looks like this:
Conclusion
And there you have it! Now anyone who has VS Code can connect to your devcontainer and automatically get an environment that's set up for them to work with. If you use GitHub Codespaces, you can even code in a browser now!
Devcontainers are really exciting, and big tech uses this style of development for strong reasons. Microsoft has made it easy for smaller projects to get the same benefits, and I can't wait to add devcontainer support to my projects.