Why are people developing inside containers?

Developer Advocate @ GitHub
Search for a command to run...

Developer Advocate @ GitHub
Thank you Rizel Scarlett! I was not aware of the GithHub Codespaces. i really appreciate your effort.
In this series, I will document technical tutorials for navigating GitHub's awesome features!
Use Codespaces to teach HTML, CSS, and JavaScript to beginner developers
Raise your hand if you've been personally victimized by the question: 'Will AI replace software engineers?' It's a common debate that drives developers to extremes—either avoiding AI entirely or frantically signing up for every AI course available. ...
I recently went down several rabbit holes about building WYSIWYG editors and popovers. While on maternity leave, I finally have time to deeply explore random technical problems without deadlines - a rare opportunity. Thus far, I've focused on contrib...
This blog post uses storytelling to introduce beginners to Verifiable Credentials, followed by a tutorial on creating them in JavaScript and Kotlin. In Our Last Issue... In our previous issue, we met Dawson Webhart, a junior frontend software enginee...

"Our current credit system says, 'Saddle yourself, so we can give you more to saddle.'" Eric Lapin, President of FormFree, stated during a recent TBD live stream. His comment sheds light on a fundamental paradox of the U.S. credit system: it often re...

Technology adoption doesn't happen with one software engineer coding in solitude. Even though big companies like Meta and Microsoft boast of their humble beginnings in a dorm room or a garage, product adoption requires good marketing. Many software e...

Black Girl Bytes
58 posts
I'm a Developer Advocate at GitHub. I'm passionate about community, code, and education! Reach out to me on Twitter ❤️
Nine years ago, in March 2013, Solomon Hykes and his cofounders revolutionized how we do software development with an open source platform called Docker. Although the creators of Docker didn't invent containers, they popularized them. Thanks to Docker, engineers can create tools, like GitHub Codespaces, that enable us to code in a development container hosted in the cloud.
I’ll admit that when I first heard about development containers, I had two questions:
If you have similar questions, this post is for you.
In this blog post, I'll explain what containers are, how they benefit engineers, and how to setup devcontainers in GitHub Codespaces.
Raise your hand if you’ve ever uttered the words, "It works on my machine." (Don’t worry; you're not alone)!

If you're not familiar with this phrase, it's a meme, but it's also a real phrase developers find themselves saying if they work in a codebase where the environments vary. Although working in varying environments is not ideal, it does happen. From my experience, situations like this occur when my local environment, my coworkers' local environments, staging, and production all have slight differences. Because the environments had slightly different configurations, bugs existed in one environment but didn’t exist in the other environment. It can feel so embarrassing and frustrating to build a feature or fix a bug that works locally but doesn't work in production or staging.
However, containers solve the issue of inconsistent developer environments. Containers enable software engineers to program in a consistent environment. Now, your coding environment can mirror production by using the same operating system, configurations, and dependencies. This ensures bugs and features behave the same across all environments relieving developers from the embarrassment of saying, "It works on my machine."
Now that we understand the purpose of containers, let’s explore how Codespaces leverages containers.
GitHub Codespaces allows you to code in a container hosted in the cloud. In this context, the cloud is an environment that doesn't reside on your computer but rather on the internet.
Typically, software engineers are responsible for setting up their local environment when they join a team. Local environment setup includes installing the required dependencies, linters, environment variables, and more. Developers may spend up to a week configuring their environment, depending on the quality of the documentation. When I was purely a software engineer, it took me about 2 days to set up my environment, and the experience was painful because I wanted to start coding immediately. Instead, I had to seed my database and edit my .zshrc file.
Fortunately, organizations can automate the onboarding process using GitHub Codespaces to configure a custom environment. When a new engineer joins the team, they can open a codespace and skip the local environment setup because the required extensions, dependencies, and environment variables exist within the codespace.
With Codespaces, I can code anywhere that I have internet access. If I switch devices or forget my laptop at home, I can easily resume my work on an iPad while I’m on the plane without cloning a repository, downloading my preferred IDE, and setting up a local environment. This is possible because Codespaces opens a Visual Studio Code-like editor inside the browser. The best part is Codespaces can autosave my code even if I forget to push my changes to my repository.
As mentioned in the paragraphs above, containers allow you to work in a mirrored production environment. Because GitHub Codespaces uses containers, you can get the same results and developer experience in your local environment as you would in your production environment.
Additionally, sometimes when changes happen to the codebase, such as infrastructure enhancements, local environments can break. When local environments break, it’s up to the developer to restore their developer environment. However, GitHub Codespaces use of containers brings uniformity to developer environments and reduces the chances of working in a broken environment.
You can leverage three files to make the Codespaces experience works for you and your teammates: the devcontainer.json file, the Dockerfile, and the docker-compose.yml file. Each of these files lives in the .devcontainer directory at the root of your repository.
The devcontainer.json file is a configuration file that tells GitHub Codespaces how to configure a codespace. Inside a devcontainer file, you can configure the following:
And more
This means that whenever you or someone opens a codepspace, the extensions, environment variables, and other configurations you specify in the devcontainer.json file will automatically install when they open a codespace in the specified repository. For example, if I wanted folks to have the same linter and extensions as me, I could add the following to my devcontainer.json file:
devcontainer.json
{
"name": "Node.js",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local arm64/Apple Silicon.
"args": { "VARIANT": "16-bullseye" }
},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint", // this is the exentension id for eslint
"esbenp.prettier-vscode", // this is the extension id for prettier
"ms-vsliveshare.vsliveshare", // this is the extension id for live share
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node"
}
You can learn more about the devcontainer.json file here.
The Dockerfile is a configuration file that tells GitHub Codespaces how to build a container. It contains a list of commands that the Docker client calls while creating an image. Dockerfiles are used to automate the installation and configuration of a container. For example, if I wanted to install Node.js in a container, I could add the following to my Dockerfile:
Dockerfile
FROM node:16-bullseye
You can learn more about Dockerfiles here, and you can learn more about setting up a node.js in Codespaces here.
You don't need a docker-compose.yml file in a Codespace, but it's useful if you want to run multiple containers. For example, if you want to run a database and a web server in a Codespace, you can use the docker-compose.yml file to run both containers. You can learn more about docker-compose.yml files here. Here's an example of what a docker-compose.yml file that's connecting to a database might look like:
docker-compose.yml
version: '3.8'
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
args:
VARIANT: "3"
NODE_VERSION: "none"
volumes:
- ..:/workspace:cached
command: sleep infinity
network_mode: service:db
db:
image: postgres:latest
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
hostname: postgres
environment:
POSTGRES_DB: my_media
POSTGRES_USER: example
POSTGRES_PASSWORD: pass
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- 5432:5432
volumes:
postgres-data: null
GitHub Codespaces is not the same as GitHub’s web editor. The web editor is the editor that appears when you press "." in a repository. It is a lightweight editor that allows you to edit files in your repository. The web editor is great for making minor changes to a file, but it’s not ideal for writing code. However, Codespaces allows you to run a full-fledged IDE in the browser equipped with a terminal and more.
P.S. I wrote this blog post with GitHub Copilot. 😉 (These are all my own words, thoughts, and frustrations, but Copilot helped unblock me when I couldn’t find the right phrases or motivation.)
There's so much to learn about GitHub Codespaces. Comment below if you have any topics regarding GitHub Codespaces you'd like me to cover in future posts. Follow me and GitHub on DEV if you want to see more content like this. Thanks for reading! 🙏🏿