Using Images, Dockerfiles, and Docker Compose
16 Dec 2022 - @chuxel
When creating a development container, you have a variety of different ways to customize your environment like “Features” or lifecycle scripts. However, if you are familiar with containers, you may want to use a Dockerfile or Docker Compose / Compose to customize your environment. This article will walk through how to use these formats with the Dev Container spec.
Using a Dockerfile
To keep things simple, many Dev Container Templates use container image references.
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu"
}
However, Dockerfiles are a great way to extend images, add additional native OS packages, or make minor edits to the OS image. You can reuse any Dockerfile, but let’s walk through how to create one from scratch.
First, add a file named Dockerfile
next to your devcontainer.json
. For example:
FROM mcr.microsoft.com/devcontainers/base:ubuntu
# Install the xz-utils package
RUN apt-get update && apt-get install -y xz-utils
Next, remove the image
property from devcontainer.json
(if it exists) and add the build
and dockerfile
properties instead:
{
"build": {
// Path is relative to the devcontainer.json file.
"dockerfile": "Dockerfile"
}
}
That’s it! When you start up your Dev Container, the Dockerfile will be automatically built with no additional work. See Dockerfile scenario reference for more information on other related devcontainer.json properties.
Iterating on an image that includes Dev Container metadata
Better yet, you can can use a Dockerfile as a part of authoring an image you can share with others. You can even add Dev Container settings and metadata right into the image itself. This avoids having to duplicate config and settings in multiple devcontainer.json files and keeps them in sync with your images!
See the guide on pre-building to learn more!
Using Docker Compose
Docker Compose is a great way to define a multi-container development environment. Rather than adding things like databases or redis to your Dockerfile, you can reference existing images for these services and focus your Dev Container’s content on tools and utilities you need for development.
Using an image with Docker Compose
As mentioned in the Dockerfile section, to keep things simple, many Dev Container Templates use container image references.
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu"
}
Let’s create a docker-compose.yml
file next to your devcontainer.json
that references the same image and includes a PostgreSQL database:
version: '3.8'
services:
devcontainer:
image: mcr.microsoft.com/devcontainers/base:ubuntu
volumes:
- ../..:/workspaces:cached
network_mode: service:db
command: sleep infinity
db:
image: postgres:latest
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: postgres
volumes:
postgres-data:
In this example:
../..:/workspaces:cached
mounts the workspace folder from the local source tree into the Dev Container.network_mode: service:db
puts the Dev Container on the same network as the database, so that it can access it onlocalhost
.- The
db
section uses the Postgres image with a few settings.
Next, let’s configure devcontainer.json to use it.
{
"dockerComposeFile": "docker-compose.yml",
"service": "devcontainer",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}"
}
In this example:
service
indicates which service in thedocker-compose.yml
file is the Dev Container.dockerComposeFile
indicates where to find thedocker-compose.yml
file.workspaceFolder
indicates where to mount the workspace folder. This corresponds to a sub-folder under the mount point from../..:/workspaces:cached
in thedocker-compose.yml
file.
That’s it!
Using a Dockerfile with Docker Compose
You can also combine these scenarios and use Dockerfile with Docker Compose. This time we’ll update docker-compose.yml
to reference the Dockerfile by replacing image
with a similar build
section:
version: '3.8'
services:
devcontainer:
build:
context: .
dockerfile: Dockerfile
volumes:
- ../..:/workspaces:cached
network_mode: service:db
command: sleep infinity
db:
image: postgres:latest
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: postgres
volumes:
postgres-data:
Finally, as in the Dockerfile example, you can use this same setup to create a Dev Container image that you can share with others. You can also add Dev Container settings and metadata right into the image itself.
See the guide on pre-building to learn more!