1

I have an existing Django project using docker compose and I am trying to add devcontainer support. I have it mostly working except there is still one thing that is bothering me.

In my docker-compose.yml file, I have a service defined called web. I want to expand the docker image created for the web service to add more dev features. I have created the .devcontainer directory with a devcontainer.json file. I also have a docker-compose.yml file in .devcontainer which defines the dev service. I have a Dockerfile in .devcontainer that I want to extend from the web image.

The problem I am running into is when the devcontainer system in vscode tries to build the containers, the web container doesn't exist so building the dev container fails. I have to manually build the web container first so the image exists, and then the dev container build will work.

This is my .devcontainer/devcontainer.json file.

{
    "name": "Existing Docker Compose (Extend)",
    // Update the 'dockerComposeFile' list if you have more compose files or use different names.
    // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
    "dockerComposeFile": [
        "../docker-compose.yml",
        "../docker-compose-development.yml",
        "docker-compose.yml"
    ],
    // The 'service' property is the name of the service for the container that VS Code should
    // use. Update this value and .devcontainer/docker-compose.yml to the real service name.
    "service": "dev",
    // The optional 'workspaceFolder' property is the path VS Code should open by default when
    // connected. This is typically a file mount in .devcontainer/docker-compose.yml
    "workspaceFolder": "/workspace",
    // Features to add to the dev container. More info: https://containers.dev/features.
    // "features": {},
    // Use 'forwardPorts' to make a list of ports inside the container available locally.
    // "forwardPorts": [],
    // Uncomment the next line if you want start specific services in your Docker Compose config.
    // "runServices": [],
    // Uncomment the next line if you want to keep your containers running after VS Code shuts down.
    // "shutdownAction": "none",
    // Uncomment the next line to run commands after the container is created.
    // "postCreateCommand": "bash pip install pre-commit"
    // Configure tool-specific properties.
    // "customizations": {},
    // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
    "remoteUser": "vscode",
    "postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder} && cd sas_applications && poetry install && cd ..",
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-vscode.azure-repos",
                "vscodevim.vim",
                "ms-python.python",
                "ms-python.isort",
                "ms-python.black-formatter"
            ]
        }
    }
}

and my .devcontainer/docker-compose.yml file

services:
  # Update this to the name of the service you want to work with in your docker-compose.yml file
  dev:
    # Uncomment if you want to override the service's Dockerfile to one in the .devcontainer
    # folder. Note that the path of the Dockerfile and context is relative to the *primary*
    # docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
    # array). The sample below assumes your primary file is in the root of your project.
    #
    build:
      context: .
      dockerfile: .devcontainer/Dockerfile
    # Overrides default command so things don't shut down after the process ends.
    entrypoint: []
    command: /bin/sh -c "while sleep 1000; do :; done"

and .devcontainer/Dockerfile

FROM web
ARG UID=1000
ARG GID=1000
RUN apt install -y pipx zsh
RUN groupadd --gid "${GID}" vscode && useradd -u "${UID}" -g "${GID}" -s /usr/bin/zsh -m vscode
USER vscode
RUN sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
RUN sed -i '/plugins=/ s/=.*/=\(git python\)/' ~/.zshrc
RUN pipx install invoke && pipx ensurepath
WORKDIR /workspace/sas_applications
CMD ["sleep", "infinity"]

I have looked into multiple options but can't come up with a solution. I would prefer not duplicating the web dockerfile in the dev dockerfile. I would also prefer not to make the developer run a manual docker-compose build step.

I thought about trying to define the dev service in the base docker-compose.yml file where the web service is defined and make use of the profile feature. However, I don't know how to tell vscode devcontainers to add that profile argument to the build command.

Thanks in advance.

1 Answer 1

1

After more research, I have found a decent solution. This solution makes use of multi-stage builds in Docker. This stackoverflow answer gave me the clue that got me pointed in the right direction.

The first change was to add multi-stage builds to the existing Dockerfile.

FROM python:3.11 as base
# Do the original image build instructions

FROM base as dev
# Do the build steps needed to add any 
#  development tools or configuration

Then, in the original docker-compose.yml file, set the build target to be the base image.

services:
  web:
    build:
     ...
     target: base
    ...

Then, in the .devcontainer/docker-compose.yml file, set the build target to be the dev image.

services:
  web:
    build:
     ...
     target: dev
    ...

Now, when building the images, you can specify which target to build just by changing the docker-compose files included at the command line. To build for deployment, use docker compose -f docker-compose.yml.

{
    "name": "Existing Docker Compose (Extend)",
    // Update the 'dockerComposeFile' list if you have more compose files or use different names.
    // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
    "dockerComposeFile": [
        "../docker-compose.yml",
        "docker-compose.yml"
    ],
    ...

The .devcontainer/devcontainer.json file will specify to include both docker compose files. vscode will now build the dev container which includes the additional development tools and configuration.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.