Why Your Team Should Ditch VMs for Container‑Based Development Environments
The article examines the hidden costs and inefficiencies of assigning a virtual machine to each developer, explains why containers and cloud‑native tools like Codespaces, Gitpod, and Kubernetes‑based platforms offer lighter, on‑demand alternatives, and provides practical guidance for transitioning.
Problem with per‑developer virtual machines
Many organizations allocate a dedicated VM for each developer and each project. Over time these VMs become idle, accumulate, and increase infrastructure cost while providing little visibility into actual usage.
Container‑based development environments
Tools that launch a development container directly from a source repository eliminate the need for long‑lived VMs. The typical workflow is:
Open the repository in the platform (GitHub, GitLab, Bitbucket, etc.).
The platform reads a devcontainer.json (or equivalent) and builds the specified Docker image.
All required SDKs, language runtimes, and debugging extensions are installed automatically.
The developer connects through a Web IDE or a remote‑VS Code client; the environment is identical on any device.
Popular services:
GitHub Codespaces – tightly integrated with GitHub repositories; start a codespace with a single click.
Gitpod – works with any Git provider; can be triggered via a URL or a .gitpod.yml file.
Devcontainer – a VS Code feature that can be used locally or on any remote host that supports Docker.
Typical devcontainer.json example
{
"name": "Node.js development",
"image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:0-14",
"postCreateCommand": "npm install",
"extensions": ["dbaeumer.vscode-eslint"],
"forwardPorts": [3000]
}This file defines the base image, runs a command after the container is created, installs VS Code extensions, and forwards ports needed for local testing.
Self‑hosted solutions for internal SCM platforms
When code resides on internal Git servers (e.g., Bitbucket Server, GitLab CE/EE) the public cloud services are unavailable. Two common approaches are:
Coder – an open‑source platform that runs on Kubernetes and provides on‑demand container workspaces. Deploy Coder via its Helm chart, define workspace templates that reference a devcontainer.json, and let developers start a workspace through a web UI or CLI.
Custom Kubernetes‑based IDE platform – build a lightweight service that watches a repository, creates a pod from a devcontainer image, and exposes the pod via SSH or a Web IDE (e.g., Theia, code‑server). The pod can be torn down automatically after inactivity.
Key benefits of these approaches:
Resources are allocated only while a workspace is active, eliminating long‑term idle VMs.
Centralised policy enforcement (resource quotas, network rules) simplifies management.
Environment definitions are version‑controlled, guaranteeing reproducibility.
Traditional tools for special scenarios
Legacy or highly specific setups may still require classic tooling:
Docker Compose – useful for local multi‑service integration (e.g., API, Redis, frontend). A typical docker‑compose.yml can spin up all services with a single docker compose up -d command.
Vagrant – convenient for reproducing Windows or legacy OS environments that cannot be containerised. Vagrantfiles describe the VM provider (VirtualBox, Hyper‑V) and provisioning steps.
Drawbacks of these tools include larger image sizes, slower start‑up times, and lack of native cloud‑native orchestration, making them less suitable as the primary development platform.
Guidelines for choosing a development environment
Prefer container‑based workspaces whenever the codebase can be built inside a Linux container.
Automate environment provisioning with devcontainer.json, .gitpod.yml, or Coder workspace templates to avoid manual setup.
Reserve Docker Compose or Vagrant for cases that require multiple heterogeneous services or non‑Linux OS simulation.
Treat VMs as a fallback for workloads that cannot be containerised (e.g., hardware‑dependent testing).
Outcome
Adopting on‑demand containerised development environments reduces idle VM count, lowers infrastructure cost, and provides consistent, reproducible toolchains across the team.
DevOps Engineer
DevOps engineer, Pythonista and FOSS contributor. Created cpp-linter, commit-check, etc.; contributed to PyPA.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
