Aller au contenu

Cas avances

Environnements multi-stack, devcontainer CLI pour la CI, templates custom et cas d'usage speciaux.


Multi-stack

Un projet fullstack avec frontend, backend et base de données :

.devcontainer/
├── devcontainer.json
├── docker-compose.yml
├── Dockerfile.app
└── post-create.sh
# .devcontainer/docker-compose.yml
services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile.app
    volumes:
      - ..:/workspace:cached
      - node-modules:/workspace/frontend/node_modules
      - go-cache:/home/vscode/go
    command: sleep infinity
    depends_on:
      - db
      - redis
    environment:
      DATABASE_URL: postgres://dev:dev@db:5432/myapp
      REDIS_URL: redis://redis:6379

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: dev
      POSTGRES_PASSWORD: dev
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  pgdata:
  node-modules:
  go-cache:
// .devcontainer/devcontainer.json
{
  "name": "Full Stack",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "features": {
    "ghcr.io/devcontainers/features/node:1": { "version": "20" },
    "ghcr.io/devcontainers/features/go:1": { "version": "1.22" }
  },
  "forwardPorts": [3000, 8080, 5432],
  "portsAttributes": {
    "3000": { "label": "Frontend (React)" },
    "8080": { "label": "API (Go)" },
    "5432": { "label": "PostgreSQL" }
  },
  "postCreateCommand": "bash .devcontainer/post-create.sh"
}
#!/bin/bash
# .devcontainer/post-create.sh
set -e

echo "=== Frontend ==="
cd /workspace/frontend && npm install

echo "=== Backend ==="
cd /workspace/backend && go mod download

echo "=== Database ==="
cd /workspace && go run cmd/migrate/main.go up

echo "=== Pret ==="

devcontainer CLI

La CLI permet d'utiliser les devcontainers en dehors de VS Code — notamment en CI :

# Installation
npm install -g @devcontainers/cli

# Build le devcontainer
devcontainer build --workspace-folder .

# Executer une commande dans le devcontainer
devcontainer exec --workspace-folder . npm test

# Lancer le devcontainer (mode interactif)
devcontainer up --workspace-folder .

Usage en CI (Gitea Actions / GitHub Actions)

# .gitea/workflows/ci.yml
name: CI
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build devcontainer
        uses: devcontainers/ci@v0.3
        with:
          runCmd: |
            npm install
            npm test
            npm run lint

L'environnement de CI est identique a l'environnement de dev — plus de "ca passe en local mais pas en CI".

Templates custom

Créer un template réutilisable pour l'équipe :

devcontainer-templates/
├── node-fullstack/
│   ├── .devcontainer/
│   │   ├── devcontainer.json
│   │   ├── Dockerfile
│   │   └── post-create.sh
│   └── devcontainer-template.json
├── python-api/
│   └── ...
└── go-microservice/
    └── ...
// devcontainer-template.json
{
  "id": "node-fullstack",
  "version": "1.0.0",
  "name": "Node.js Full Stack",
  "description": "Node.js avec React, Express et PostgreSQL",
  "options": {
    "nodeVersion": {
      "type": "string",
      "description": "Version de Node.js",
      "default": "20",
      "proposals": ["18", "20", "22"]
    }
  }
}

Utiliser un template : Ctrl+Shift+P → "Dev Containers: Add Dev Container Configuration Files" → choisir le template.

FPGA et embarque dans un conteneur

Pour les projets IoT et embarque (voir IoT), un devcontainer peut inclure les toolchains :

{
  "name": "Embedded Dev",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "features": {
    "ghcr.io/devcontainers/features/python:1": { "version": "3.12" }
  },
  "postCreateCommand": "pip install platformio esptool",
  "runArgs": [
    "--device=/dev/ttyUSB0"
  ],
  "mounts": [
    "source=/dev/bus/usb,target=/dev/bus/usb,type=bind"
  ]
}

Accès matériel

L'accès aux périphériques USB depuis un conteneur necessite --device ou --privileged. Cela ne fonctionne que sur Linux natif (pas sur macOS/Windows ou le conteneur tourne dans une VM).