Skip to main content
Ona fully supports Development Containers, allowing you to standardize development environments across your team. Define your setup in a devcontainer.json file to ensure consistent tools, dependencies, and configurations for all developers.

Benefits

Using Dev Containers with Ona provides several advantages:
  • Standardized environments across all team members
  • Consistent tooling with precisely defined dependency versions
  • Isolated Linux VM environments, even when running locally
  • Support for both single and multi-container development setups
  • Version-controlled configuration that lives with your codebase
  • Integration with VS Code and other supported editors
  • Separation of development environment from local machine configuration

Configuration

File Location

Place your devcontainer.json file in one of these standard locations:
  • .devcontainer/devcontainer.json
  • .devcontainer.json

Basic Configuration Example

{
	"name": "My Project",
	"image": "mcr.microsoft.com/devcontainers/universal:4.0.1-noble",
	"features": {
		"ghcr.io/devcontainers/features/docker-in-docker:2": { "moby": false }
	},
	"customizations": {
		"vscode": {
			"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
			"settings": {
				"editor.formatOnSave": true
			}
		},
		"jetbrains": {
			"plugins": ["com.wix.eslint", "intellij.prettierJS"]
		}
	},
	"forwardPorts": [3000, 8080]
}
This configuration:
  • Uses the Universal image with common languages and tools pre-installed (Node.js, Python, Go, Java, and more)
  • Adds Docker-in-Docker support
  • Includes ESLint and Prettier VS Code extensions
  • Installs the ESLint & PrettierJS plugin for JetBrains IDEs
  • Configures auto-formatting on save
  • Forwards ports 3000 and 8080

Multiple Dev Container configurations

You can manage multiple Dev Container configurations using Ona projects. This allows you to define different environments for:
  • Different branches or repositories
  • Various development scenarios
  • Specialized tasks requiring specific tools

Known limitations

When using Dev Containers with Ona, be aware of these limitations:
  • Platform-specific features may not work with Ona Desktop
  • Conflicting features can cause build failures (Ona will display an error message)
  • Some Dev Container commands might behave differently in Ona’s environment
  • When build errors occur, recovery mode is engaged, requiring manual intervention
Microsoft provides well-maintained Dev Container base images for popular development stacks:
  • mcr.microsoft.com/devcontainers/universal:4.0.1-noble - Full-featured image with common languages and tools
  • mcr.microsoft.com/devcontainers/javascript-node - Node.js development
  • mcr.microsoft.com/devcontainers/python - Python development
  • mcr.microsoft.com/devcontainers/dotnet - .NET development
  • mcr.microsoft.com/devcontainers/java - Java development
  • mcr.microsoft.com/devcontainers/go - Go development
  • mcr.microsoft.com/devcontainers/base:ubuntu - Minimal image

Advanced configuration

Using secrets during builds

Organization and project secrets can be used during Dev Container image builds via secret mounts. This is useful when your Dockerfile needs to authenticate with private package registries, pull licensed dependencies, or access credentials that should not be baked into the final image. Secrets are not exposed by default. Each RUN instruction in your Dockerfile must explicitly request the secrets it needs using the --mount=type=secret flag. The mounted secret itself is only available for the duration of that RUN step and is not included in the image layer.
The secret mount is ephemeral, but commands within the RUN step can still write secret values to files or configuration stores that are persisted in the image. If you don’t want a credential to be available in the resulting image, avoid commands like npm config set that write credentials to disk — use the env= mount pattern or clean up any written files before the RUN step ends.
User secrets are not available during builds. Built images are cached and shared across the project when the Dev Container image cache is enabled, so personal credentials in a build could be exposed to other team members.
Build-time secret mounts require a Dockerfile-based Dev Container (build.dockerfile or dockerFile in devcontainer.json). Docker Compose-based Dev Containers are not yet supported.

How to reference a secret

The id in --mount=type=secret,id=... must match how the secret is configured in Ona. For file secrets, the id is the full file path. For environment variable secrets, the id is the variable name. Use target= to control where the secret is mounted during the RUN step. The target path can be any location your build step needs — it does not have to match the id.

Example: private npm registry (file mount)

Given a file secret configured in Ona at /usr/local/secrets/npm-token:
FROM node:20
COPY package.json package-lock.json ./

RUN --mount=type=secret,id=/usr/local/secrets/npm-token,target=/tmp/npm-token \
    echo "//registry.npmjs.org/:_authToken=$(cat /tmp/npm-token)" > .npmrc && \
    npm ci && \
    rm -f .npmrc
The .npmrc file is written, used for npm ci, and removed within the same RUN step so the token is not persisted in the image layer.

Example: private npm registry (env mount)

The env= option mounts the secret directly as an environment variable, avoiding the need to read from a file. This requires Dockerfile syntax v1.10.0+, so you must add # syntax=docker/dockerfile:1 as the very first line of your Dockerfile (before any other instructions or comments):
# syntax=docker/dockerfile:1
FROM node:20
COPY package.json package-lock.json ./

RUN --mount=type=secret,id=NPM_TOKEN,env=NPM_TOKEN \
    echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && \
    npm ci && \
    rm -f .npmrc
The # syntax=docker/dockerfile:1 directive pulls the docker/dockerfile:1 image from Docker Hub to use as the build frontend. If your environment restricts access to Docker Hub, you can mirror the image to a private registry and reference it instead:
# syntax=my-registry.example.com/docker/dockerfile:1
No changes to devcontainer.json are needed. Ona passes the secrets to the build process, and your Dockerfile controls which RUN steps can access them.

Multi-Container Development

For more complex setups, you can define multiple containers using Docker Compose. devcontainer.json:
{
	"name": "Multi-container App",
	"dockerComposeFile": "docker-compose.yml",
	"service": "app",
	"workspaceFolder": "/workspace",
	"customizations": {
		"vscode": {
			"extensions": ["ms-azuretools.vscode-docker"]
		}
	}
}
docker-compose.yml:
version: "3.8"

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ..:/workspace:cached
    network_mode: host
    command: sleep infinity

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    network_mode: host
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: app_dev
Required: Set network_mode: host on all services. Without this, services attempt to bridge networks, which can lock you out of your dev container with no way to recover except deleting the environment.

Adding Custom Features

Dev Container Features are self-contained, shareable units of installation code and configuration that let you quickly add tooling, runtimes, or libraries to your development container. You can add features to your Dev Container by adding them to the features section of your devcontainer.json file:
{
	"features": {
		"ghcr.io/devcontainers/features/docker-in-docker:2": { "moby": false },
		"ghcr.io/devcontainers/features/github-cli:1": {}
	}
}
Ona works well with many Dev Container Features, especially official ones that are designed with remote development environments in mind. Linux-based runners generally provide best compatibility with most Dev Container Features. Here’s what you should know:
  • Community-supported features might require additional testing, as they may have been developed without specific consideration for compatibility.
  • Feature behavior can vary depending on base images, other installed features, and specific configurations in your setup.

Troubleshooting

If your Dev Container fails to build:
  1. Use the “Ask Ona” button - When a devcontainer build fails, click the “Ask Ona” button in the startup accordion to get AI-powered help diagnosing and fixing the issue. Ona will analyze the error logs and suggest solutions for common problems like privileged operations, sudo commands, or image pull failures. This feature is available when Ona AI is enabled and your runner supports LLM capabilities.
  2. Check the Ona console for specific error messages
  3. Ensure image versions are correctly specified
  4. Try rebuilding in recovery mode to debug the issue

Next steps