8 reasons I love Dev Containers

David Dahan
Apr 2023 6 min
tech
environment
tools
architecture

What is a dev container?

In a few words, it's a full-featured development environment living in a dedicated container. It allows you to define this environment in a declarative way, using a config file, and connect to it, using VS Code. As stated in its presentation: "this lets VS Code provide a local-quality development experience including full IntelliSense (completions), code navigation, and debugging regardless of where your tools (or code) are located." It can be used in various ways but the obvious usage is to use Docker dev containers running on your own laptop. The file system can be mounted and synchronised between your host machine and the container, or better, you can clone a Git repository directly to the container without any mounting/syncing.

Surprisingly, this feature is not very known nor widely used yet. This could be because it's quite new, or it may be hard to notice all the benefits it provides without actually using it, I'm not sure. But let me try to convince you how helpful it is, by showing how it helped me in my last projects.

How can a dev container be helpful?

1. Sandboxing

Any project using a container is entirely isolated:

  1. from your host OS
  2. from your other dev containers.

Sandboxed environments do not mess with the host OS packages nor between the different projects themselves.

  • No more conflict between packages with their dependencies.
  • You don't need tools like NVM (node) or venv (python) anymore, since your container requires a single version of node or python installed. You don't even ask yourself if a package must be installed locally or globally, since the distinction makes no sense anymore.
  • You can be the root user on the container(s), removing all permission-issues related. This saves time and energy.
  • Containerized projects avoid any risk of bricking your host OS by installing weird stuff. My computer stays clean over time.
  • Dev containers are totally compatible with Docker compose. This means you can easily sandbox a more complex project in multiple containers. For example, if you want to separate a web server, an SQL database, and a Redis store.

As you see, sandboxing removes a lot of complexity and various potential issues by the simple mechanism of isolation.

2. Instant Rebuilding

Whatever happens to your environment, you can rebuild it, running a simple VS Code command. It's because everything concerning the project installation is declared in a config, and that this config is versioned on your repository. It will usually take around 20 seconds for my projects, using Docker cache. But why is this so great?

  • You can mess up with your project: you can run any command with no fear, erase files accidentally, make any bold move, etc. It's like a videogame: if you mess up, you can go back to the previous state in a few seconds.
  • You give up the "upgrade" logic: without dev containers, if you need to upgrade any component, it's probably faster and safer to do it rather than reinstalling all the environment. This is not the case anymore with dev containers. You just declare the new version, and run a rebuild. 20 seconds later, you get a fresh new project with the last version, without updating anything. It's as if you were always setting up new projects, rather than upgrading them.
  • If you use multiple computers (like a Desktop at home and a laptop outside), you can keep a consistent environment between them by downloading the latest container config and rebuilding it. Or you could even use a remote environment, but shhh, it's in an upcoming section of this article!
  • You can even have your computer stolen, or change for a new one easily, with no difference.

3. One-click Project setup

Do you remember the days when you had to follow a 17-step process to set up a project on your laptop? It was long, unreliable, painful, and often eventually failed somewhere because you had a different computer than the person who wrote it. Right? With dev containers, these days are over. Just install Docker, and run the Clone Repository in Container Volume command. Done. There is no setup process anymore, since the setup itself is declared in the config files.

4. Dev/Prod Environment Parity

A good piece of advice for any serious project is to have the most similar environments, especially when not using an intermediary environment like staging, before pushing to production.

In that sense, It seems risky to me to use Windows (or even Mac OS) while your production server runs on Debian. Even if mac OS is unix based, commands are different. Using a dev container, you can choose the same OS that your production environment uses, and avoid accidental complexity related to your host OS. And yes, you may think "we could have done this 10 years ago using tools like VirtualBox or Vagrant". But the general developer experience would have been totally different using your IDE inside a graphical virtual machine, or using SSH to access your file system from your local host. Remember that the promise of a dev container is to keep the same developer experience than the local one. We can't compare apples and oranges.

Besides, when using dev containers with Docker, you could in theory use these Docker files to mirror the setup in production. All that learning to make a clean environment should be used as many times as possible, right? People already using Docker in production should be even more prone to use dev containers.

5. Dev/Dev Environment Parity

While we saw dev containers are already amazing for single developers, they shine even more when used within a team of multiple developers. And it's easy to understand why: imagine a world where any developer of your team, no matter its computer or OS, can install the exact same project with no effort? No matter if your teammate has a mac or a windows, in the end, the container will hold the same OS, the same OS packages, the same project packages, and even the same editor extensions and settings.

This work is versioned, and automatically shared with your teammates, after a git push. This means it's a "once and for all" work, which instantly benefits all your teammates.

By using dev containers, you allow any newcomer to work on the project almost instantly with no effort, making you the team Hero :)

6. Facilitated Team organization

It's hard when starting a project to define rules between developers. How to format code the same way, how many characters by lines, which warning messages should be addressed, etc. Very quickly, developers can disagree on some details and someone has to decide. When all these decisions are enforced, it makes everyone's life easier. Let's see how.

VS Code is very customizable and allows configuration both at user level, and container (project) level. This facilitates the organization:

  • On one hand, team requirements are extensions and settings that are defined in the container config file. They will be enforced and will override the user preferences if they exist. For example: install Prettier extension with a 90 char per line setting is a project setting.
  • On the other hand, user preferences are extensions and settings that are NOT defined in the container, and then, supposed to be free to use to the developer. For example: install Material theme extension or format code on save is a user personal preference.

This distinction has always existed, but dev containers, from their declarative nature, allow CTOs to set things in stone, rather than relying on other developers' good will.

Note that even if you're a single developer working on multiple projects, this VS Code settings flexibility will make your VS Code change automatically when you switch projects, with the right extensions and the right config.

7. Reuse for other projects

All the time you spend having clean config files, are totally reusable for other projects. That's the role of Docker after all. I personally wrote some scripts that install OS-level packages, customize my PS1, or set some useful aliases. These scripts can be hosted on github and downloaded at the container build time.

8. Your machine … or not

As you may have noticed in the architecture chart at the beginning, nothing actually forces the container to live on your local machine. It could be a remote machine with other characteristics. Need some horsepower for AI-related tasks? No problem. What's brilliant here is the ability to keep a wonderful developer experience while using a remote environment. This is because VS Code UI lives on your host machine while VS Code server is executed on the container itself. It provides a much better experience than techniques like SSHFS.

If you're working on multiple projects, no matter if they are on local or remote containers, it will be completely invisible to you: you just connect to your container to run the project.

Thanks to this decoupled architecture (and that VS Code runs on Electron, something more unexpected is that you can even use a simple browser on an iPad to run VS Code (its UI part), while VS Code server runs the remote machine, keeping a good user experience. It basically allows you to keep the same developer experience, no matter the host machine you're using, because most of the demanding work happens at the server level.

Conclusion

Are dev containers perfect? No:

  • There is a learning curve, you need to learn the basics of Docker
  • Debugging when building your first containers can be painful, as errors are not always self-explanatory
  • As far as I know, they're still tied to VS Code and force your team to use the same IDE
  • They drag memory, CPU, and battery on your laptop, so you'd better have a decent computer to use them properly

But they're totally worth it. I can't even imagine going back and losing all these benefits.


written by
David Dahan
3 likes