Using VS Code Remote Containers without Docker Desktop

Introduction

Transitioning to DevContainer Architecture & Core Tooling without Docker Desktop requires precise runtime socket mapping and deterministic environment variables. This guide provides a reproducible configuration for routing VS Code DevContainers through Podman, Colima, or Rancher Desktop while maintaining full spec v1.0+ compliance. Engineering teams adopting this approach eliminate Docker Desktop licensing overhead while preserving deterministic, containerized development workflows.

1. Runtime Selection & Socket Preparation

Select a Docker-compatible CLI such as Podman, Colima, or Rancher Desktop. Ensure the daemon exposes a Unix socket compatible with the Docker API. For rootless setups (Podman’s default), map the host UID/GID explicitly to prevent permission denied errors during volume mounts.

Verify daemon readiness before proceeding:

# Colima
colima start
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"
docker info

# Podman (with system service enabled)
podman system service --time=0 unix:///run/user/$(id -u)/podman/podman.sock &
export DOCKER_HOST="unix:///run/user/$(id -u)/podman/podman.sock"
docker info

The VS Code DevContainer Extension Deep Dive requires this socket handshake to initialize the remote server.

2. Deterministic Environment Overrides

Configure your host shell to export DOCKER_HOST before launching VS Code. This forces the Dev Containers extension to bypass Docker Desktop auto-detection and route directly to your chosen runtime. Persist these variables in ~/.zshrc or ~/.bashrc for deterministic behavior across sessions.

VS Code also respects DOCKER_HOST set in workspace settings via "remote.containers.dockerPath" (the path to the docker-compatible CLI binary). For Podman, set this to the podman binary path and ensure it implements the Docker CLI interface.

3. devcontainer.json Adjustments for Alternative Runtimes

Modify .devcontainer/devcontainer.json to ensure the configuration works with rootless runtimes. The key adjustment for Podman’s rootless mode is ensuring remoteUser matches the host user — Podman maps container UIDs to the host user’s subuid range by default.

Use initializeCommand to verify socket connectivity before the container builds. Spec v1.0+ requires strict adherence to these fields for cross-platform consistency.

4. Validation & Connection Testing

Execute devcontainer up --workspace-folder . via CLI to bypass UI caching. Verify docker info inside the container returns the correct runtime. Confirm VS Code Server attaches successfully and file sync operates without latency. Inspect the Dev Containers output channel in VS Code for socket handshake failures.

Refer to the VS Code DevContainer Extension Deep Dive for advanced telemetry parsing.

Code

Host environment socket routing

# Colima (recommended for macOS)
colima start --cpu 4 --memory 8 --disk 60
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"

# Verify routing before opening VS Code
docker context ls
docker info | grep 'Server Version'

devcontainer.json for alternative runtimes

{
  "name": "deterministic-dev-env",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "initializeCommand": "test -S ${DOCKER_HOST#unix://} || (echo 'Docker socket missing' && exit 1)",
  "remoteUser": "vscode",
  "features": {
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  }
}

Podman socket symlink (macOS/Linux)

# Create deterministic symlink for VS Code extension
# Podman rootless socket location varies by platform
PODMAN_SOCK="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/podman/podman.sock"
podman system service --time=0 "unix://${PODMAN_SOCK}" &
export DOCKER_HOST="unix://${PODMAN_SOCK}"

Common Pitfalls

SymptomRoot CauseRemediation
Permission denied on volume mountsRootless runtime UID/GID mismatchUse --userns=keep-id (Podman) or ensure remoteUser UID matches the host user
Extension fails to attach after switchVS Code caching stale Docker contextClear ~/.vscode/extensions/ms-vscode-remote.remote-containers-* cache and restart
Multi-service definitions fail to resolveMissing docker compose v2 pluginInstall docker-compose-plugin or use podman-compose aliased to docker compose
Connection timeout during buildIncorrect DOCKER_HOST protocol prefixEnsure unix:// or tcp:// prefix matches runtime daemon configuration exactly
Bind mounts silently fail on macOSFile sharing restrictions in VM-based runtimesExplicitly declare shared directories in runtime VM config (e.g., colima start --mount ~/projects:w)

Conclusion

Alternative runtimes are fully compatible with VS Code DevContainers as long as they implement the Docker API socket. The two essential steps are: export DOCKER_HOST pointing to the correct Unix socket, and ensure the runtime is running before VS Code launches. For macOS, Colima provides the most friction-free Docker Desktop replacement.

FAQ

Does replacing Docker Desktop break DevContainer spec compliance? No. The DevContainer specification relies on OCI-compliant runtimes and Docker-compatible CLI commands. Alternative runtimes that implement the Docker API socket or CLI aliases remain fully compliant with spec v1.0+.

How do I handle multi-service DevContainers without Docker Desktop Compose? Use docker compose v2 (standalone binary or plugin) or Podman Compose. Ensure your devcontainer.json dockerComposeFile points to a valid YAML and that the DOCKER_HOST environment variable routes compose commands to the correct daemon.

Why does VS Code fail to attach after switching runtimes? The extension caches the previous Docker context. Clear the ~/.vscode/extensions/ms-vscode-remote.remote-containers-* cache directory, restart VS Code with DOCKER_HOST explicitly exported, and run Dev Containers: Rebuild Container from the command palette.