und produktiv nutzen
Ein Devcontainer verlagert die komplette Entwicklungsumgebung in einen Container, sodass jeder Entwickler exakt dieselbe PHP-Version, dieselben Extensions und dieselben Tools nutzt, unabhängig vom eigenen Rechner. Statt stundenlanger Onboarding-Dokumentation genügt ein Klick auf "Reopen in Container".
Inhaltsverzeichnis
- 1. Was ein Devcontainer wirklich löst
- 2. Grundstruktur der devcontainer.json
- 3. Ein eigenes Dockerfile für den Devcontainer bauen
- 4. Extensions und Editor-Einstellungen automatisch mitliefern
- 5. Non-Root-User und Port-Forwarding richtig konfigurieren
- 6. Devcontainer mit Docker Compose für Multi-Service-Setups
- 7. Devcontainer Features statt eigener Dockerfile-Layer
- 8. Debugging und Xdebug im Devcontainer einrichten
- 9. Devcontainer im Vergleich zu anderen Setup-Ansätzen
- 10. Zusammenfassung
- 11. FAQ
1. Was ein Devcontainer wirklich löst
Ein Devcontainer ist eine standardisierte Beschreibung einer vollständigen Entwicklungsumgebung, die VS Code über die Dev Containers Extension direkt in einem laufenden Container öffnet. Statt PHP, Composer, Node und alle Extensions lokal zu installieren, definiert eine einzige Konfigurationsdatei, welches Basisimage genutzt wird, welche Tools zusätzlich installiert werden und welche Editor-Erweiterungen automatisch aktiv sind. Der Effekt: ein neuer Kollege klont das Repository, öffnet es in VS Code, klickt auf "Reopen in Container" und arbeitet wenige Minuten später in einer exakt identischen Umgebung wie der Rest des Teams.
Das eigentliche Problem, das ein Devcontainer löst, ist die Divergenz lokaler Umgebungen über die Zeit. Ohne Devcontainer installiert jeder Entwickler PHP, Xdebug und Node eigenständig, mit leicht unterschiedlichen Versionen, unterschiedlichen php.ini-Einstellungen und irgendwann kleinen, schwer reproduzierbaren Bugs, die "bei mir funktioniert es aber". Ein Devcontainer macht die Umgebung selbst zu einem versionierten Artefakt im Repository, das mit jedem Commit mitgeht und für jeden identisch ist.
Dieser Artikel zeigt den vollständigen Weg von der ersten devcontainer.json bis zum produktiven Multi-Service-Setup mit PHP, MySQL und Redis, inklusive Debugging-Konfiguration für Xdebug innerhalb des Devcontainer-Setups.
2. Grundstruktur der devcontainer.json
Jeder Devcontainer beginnt mit einer Datei unter .devcontainer/devcontainer.json im Projekt-Root. Diese Datei ist technisch gesehen JSON mit Kommentarunterstützung (JSONC) und beschreibt, welches Image oder welches Dockerfile als Basis dient, welche Ports weitergeleitet werden, welche Umgebungsvariablen gesetzt sind und welche Lifecycle-Hooks nach dem Erstellen des Containers ausgeführt werden. VS Code liest diese Datei automatisch, sobald die Dev Containers Extension installiert ist und ein passendes Projekt geöffnet wird.
{
"name": "mironsoft-shop-dev",
"dockerFile": "Dockerfile",
"context": "..",
"forwardPorts": [8080, 3306, 6379],
"portsAttributes": {
"8080": { "label": "Web", "onAutoForward": "notify" }
},
"remoteUser": "developer",
"postCreateCommand": "composer install && npm install",
"customizations": {
"vscode": {
"extensions": [
"bmewburn.vscode-intelephense-client",
"xdebug.php-debug",
"esbenp.prettier-vscode"
]
}
}
}
Der Schlüssel postCreateCommand ist besonders wichtig für einen produktiven Devcontainer: er wird genau einmal nach dem ersten Erstellen des Containers ausgeführt und eignet sich damit ideal für composer install, npm install oder das Einspielen einer Datenbank-Fixture. Der Schlüssel remoteUser legt fest, mit welchem Benutzer VS Code im Container arbeitet, was direkten Einfluss auf Dateirechte zwischen Host und Container hat.
3. Ein eigenes Dockerfile für den Devcontainer bauen
Für PHP-Projekte reicht ein generisches Basisimage selten aus, weil Extensions wie pdo_mysql, intl oder opcache projektspezifisch installiert werden müssen. Ein eigenes Dockerfile im .devcontainer-Verzeichnis erlaubt volle Kontrolle über die PHP-Version, installierte Extensions und zusätzliche CLI-Tools wie ShellCheck oder den PHP CS Fixer, die im Alltag der Entwicklung gebraucht werden, aber nicht im Produktionsimage landen sollen.
# .devcontainer/Dockerfile — development-only image, not used in production
FROM php:8.4-fpm
RUN apt-get update && apt-get install -y \
git unzip libzip-dev libicu-dev \
&& docker-php-ext-install pdo_mysql intl opcache zip \
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
# Composer for dependency management
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# Non-root user matching the host UID to avoid file permission issues
ARG USERNAME=developer
ARG USER_UID=1000
RUN useradd -m -u ${USER_UID} -s /bin/bash ${USERNAME}
USER ${USERNAME}
WORKDIR /workspace
Wichtig für den Devcontainer-Alltag: dieses Dockerfile ist bewusst vom Produktions-Dockerfile getrennt. Entwicklungstools wie Xdebug oder Git gehören nicht in ein Produktionsimage, sollen aber im Devcontainer selbstverständlich verfügbar sein. Die Trennung verhindert, dass Entwicklungsabhängigkeiten versehentlich mit in ein Deployment wandern.
4. Extensions und Editor-Einstellungen automatisch mitliefern
Eines der unterschätzten Features eines Devcontainer-Setups ist die automatische Installation von VS-Code-Extensions direkt im Container. Über den Schlüssel customizations.vscode.extensions in der devcontainer.json installiert VS Code beim ersten Start automatisch alle gelisteten Extensions innerhalb des Containers, ohne dass ein Entwickler sie manuell suchen und installieren muss. Das reduziert Onboarding-Reibung erheblich, weil PHP-Intelephense, Xdebug-Integration und Linter-Extensions sofort einsatzbereit sind.
Zusätzlich lassen sich projektspezifische Editor-Einstellungen über customizations.vscode.settings direkt mitgeben, etwa die Formatierungsregel für PHP-Dateien oder das bevorzugte Tabulatorverhalten. Diese Einstellungen gelten nur innerhalb des Devcontainer-Kontexts und überschreiben keine globalen VS-Code-Einstellungen auf dem Host, was Konflikte zwischen privaten Präferenzen und Projektstandards vermeidet.
5. Non-Root-User und Port-Forwarding richtig konfigurieren
Ein häufiger Stolperstein bei einem neuen Devcontainer: Dateien, die im Container erzeugt werden, gehören plötzlich root, weil der Container standardmäßig als root läuft. Das führt auf dem Host zu Berechtigungsproblemen, sobald Entwickler versuchen, dieselben Dateien außerhalb des Containers zu bearbeiten. Die Lösung ist ein dedizierter Non-Root-User im Dockerfile, dessen UID exakt der UID des Host-Nutzers entspricht, kombiniert mit dem remoteUser-Schlüssel in der devcontainer.json.
Port-Forwarding ist der zweite wichtige Baustein: der Schlüssel forwardPorts sorgt dafür, dass VS Code Ports aus dem Container automatisch auf den Host durchreicht, ganz ohne manuelle -p-Flags. Für einen Devcontainer mit Webserver, Datenbank und Redis lassen sich mehrere Ports gleichzeitig weiterleiten, mit individuellen Labels und Verhalten über portsAttributes, etwa eine automatische Browser-Vorschau für den Webserver-Port.
6. Devcontainer mit Docker Compose für Multi-Service-Setups
Sobald ein Projekt mehr als einen Container braucht, etwa PHP-FPM, MySQL und Redis gemeinsam, wird ein reines Dockerfile zu unflexibel. Für diesen Fall unterstützt der Devcontainer-Standard direkt Docker Compose: statt dockerFile referenziert die devcontainer.json eine docker-compose.yml, und ein zusätzlicher Schlüssel service legt fest, in welchem Service VS Code sich öffnet.
{
"name": "mironsoft-shop-dev",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"shutdownAction": "stopCompose"
}
# .devcontainer/docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ../..:/workspace:cached
command: sleep infinity
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: shop_dev
volumes:
- db_data:/var/lib/mysql
redis:
image: redis:7.4-alpine
volumes:
db_data:
Der Befehl sleep infinity im app-Service ist ein bewusstes Muster: der Container soll nicht wie in Produktion einen Webserver starten, sondern schlicht am Leben bleiben, während VS Code über eine Remote-Shell darin arbeitet. Der eigentliche Webserver oder PHP-FPM-Prozess wird dann bei Bedarf manuell oder über ein separates postStartCommand gestartet, was dem Devcontainer mehr Kontrolle über den Lebenszyklus einzelner Prozesse gibt.
7. Devcontainer Features statt eigener Dockerfile-Layer
Devcontainer Features sind wiederverwendbare, versionierte Bausteine, die häufig benötigte Tools wie Git, GitHub CLI oder Node.js zu einem bestehenden Image hinzufügen, ohne dass ein eigenes Dockerfile diese Logik selbst pflegen muss. Statt in jedem Projekt erneut apt-get install git zu schreiben, referenziert die devcontainer.json ein offizielles Feature, das von der Community gepflegt wird und automatisch aktuelle Best Practices für Installation und Konfiguration mitbringt.
{
"name": "mironsoft-shop-dev",
"dockerFile": "Dockerfile",
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "20" },
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": true,
"configureZshAsDefaultShell": true
}
}
}
Der Vorteil von Features gegenüber manuellen Dockerfile-Layern: sie werden unabhängig vom Basisimage gepflegt und aktualisiert, wodurch ein Devcontainer-Setup insgesamt wartungsärmer bleibt. Ein Team, das node und Git über Features statt über eigene RUN-Zeilen einbindet, muss bei Sicherheitsupdates nur die Feature-Version anheben, statt das komplette Dockerfile durchzugehen.
8. Debugging und Xdebug im Devcontainer einrichten
Debugging ist der Bereich, in dem ein Devcontainer seinen größten praktischen Nutzen zeigt, weil Xdebug-Konfiguration normalerweise zu den fehleranfälligsten Teilen eines lokalen PHP-Setups gehört. Da Xdebug bereits im Dockerfile installiert ist, muss nur noch die php.ini-Konfiguration für den Client-Host korrekt gesetzt und der passende VS-Code-Launch-Konfigurationseintrag hinterlegt werden.
; .devcontainer/xdebug.ini — mounted into the container
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.idekey=VSCODE
Auf der VS-Code-Seite genügt eine passende launch.json mit dem Typ php und Port 9003, kombiniert mit einem Path-Mapping zwischen dem Container-Pfad /workspace und dem lokalen Projektpfad. Da der komplette Devcontainer bereits im Repository versioniert ist, funktioniert Debugging bei jedem Teammitglied identisch, ohne individuelle Xdebug-Fehlersuche pro Rechner.
9. Devcontainer im Vergleich zu anderen Setup-Ansätzen
Devcontainer sind nicht die einzige Möglichkeit, eine lokale Entwicklungsumgebung zu standardisieren, aber sie bieten die engste Integration mit dem Editor selbst.
| Ansatz | Editor-Integration | Onboarding-Aufwand | Reproduzierbarkeit |
|---|---|---|---|
| Lokale Installation | Keine besondere Integration | Hoch, viele manuelle Schritte | Niedrig, driftet mit der Zeit |
| Plain Docker Compose | Manuelles Attach nötig | Mittel | Hoch |
| Devcontainer | Nativ in VS Code | Niedrig, ein Klick | Hoch |
| Virtuelle Maschine | Keine | Hoch, großer Download | Mittel bis hoch |
Der klare Vorteil eines Devcontainer-Setups liegt in der direkten Editor-Integration: Extensions, Debugging und Terminal fühlen sich exakt so an wie eine lokale Installation, laufen aber vollständig isoliert im Container. Plain Docker Compose ohne Devcontainer-Integration bietet dieselbe Reproduzierbarkeit, verlangt aber manuelles Attachen des Editors an den laufenden Container.
Mironsoft
Devcontainer-Setup, Onboarding-Automatisierung und PHP-Entwicklungsumgebungen
Neue Entwickler in Minuten produktiv machen?
Wir bauen Devcontainer-Konfigurationen für eure PHP- und Node-Projekte, inklusive Xdebug, Multi-Service-Compose-Setups und automatischer Extension-Installation, damit Onboarding zum Klick statt zum halben Tag wird.
Devcontainer-Setup
devcontainer.json, Dockerfile und Compose-Integration für euer Projekt
Debugging-Integration
Xdebug und Launch-Konfiguration für das gesamte Team einheitlich einrichten
Onboarding-Doku
Kurzanleitung für neue Teammitglieder auf Basis des Devcontainer-Setups
10. Zusammenfassung
Ein Devcontainer ist mehr als ein weiteres Docker-Setup, er ist ein versioniertes, im Repository mitgeführtes Vertragswerk darüber, wie ein Projekt entwickelt wird. Die devcontainer.json beschreibt Basisimage, Ports, Umgebungsvariablen und Extensions in einer einzigen Datei, ein eigenes Dockerfile bringt projektspezifische PHP-Extensions mit, und Devcontainer Features reduzieren Wartungsaufwand für häufig benötigte Tools wie Git oder Node.
Für Multi-Service-Projekte mit Datenbank und Cache integriert sich der Devcontainer-Standard nahtlos mit Docker Compose, während Debugging über Xdebug dank versionierter Konfiguration für jedes Teammitglied identisch funktioniert. Wer Onboarding-Zeit reduzieren und Umgebungsdrift zwischen Entwicklerrechnern vermeiden will, findet im Devcontainer-Ansatz die derzeit engste Integration zwischen Editor und Container.
Devcontainer für VS Code — Das Wichtigste auf einen Blick
devcontainer.json
Zentrale Konfigurationsdatei für Basisimage, Ports, Umgebungsvariablen, Extensions und Lifecycle-Hooks.
Multi-Service-Setups
dockerComposeFile plus service-Schlüssel bindet PHP, MySQL und Redis in ein gemeinsames Devcontainer-Setup ein.
Features
Wiederverwendbare, community-gepflegte Bausteine statt manueller Dockerfile-Layer für Git, Node und CLI-Tools.
Debugging
Xdebug-Konfiguration und VS-Code-Launch-Datei im Repository versioniert, funktioniert bei jedem Teammitglied identisch.