DEV Community

Cover image for Dev Containers - Part 5: Multiple Projects & Shared Container Configuration
graezykev
graezykev

Posted on

Dev Containers - Part 5: Multiple Projects & Shared Container Configuration

Welcome to the fifth guide in the Dev Container series:

To get started, you can clone my demo project using the following command:

git clone -b part-5-shared-configure-for-multiple-projects https://github.com/graezykev/dev-container.git
Enter fullscreen mode Exit fullscreen mode

Introduction

In Part 3, we learned about using Docker Compose in Dev Containers to build containers for Node.js applications and databases.

Currently, you can only connect to one container per Visual Studio Code window. But what if you have multiple projects using different tech stacks like Node.js, Python, Go, etc., and need to create Dev Containers for each?

One option is to place a .devcontainer folder under each project:

.
└── path
 └── to
    ├── project-a-node-js
    │   └── .devcontainer
    │       ├── docker-compose.yml
    │       ├── ...
    │       └── devcontainer.json
    ├── project-b-node-js
    │   └── .devcontainer
    │       ├── ...
    │       └── devcontainer.json
    ├── project-c-python
    │   └── .devcontainer
    │       ├── ...
    │       └── devcontainer.json
    ├── project-d-go-lang
    │   └── .devcontainer
    │       ├── ...
    │       └── devcontainer.json
    └── project-...
Enter fullscreen mode Exit fullscreen mode

If these applications need to share the same database, you must ensure they all use the same database container in their docker-compose.yml and the same volume:

services:

  app-name-...
    ...

  postgres:
    image: postgres:latest
    ...

...

volumes:
  postgres-data:
Enter fullscreen mode Exit fullscreen mode

However, this can result in overlapping configurations across multiple projects, making maintenance tedious. A better approach is to share a common docker-compose.yml:

.
└── path
 └── to
  └── dev-container
      │
      ├── .devcontainer
      │   │
      │   ├── .env
      │   ├── docker-compose.yml
      │   ├── ...
      │   │
      │   ├── project-a-node-js
      │   │   └── devcontainer.json
      │   │
      │   ├── project-b-node-js
      │   │   └── devcontainer.json
      │   │
      │   ├── project-c-python
      │   │   └── devcontainer.json
      │   │
      │   ├── project-d-go-lang
      │   │   └── devcontainer.json
      │   │
      │   └── project-e-...
      │       └── devcontainer.json
      │
      ├── project-a-node-js
      │       └── index.js
      │
      ├── project-b-node-js
      │
      ├── project-c-python
      │       └── hello.py
      │
      ├── project-d-go-lang
      └── project-e-...
Enter fullscreen mode Exit fullscreen mode

All projects and the .devcontainer folder share a common root-level folder, with each project having its own configuration folder under .devcontainer.

This setup allows you to define multiple Dev Containers (and a container for the database) in a common docker-compose.yml, and create a devcontainer.json for each project to reference the shared docker-compose.yml. This approach also helps manage each project's features and lifecycle scripts, avoiding configuration conflicts.

Common Docker Compose File

First, create a common docker-compose.yml inside the root-level .devcontainer:

services:
  project-a-node-js:
    image: graezykev/dev-container-base-image:latest
    volumes:
 - ..:/workspaces:cached
    ports:
 - 8001:8000
    depends_on:
 - postgres
    command: /bin/zsh -c "while sleep 1000; do :; done"

  project-b-node-js:
    ...
    volumes:
 - ..:/workspaces:cached
    ports:
 - 8002:8000

  project-c-python:
    ...

  project-d-go-lang:
    ...

  project-e-...

  postgres:
    ...

volumes:
  postgres-data:  
Enter fullscreen mode Exit fullscreen mode

See the complete file in my demo.

All projects share the same database container postgres.

We have learned most of the concepts in Part 3 but there are a few things we need to pay attention to.

Ports

Notice the port mappings: 8001:8000, 8002:8000, etc. Each project uses port 8000 within its own Dev Container, mapped to different ports on the host machine. This setup avoids port conflicts and allows access to each project's server via distinct ports (e.g., 8001, 8002, etc.).

See demo preveiw below.

Volumes & Workspace

Using ..:/workspaces for the volumes sections mounts the entire root-level folder (dev-container) on the host machine to /workspaces in the containers.

In each devcontainer.json, specify the project folder within the workspace:

"workspaceFolder": "/workspaces/project-b-node-js"
Enter fullscreen mode Exit fullscreen mode

set workspaceFolder for the right dev container

Service

In each devcontainer.json, reference the Docker Compose file docker-compose.yml and specify the service name:

{
  "name": "Dev Container",
  "dockerComposeFile": [
    "../docker-compose.yml"
  ],
  "service": "project-a-node-js",
  "shutdownAction": "none",
  "workspaceFolder": "/workspaces/project-a-node-js"
}
Enter fullscreen mode Exit fullscreen mode
{
  "service": "project-b-node-js",
  "workspaceFolder": "/workspaces/project-b-node-js"
}
Enter fullscreen mode Exit fullscreen mode
{
  "service": "project-c-python",
  "workspaceFolder": "/workspaces/project-c-python"
}
Enter fullscreen mode Exit fullscreen mode

The "shutdownAction": "none" option will leave the containers running when VS Code closes -- which prevents you from accidentally shutting down both containers by closing one window (or switching containers).

Build and Switch Dev Containers

In VS Code, open the root-level folder (dev-container in my demo). Run Dev Containers: Reopen in Container from the Command Palette and select the project to build.

choose dev container to build

This triggers the Dev Container build for the selected project.

To switch between projects, use Dev Containers: Switch Container from the Command Palette and select the desired project.

After each Dev Container is built, we can use this Switch Container command to switch between projects, the current VS Code window will reload each time and connect to the selected Dev Container.

Demo Preview

In my demo, I have three projects: two Node.js projects and one Python project, each starts an HTTP server with a web page.

When visited, the projects write "visiting records" to the shared database and display all records on the page.

preview

And remember the port mapping we mentioned before?

visiting records

Top comments (0)