Environments
DevContainer

Development Containers

Dev containers and Gitpod configuration files are both powerful tools used to define and standardize development environments. This guide will explore their features, compare them, and provide detailed information on customizing dev containers for your project.

Note: This was first conducted here. (opens in a new tab)

Dev Containers vs. Gitpod

Both dev containers and Gitpod aim to create consistent development environments, but they have different use cases and features.

Comparison Table

FeatureDev ContainersGitpod
Defines development environmentYesYes
Runs on local machine (e.g., VSCode)YesNo
Runs in the cloud via URLNo (but possible with GitHub Codespaces)Yes
Extension configurationYesYes
User managementYesYes
Configuration filedevcontainer.json.gitpod.yml
Primary use caseLocal development, CI/CD pipelinesInstant cloud development environments

Key Differences

  1. Execution Environment:

    • Dev containers run locally on your machine, typically within VS Code.
    • Gitpod creates cloud-based development environments accessible via a URL.
  2. Setup Complexity:

    • Dev containers might require more initial setup but offer more control over the local environment.
    • Gitpod provides a more immediate start with less local configuration needed.
  3. Integration:

    • Dev containers integrate seamlessly with local VS Code installations.
    • Gitpod is designed for browser-based development and integrates well with GitHub, GitLab, and Bitbucket.
  4. Resource Usage:

    • Dev containers use local system resources.
    • Gitpod uses cloud resources, which can be beneficial for developers with less powerful local machines.

Customizing Dev Containers

The devcontainer.json file allows for extensive customization of your development environment. Here's a guide to some key customizations:

Basic Structure

A typical devcontainer.json file might look like this:

{
    "name": "My Project Dev Container",
    "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
    "features": {
        "ghcr.io/devcontainers/features/node:1": {}
    },
    "customizations": {
        "vscode": {
            "extensions": [
                "dbaeumer.vscode-eslint"
            ]
        }
    },
    "settings": {
        "terminal.integrated.profiles.linux": {
            "bash": {
                "path": "/usr/bin/bash",
                "icon": "terminal-bash"
            }
        },
        "terminal.integrated.defaultProfile.linux": "bash",
        "terminal.integrated.fontSize": 20,
        "editor.fontSize": 20,
        "workbench.colorTheme": "Default Dark+ Experimental"
    },
    "forwardPorts": [3000],
    "postCreateCommand": "npm install"
}

Key Components

  1. Base Image: Specified by the image property. Choose a base image that suits your project's needs.

  2. Features: Add tools and runtimes using the features property.

  3. VS Code Customizations:

    • extensions: Specify VS Code extensions to be installed.
    • settings: Customize VS Code settings for this container.
  4. Port Forwarding: Use forwardPorts to specify which ports should be forwarded from the container to the host.

  5. Post-Creation Commands: Use postCreateCommand to run commands after the container is created, like installing dependencies.

Advanced Customizations

  1. Environment Variables: Add environment variables using the remoteEnv property:

    "remoteEnv": {
        "MY_VARIABLE": "my-value"
    }
  2. Mount Volumes: Mount additional volumes using the mounts property:

    "mounts": [
        "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
    ]
  3. User Settings: Specify the user the container should use:

    "remoteUser": "vscode"
  4. Dockerfile: For more complex setups, you can use a custom Dockerfile:

    "build": {
        "dockerfile": "Dockerfile"
    }

Best Practices

  1. Version Control: Always version control your devcontainer.json file to ensure consistency across the team.

  2. Documentation: Comment your devcontainer.json file, especially for complex setups.

  3. Minimal Base Image: Start with a minimal base image and add only what's necessary.

  4. Test Regularly: Regularly rebuild your container to ensure it still works as expected.

  5. Use Features: Leverage the features property for common tools instead of installing them manually.

Developer References

By mastering dev containers, you can create consistent, reproducible development environments that enhance collaboration and streamline your development workflow.