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:
- Why are people developing inside containers?
- What are containers?
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.
What does it mean to develop inside a container?
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 takes software and cloud development to the next level
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.
Faster onboarding
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.
Code from anywhere
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.
Consistent environments
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.
Three files you may need to configure a Codespace
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
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:
- Extensions
- Environment variables
- Dockerfile
- Port forwarding
- Post-creation commands
- 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
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.
The docker-compose.yml file
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
Codespaces is not the same as GitHub’s web editor
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 and running full stack web applications. This is because the GitHub web editor does not have a terminal. However, Codespaces allows you to run a full-fledged IDE in the browser equipped with a terminal and more.
See the below image to understand the differences between GitHub's web editor and GitHub Codespaces. This image is from the GitHub official documentation. You can read more details here.
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! 🙏🏿
Top comments (16)
I was struggling with the whole containerization concept and this article really helped me 🔥
I’m glad it helped. This comment made my day!
I've recently been using Docker for developing my API in a little project because mongodb doesn't work on M1 yet.
And from that necessary use case I am now hooked on them. Not having my machine bogged down with different versions of things and programs is great. And a single command from a single terminal to get my BE going means I'm more likely to jump in a tinker around when I've got nothing to do.
I have been interested in codespaces since I saw the reveal video, but I only have experience with GitPod which was super handy.
And what successful alternatives are they that do the same thing but do not have a vendor lock-in to Github?
Hmm, maybe GitPod, CodeSandbox, and Repl.it. Transparently, I work at GitHub, and I'm most familiar with using GitHub Codespaces..so I don't know what the set up looks like for these tools or if you can pre-install things like extensions in those IDEs. I think you can with GitPod..that may be the closest alternative.
Any reason why you're looking for something outside of GitHub?
Because it's vendor lock in. GitHub's pricing may be competitive now but how can I know it will still be few years from now? In the worst case scenario I can't selfhost codespaces.
GitPod on the other hand can be selfhosted and you're not vendor locked-in to GitHub with your repo(GitHub is currently the best Git service but who knows if that's gonna be the case in the future)
The same with databases. You shouldn't use Firestore(or Firebase as a whole) for that reason. You should use something standard (SQL) so when your provider of choice goes under, you dump everything, create a DB with another provider or you selfhost one, restore the dump on the new database, change environment variables and you're good to go.
Fair points!!
Thanks for sharing this. I like the way it starts from very scratch. 🙌🎈
Thank you! I wrote it in the way that I learn best. Appreciate your comment.
The caption is misleading and a bit clickbait. Let's avoid this.
GitHub is a specific environment not suitable to all development.
Containers on their own can't help facing tons of other issues, as e.g. different runtime placement and timeouts in interaction to a public service. Well, they definitely have huge advantage of exact stable environment, but it is not absolute.
Hi Valentin,
The blog banner I used says "Why are people developing in containers: GitHub Codespaces." I work at GitHub, so my goal is to continue informing people about Codespaces as an option for development. I also thought it would be cool to give beginners more context about containers. I was able to accomplish my goal of introducing people to both GitHub Codespaces and containers. People have messaged me that this post clarified a bit for them. I am also in the process of learning, so I'm sharing as I learn.
If you have more to share about containers, I encourage you to write about it and share it. Thank you!
Hello Rizèl Scarlett,
thank you for your article.
Now I understand Docker a bit better.
I love the structure in your article and it was easy to read.
I am also glad of the links your article provides because I think it adds more credibility.
As the next article, I would very much like to know in detail how Copilot helped you to write this article.
Thank you for this article. I have been struggling too to answer the exact question: What's the noise about containers really? This article is simple but very straight to the point.
Now, I use Visual Studio 2022 to develop software against a Sql Server database, can I use the GitHub Codespaces??
Rizèl, thank you for this post and a couple of others like codespaces for training. It's so great to see someone who is actually deep in code espousing this stuff. I fell in love with cloud-based development when I first came across cloud shell in 2016-ish. That was always a bit proprietary though, so the whole devcontainer thing is so much more to my taste! It surprises me that this approach isn't way more popular amongst my senior devs, maybe it's just a matter of time now. Anyway, you've saved me a BUNCH of time setting up my own new company website on github pages, using devcontainer as my IDE, with your config. Bravo :)
Is it possible to use 2 repo for 1 project?
My company use 1 repo for development container and other for actual code
Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more