Dev Containers

Dev Containers

Docker is well-known and is widely used in the software application realm. In recent years, it has made its way into many embedded software projects. In embedded development, it is mainly used for running builds and tests locally on the machine or on Continuous Integration/Continuous Deployment (CI/CD) platforms. 

Check out our Using Docker for Embedded Development blog post to learn more about it. The Dockerfile can start off simple with a few required packages, and it quickly grows in size and complexity as a project progresses. Aside from a complicated Dockerfile, in order to develop code within a Docker container, we have to install screen-based text editors such as vim. For the developers who are not familiar with any of the screen-based text editors, they have to spend some time learning one of them before they can be productive within a Docker container. It will definitely speed things up if we can visualize and modify the files within the Docker container on an IDE. This is where Dev Containers come in.

What are Dev Containers?

A Dev Container, or Development Container, is a Docker Container that provides an isolated, consistent environment that consists of the IDE, tools, and packages that we need to develop software. Once it is set up and checked into version control, the developers can focus on the real product instead of spending extra time on setting up or replicating the build environment.

Why Dev Containers?

A dev container has all the benefits that a Docker container can offer, such as being a fast, lightweight, and standardized environment. By being able to integrate with the IDE, it provides an interface for us to interact with a Docker container and makes a complicated Docker container more manageable. The following sections will expand on the benefits of using dev containers.

Time Saving

In the beginning of a project, time spent on setting up a build and test environment is unavoidable, but we can save the time when the next developer tries to set up the same environment. When new developers join the team, many hours could be spent on trying to set up or replicate the same environment. With dev containers, one can set up the environment by just installing an IDE, such as Visual Studio Code, Docker and running the dev container.

Consistency

There are many existing ways of creating isolated environments and managing tools and packages, such as using Python Virtual Environments and Poetry, but we often still end up dealing with the “it works on my machine” situation. For example, a different version of a toolchain can result in a different binary that acts differently. By using the dev containers, all developers use the same versions of tools and configurations to build and test their code.

IDE Integration

Dev containers improve the interaction with the Docker container by integrating with the IDEs. The IDEs that currently support Dev Containers are Visual Studio Code (VS Code) and JetBrains IDEs, and we will be focusing on the VS Code Dev Containers in this blog post. The configuration of a dev container is described in a devcontainer.json file. The devcontainer.json file can be created manually or by using the VS Code Dev Container extension in a .devcontainer directory in the root directory of our project.

With the devcontainer.json in place, the project can now be opened in a dev container by using the VS Code Dev Container extension’s Reopen in Container command. It will look exactly like when it is opened locally on the host machine. VS Code extensions such as C/C++ (IntelliSense) and Cortex-Debug can be configured in the customizations section of the devcontainer.json so that these extensions will be installed in the dev container. By doing so, we can now navigate the code base and even debug the code in the dev container.The following is an example of a devcontainer.json that uses ubuntu:24.04 as a base image and installs Git, VSCode’s C/C++, and CMake Tools extensions:

{
	"image": "ubuntu:24.04",
	"features": {
		"ghcr.io/devcontainers/features/git": {},
	},
	"customizations": {
		"vscode": {
			"extensions": [
				"ms-vscode.cpptools",
				"ms-vscode.cmake-tools"
			],
		},
	}
}

When we open the VS Code integrated terminal (for MacBook users: command + shift + P -> View: Toggle Terminal), we are actually within the Docker container. Because of that, we can use the tools that were installed within the Docker container to interact with the code base. For example, if GCC is installed in the container, we can now build our code without having to install GCC on our host machine and the version of the GCC is fixed. VS Code has a nice documentation on how to set up and start using a dev container.

Devcontainer CLI

When we open a project, VS Code uses a CLI in the background to configure the dev container. The CLI is available for developers to create and use dev containers outside of the IDE. The following are the steps to get started on the devcontainer CLI:

// For MacBook users, install node via Homebrew
brew install node

// Install devcontainer CLI via npm
sudo npm install -g @devcontainers/cli

// Spin up a dev container
devcontainer up --workspace-folder <path-to-the-project>

// Run a command in the dev container
devcontainer exec --workspace-folder <path-to-the-project> <command>

Simplify Dockerfile

Dev containers make Dockerfiles modular. Instead of installing all the required IDEs, tools, and packages in a single Dockerfile, we can make use of the features section of the devcontainer.json by adding the tools we want to install in our Docker container. The features are links to the Docker images hosted on public or private Docker registries. A list of official dev container features can be found here. We can install IDEs or tools that cannot be found on the public Docker registry in a customized Docker image, but instead, by turning them into features that can be included in the dev container, we can have a much simpler base image. The customized features can then be reused in other projects as well.

Automatic Mounting of Filesystem

When we open a project with a dev container on an IDE, it automatically mounts the project’s filesystem within the Docker container. Modifications to the files on the IDE will reflect in both the local files on the host machine and the files in the Docker container. This can be achieved by running a Docker container with the -v or -volume flag by using the Docker CLI, but the dev container sets it up without having to type out the long Docker CLI command.

Conclusion

Docker itself has been a revolutionary tool. Dev containers further elevate the usage of Docker in software development. Besides the benefits of saving time and providing a consistent development environment provided by the nature of Docker containers, dev containers reduce the complexity of using Docker by integrating with IDEs and simplifying the Dockerfiles.

Dojo Five is dedicated to modernizing the embedded industry by using modern practices and tools such as Docker and dev containers. If you are interested in bringing your project to the next level, you can schedule a call with our team. Or, feel free to check out EmbedOps, our CI build platform. It’s free to sign up.

We look forward to hearing from you! -D5

Discover why Dojo Five EmbedOps is the embedded enterprise choice for build tool and test management.

Sign up to receive a free account to the EmbedOps platform and start building with confidence..

  • Connect a repo
  • Use Dev Containers with your Continuous Integration (CI) provider
  • Analyze memory usage
  • Integrate and visualize static analysis results
  • Perform Hardware-in-the-Loop (HIL) tests
  • Install the Command Line Interface for a developer-friendly experience

Subscribe to our Monthly Newsletter

Subscribe to our monthly newsletter for development insights delivered straight to your inbox.

Interested in learning more?

Best-in-class embedded firmware content, resources and best practices

Get gui showing commit messages

Using a Git GUI Isn’t All Bad (And Sometimes Pretty Useful)

While not the popular opinion of CLI git users, I’ve gotten a ton of mileage from my git GUI. Using the CLI rather than a GUI provides a lot of value: seeing the bigger picture of your code and being able to navigate through different branches, commits or history can become clean and easy to understand with a little help from your friendly GUI. As a recap on what each term means, here is a description of git, CLI and

Read More »
Build Yocto Faster with EmbedOps

Build Yocto Faster with EmbedOps

Ask an embedded engineer what they do while a Yocto image builds and you get a version of the same answer. They switch to something else and forget to come back, or they can’t concentrate because the thing might finish any minute. As one told us, the wait is hard to put to any effective use. On the image we benchmark against, the first build takes an hour and 43 minutes. The ones after it take 8 to 12 minutes

Read More »
Docker Whale

Docker: An Ideal Development Environment

Docker is a revolutionary tool that provides speed and repeatability for an embedded team. While traditionally used in non-firmware environments, there is enormous potential to improve the development efforts of firmware projects by making use of Docker. The Problem A few decades ago, you could submit your work as a batch job to a common environment, shared by everyone.Everyone used the same tools and the same settings. As technology improved, the shared environment slowly started moving towards personalized spaces; first

Read More »