GitHub Codespaces is an incredible offering that lets you run Visual Studio Code within a Docker container in the cloud, from your browser. What makes this offering a real game changer is when you couple that with all the dependencies needed to get a development environment configured correctly. Imagine how much time this would save developers working on larger complicated projects. I know I’ve definitely worked on projects where I spent hours finding all the random dependencies and compiler settings needed just to get the project to build. For some of my projects, I made an effort to set up some files for Codespace to use that would get other developers set up in less than a minute.
DEV Container JSON
First you have to create the JSON file for the container. This can live in two places, either .devcontainer/devcontainer.json
or .devcontainer.json
. When a Codespace is created for a repo, it will automatically check in these locations for the information on the container it needs to build and how to build it. Below is an example of a file for a container that has Rust installed.
{
"image": "mcr.microsoft.com/devcontainers/universal:2",
"features": {
"ghcr.io/devcontainers/features/rust:1": {}
}
}
When it comes to configuration of these containers, the sky is really the limit. The JSON reference for these can be found at https://containers.dev/implementors/json_reference/. There’s all kinds of things we can do, for instance if we want to have some VS Code plugins installed as well, we can update our file accordingly:
{
"image": "mcr.microsoft.com/devcontainers/universal:2",
"features": {
"ghcr.io/devcontainers/features/rust:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"redhat.vscode-yaml"
]
}
}
}
Now let’s say we have some more dependencies we want to install that we can script out; this is after all a Linux environment. We can write them in a bash file and then have the container build process run that script. I generally place this file in the .devcontainer/
folder as init.sh
so all of the Codespace files are together. Here’s an example of a script that might set up some dependencies:
rustup override set nightly
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
rustup component add llvm-tools-preview
cargo build --manifest-path=/workspaces/Repo/projects/project/Cargo.toml
Then we can tell our container to run that file after it has pulled in the repo and done most of the creation process using the onCreateCommand
property:
{
"image": "mcr.microsoft.com/devcontainers/universal:2",
"features": {
"ghcr.io/devcontainers/features/rust:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"redhat.vscode-yaml"
]
}
},
"onCreateCommand": "sh /workspaces/Repo/.devcontainer/init.sh"
}
From there you should be able to set up a pretty good dev environment. Although I want to reiterate, you can do build pretty much anything you with these containers. Some more good resources I found were https://code.visualstudio.com/docs/devcontainers/create-dev-container and https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/setting-up-your-repository/setting-up-a-template-repository-for-github-codespaces.
Trial And Error Within Codespaces
A helpful bit to end on that I found was how easy Codespace makes it to test updates to configs. If you open a Codespace for a repo, and then create the specified files, Codespace will probably provide a prompt suggesting you rebuild the container since there were changes to its configuration. This prompt will go away after a bit, but you can always rebuild the container whenever you want by opening the Codespace management pane in the bottom left of the screen and clicking “Rebuild”. This will go off the changes you have locally in your existing Codespace, which is super helpful for trial and error of the configuration before you commit it to the repo.