Add Development Container to a Project

For a project already configured for containerization (e.g. Dockerfile and optionally docker-compose.yml), it’s relatively easy to have VS Code use the container for development.

Over time, I’ve moved slowly to leveraging what VS Code offers in terms of integration with Docker when working with Python/Django projects:

  • Use docker compose run ... to manage my own container up/down. Use VS Code strictly as a text editor and ignore all the import errors.
  • Use the “Attach to Running Container …” option once I have a container up. This works until I shut down the container when VS Code complains. I then ignore and close VS Code. Each attachment will take time to build and initialize.

Template devcontainer.json

And NOW, I finally have time to look into their Development Container support. After some trial and error guessing the format of the devcontainer.json file, this is what I have:

.devcontainer/devcontainer.json

{
  "name": "Python Test Dev Container",
  "dockerComposeFile": "../docker-compose.yml",    // the project root
  "service": "app",              // MUST match docker-compose.yml:service.name
  "workspaceFolder": "/code",    // MUST match DockerFile:WORKDIR 
  "forwardPorts": [8000],        // Optional but should match ports used by app

  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance"
      ],
      "settings": {
          // Or whatever shell your container supports
          "terminal.integrated.shell.linux": "/bin/bash"
      }
    }
  }
}

This works with the following Dockerfile and docker-compose.yml files:

Dockerfile (excerpt)

FROM python:3.14-bookworm
...

RUN apt update && apt install -y \
    ...

...

WORKDIR /code
...
COPY . /code
docker-compose.yml (excerpt)

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./:/code
    ports:
      - "8000:8000"
    tty: true
    stdin_open: true
    environment:
      - ...

As much as I can, I push the configuration into Dockerfile or docker-compose.yml files since they will be used to build and launch the application’s container(s). Everything under .devcontainer/ serves only VS Code as far as I know.

Some documentation online says to have a copy of Dockerfile and docker-compose.yml under .devcontainer/, but doing this will either:

  • duplicate the files between the project root and .devcontainer/, or
  • break the ability to build and run container outside VS Code

This arrangement still has these points of integration where some info is duplicated (and must match):

  • devcontainer.json‘s service must match the service in docker-compose.yml (“app” in this example).
  • devcontainer.json‘s workspaceFolder must match the WORKDIR in Dockerfile and the host mount in docker-compose.yml (“/code” in this example).
  • devcontainer.json‘s forwardPorts much match the ports used by the app (8000 in this example).
    This setting is not strictly necessary; I was able to have things work after removing the forwardPorts setting from devcontainer.json. However, if this setting is used, its values should match those defined in docker-compose.yml and/or Dockerfile.

python.defaultInterpreterPath

During the process, I got a whine from VS Code about this setting:

This could be specific to the Docker image from which I built the container with (FROM python:3.14-bookworm). I shelled into the container and did a which python and found /usr/local/bin/python to be a good value to use:

That seems to make it happy.

Virtual Environment

If a virtual environment is used (e.g. .venv/ from uv or pyenv), use the value .venv/bin/python (or wherever python is found in the virtual environment) instead.

The Payoff

So what did all this get us?

Once I open up the project folder in VS Code, I can start a container (building it as necessary) from which to start editing files and/or fire up terminals to run tools (e.g. python manage.py ...). This can be done by:

  • Press F1. This will bring up a list of choices in the center top menu.
  • Select “Dev Containers: Reopen in Container” from the menu.
    NOTE: if done working, choose “Dev Containers: Reopen Folder Locally” to stop the container.

Now, all the dependencies are “known” by VS Code, so imports and code navigations are easier. Just make sure python.defaultInterpreterPath setting in VS Code is set correctly.

VS Code Offers to Help

Once that is set up, loading up the IDE and opening the project’s folder will bring up this notification:

Clicking “Reopening in Container” is identical to F1 > Dev Containers: Reopen in Container described above.