Skip to main content

Development Containers

Configure development container environments in your atmos.yaml to provide consistent, reproducible tooling across your team. Based on the Development Container Specification, Atmos manages named container configurations with support for Docker and Podman runtimes.

Quick Start

The simplest devcontainer configuration uses a pre-built image:

atmos.yaml

devcontainer:
terraform:
spec:
image: "hashicorp/terraform:1.10"
workspaceFolder: "/workspace"

Launch it with:

atmos devcontainer shell terraform

Configuration Structure

Development containers are configured under the top-level devcontainer key. Each entry is a named configuration that can be launched independently:

atmos.yaml

devcontainer:
<name>: # Named configuration (e.g., "geodesic", "terraform", "python")
settings: # Atmos-specific settings (optional)
runtime: "" # "docker", "podman", or omit for auto-detection
spec: # Development Container specification (required)
# ... Dev Container spec fields ...

Settings

Atmos-specific configuration options that control how containers are managed.

settings.runtime

Specify the container runtime to use: "docker", "podman", or omit for automatic detection.

Default: Auto-detect (checks Docker first, then Podman)

When omitted, Atmos will automatically detect which runtime is available on your system. This is useful for teams where some members use Docker and others use Podman.

Example:

devcontainer:
geodesic:
settings:
runtime: "podman"
spec:
image: "cloudposse/geodesic:latest"

Spec (Development Container Specification)

The spec section follows the Development Container Specification. You can provide either a single map or a list of maps (for merging configurations).

Basic Configuration

spec.name

Display name for the container.

Type: string

Example:

spec:
name: "Terraform Development Environment"
spec.image

Pre-built container image to use. Use this or build, not both.

Type: string

Example:

spec:
image: "hashicorp/terraform:1.10"
spec.build

Build configuration for creating a custom container. Use this or image, not both.

Type: object with fields:

  • dockerfile (string) - Path to Dockerfile
  • context (string) - Build context directory
  • args (map) - Build arguments

Example:

spec:
build:
dockerfile: ".devcontainer/Dockerfile"
context: "."
args:
NODE_VERSION: "20"
PYTHON_VERSION: "3.12"

Workspace Configuration

spec.workspaceFolder

Working directory inside the container where commands will execute.

Type: string Default: /workspace

Example:

spec:
workspaceFolder: "/workspace"
spec.workspaceMount

Primary workspace volume mount specification. Uses Docker mount syntax.

Type: string

Supports variable expansion:

  • ${localWorkspaceFolder} - Path to the workspace on your machine
  • ${localEnv:VAR} - Local environment variable

Example:

spec:
workspaceMount: "type=bind,source=${localWorkspaceFolder},target=/workspace"
spec.mounts

Additional volume mounts beyond the workspace. Common uses include mounting credential directories or SSH keys.

Type: array of strings (Docker mount syntax)

Example:

spec:
mounts:
- "type=bind,source=${localEnv:HOME}/.aws,target=/root/.aws,readonly"
- "type=bind,source=${localEnv:HOME}/.ssh,target=/root/.ssh,readonly"
- "type=volume,source=terraform-cache,target=/root/.terraform.d/plugin-cache"

Port Configuration

spec.forwardPorts

Ports to forward from the container to your host machine. Supports both static ports and the !random YAML function for dynamic port assignment.

Type: array of numbers or strings

Example:

spec:
forwardPorts:
- 3000 # Static port
- !random 8080 8099 # Random port in range (avoids conflicts)
- "8080:8081" # Host 8080 to container 8081

Using !random is recommended when running multiple instances to avoid port conflicts.

spec.portsAttributes

Metadata for forwarded ports, such as labels and protocols.

Type: object mapping port numbers/strings to attribute objects

Each port can have:

  • label (string) - Descriptive label
  • protocol (string) - Protocol (http, https, etc.)

Example:

spec:
portsAttributes:
"3000":
label: "Web Server"
protocol: "http"
"5432":
label: "PostgreSQL"
protocol: "tcp"

Environment Configuration

spec.containerEnv

Environment variables to set inside the container.

Type: object (key-value pairs)

Supports variable expansion:

  • ${localEnv:VAR} - Expand from your local environment
  • ${localWorkspaceFolder} - Path to workspace

Example:

spec:
containerEnv:
AWS_PROFILE: "${localEnv:AWS_PROFILE}"
TF_PLUGIN_CACHE_DIR: "/root/.terraform.d/plugin-cache"
TERM: "${localEnv:TERM}"
spec.remoteUser

User to run as inside the container.

Type: string Default: Depends on the image

Example:

spec:
remoteUser: "root"

Runtime Configuration

spec.runArgs

Additional arguments to pass to docker run or podman run.

Type: array of strings

Example:

spec:
runArgs:
- "--network=host"
- "--dns=8.8.8.8"
spec.overrideCommand

Whether to override the image's ENTRYPOINT/CMD.

Type: boolean Default: false

Example:

spec:
overrideCommand: true
spec.init

Run an init process inside the container to handle signal forwarding and reaping.

Type: boolean Default: false

Example:

spec:
init: true
spec.privileged

Run the container in privileged mode.

Type: boolean Default: false

Warning: Only use when necessary for your workflow.

Example:

spec:
privileged: true
spec.capAdd

Linux capabilities to add to the container.

Type: array of strings

Example:

spec:
capAdd:
- "SYS_PTRACE"
- "NET_ADMIN"
spec.securityOpt

Security options for the container.

Type: array of strings

Example:

spec:
securityOpt:
- "seccomp=unconfined"
spec.userEnvProbe

How to probe the user environment inside the container.

Type: string Options: "none", "loginShell", "loginInteractiveShell", "interactiveShell"

Example:

spec:
userEnvProbe: "loginInteractiveShell"

Advanced Features

Merging Configurations with !include

Reuse existing .devcontainer/devcontainer.json files by merging them with Atmos-specific overrides:

atmos.yaml

devcontainer:
geodesic:
spec:
- !include .devcontainer/devcontainer.json # Base configuration
- forwardPorts: # Override/extend
- !random 8080 8099
containerEnv:
AWS_PROFILE: "dev"

When using a list, configurations are merged in order. Later entries override earlier ones.

Dynamic Port Assignment

Use the !random YAML function to avoid port conflicts when running multiple container instances:

atmos.yaml

devcontainer:
app:
spec:
forwardPorts:
- !random 8080 8099 # Assigns random port in range
- 3000 # Static port

This is especially useful when launching multiple instances with the --instance flag.

Multiple Instances

Run multiple containers from the same configuration using the --instance flag:

# Default instance
atmos devcontainer shell geodesic

# Named instances
atmos devcontainer shell geodesic --instance dev
atmos devcontainer shell geodesic --instance prod
atmos devcontainer shell geodesic --instance testing

Each instance gets a unique container name: atmos-<config>-<instance>.

Common Patterns

Pattern: Simple Image-Based Container

Use a pre-built image for quick development environments:

atmos.yaml

devcontainer:
python:
spec:
image: "python:3.12"
workspaceFolder: "/workspace"
containerEnv:
PYTHONPATH: "/workspace"

Pattern: Custom Dockerfile Build

Build a custom container with specific tools:

atmos.yaml

devcontainer:
custom:
spec:
build:
dockerfile: ".devcontainer/Dockerfile"
context: "."
args:
NODE_VERSION: "20"
TERRAFORM_VERSION: "1.10"
workspaceFolder: "/workspace"

Pattern: Geodesic Shell (Multi-Tool Environment)

Use Geodesic as a comprehensive toolbox:

atmos.yaml

devcontainer:
geodesic:
settings:
runtime: "docker"
spec:
- !include .devcontainer/devcontainer.json
- forwardPorts:
- !random 8080 8099
- !random 3000 3099
containerEnv:
AWS_PROFILE: "dev"
TF_PLUGIN_CACHE_DIR: "/root/.terraform.d/plugin-cache"

Pattern: Mounting Authentication Credentials

Mount cloud provider credentials into your container:

atmos.yaml

devcontainer:
terraform:
spec:
image: "hashicorp/terraform:1.10"
workspaceFolder: "/workspace"
mounts:
- "type=bind,source=${localEnv:HOME}/.aws,target=/root/.aws,readonly"
- "type=bind,source=${localEnv:HOME}/.azure,target=/root/.azure,readonly"
containerEnv:
AWS_PROFILE: "${localEnv:AWS_PROFILE}"
AZURE_SUBSCRIPTION_ID: "${localEnv:AZURE_SUBSCRIPTION_ID}"

Alternatively, use Atmos identity injection with the --identity flag for enhanced security.

Complete Example

A comprehensive configuration showing all major features:

atmos.yaml

devcontainer:
# Simple image-based container
terraform:
spec:
name: "Terraform Development"
image: "hashicorp/terraform:1.10"
workspaceFolder: "/workspace"
forwardPorts:
- !random 8080 8099
mounts:
- "type=bind,source=${localEnv:HOME}/.aws,target=/root/.aws,readonly"
containerEnv:
TF_PLUGIN_CACHE_DIR: "/root/.terraform.d/plugin-cache"
AWS_PROFILE: "${localEnv:AWS_PROFILE}"

# Custom build with Podman
custom:
settings:
runtime: "podman"
spec:
name: "Custom Development Environment"
build:
dockerfile: ".devcontainer/Dockerfile"
context: "."
args:
WORKSPACE: "/workspace"
workspaceFolder: "/workspace"
remoteUser: "developer"
init: true

# Geodesic with merged configuration
geodesic:
spec:
- !include .devcontainer/devcontainer.json
- name: "Geodesic Cloud Shell"
forwardPorts:
- !random 8080 8099
- !random 3000 3099
portsAttributes:
"8080":
label: "Application"
protocol: "http"
containerEnv:
AWS_PROFILE: "dev"
TERM: "${localEnv:TERM}"

Environment Variables

The devcontainer configuration is read exclusively from atmos.yaml and does not support environment variable overrides. However, individual container settings support environment variable expansion using ${localEnv:VAR} syntax within the spec section.

See Also