Blog

Wie Sie einen Devcontainer für Ihr Python-Projekt erstellen

Jeroen Overschie

Aktualisiert Oktober 16, 2025
13 Minuten

Komplizierte Umgebung. Festlegen von Versionen. Die Hardware ist bei jedem anders. Die Projektumgebung ändert sich mit der Zeit.

Stellen Sie sich das folgende Szenario vor.

Ihr Unternehmen verwendet Apache Spark, um Daten zu verarbeiten, und Ihr Team hat pyspark in einem Python-Projekt eingerichtet. Die Codebasis basiert auf einer bestimmten Python-Version, die eine bestimmte Java-Installation verwendet, und einer dazugehörigen pyspark-Version, die mit der ersteren zusammenarbeitet. Um ein neues Mitglied an Bord zu holen, müssen Sie eine Liste von Anweisungen übergeben, die der Entwickler sorgfältig befolgen muss, damit seine Einrichtung funktioniert. Aber nicht jeder kann dies auf demselben Laptop ausführen: unterschiedliche Hardware und unterschiedliche Betriebssysteme. Das wird eine Herausforderung.

Aber die Einrichtung ist eine einmalige Sache, richtig? Führen Sie die Einrichtung nur einmal durch und alles ist in Ordnung. Nicht ganz. Ihre Code-Umgebung wird sich im Laufe der Zeit ändern: Ihr Team wird während der Entwicklung des Projekts wahrscheinlich Pakete installieren, aktualisieren oder entfernen. Das bedeutet, dass ein Entwickler, der eine neue Funktion erstellt und dafür seine eigene Umgebung ändert, auch dafür sorgen muss, dass die anderen Teammitglieder ihre Umgebung ändern und dass die Produktionsumgebung entsprechend aktualisiert wird. So kann es leicht zu falsch abgestimmten Umgebungen kommen: zwischen den Entwicklern und zwischen Entwicklung und Produktion.

Das können wir besser machen! Anstatt anderen Entwicklern ein Einrichtungsdokument zu geben, sollten wir sicherstellen, dass wir auch formale Anweisungen erstellen, damit wir die Entwicklungsumgebung automatisch einrichten können. Mit Devcontainern können wir genau dies tun.

Mit Devcontainern können Sie Ihre IDE mit einem laufenden Docker-Container verbinden. Auf diese Weise erhalten wir die Vorteile der Reproduzierbarkeit und der Isolierung, während wir gleichzeitig eine native Entwicklungserfahrung erhalten. Dieser Ansatz bietet eine vollwertige Entwicklungsumgebung, die einen nahtlosen Wechsel und Zugriff auf Tools, Plattform und Dateisystem innerhalb des Containers ermöglicht.

Übersicht über die Verwendung von Devcontainer

Devcontainers kann uns helfen:

  • Erhalten Sie eine reproduzierbare Entwicklungsumgebung
  • ⚡️ Nehmen Sie neue Teammitglieder sofort in Ihr Projekt auf.
  • ‍ ‍ ‍ Bessere Abstimmung der Umgebungen zwischen den Teammitgliedern
  • ⏱ Wenn Sie Ihre Entwicklungsumgebung auf dem neuesten Stand und reproduzierbar halten, spart Ihr Team später bei der Produktion Zeit.

Lassen Sie uns herausfinden, wie wir einen Devcontainer für Ihr Python-Projekt einrichten können!

Erstellen Ihres ersten Devcontainers

- Schritt 1

Beachten Sie, dass sich diese Anleitung auf VSCode konzentriert. Andere IDEs wie PyCharm unterstützen die Ausführung in Docker-Containern, aber die Unterstützung ist weniger umfassend als bei VSCode.

Bei der Einrichtung des Devcontainers ist es wichtig, den Prozess der Devcontainer-Konfiguration zu verstehen, einschließlich der Erstellung und Anpassung der Devcontainer-Konfigurationsdateien.

Rekapitulieren Sie

Um es noch einmal zu sagen: Wir versuchen, eine Entwicklungsumgebung zu erstellen, die Folgendes installiert: 1) Java, 2) Python und 3) pyspark. Und zwar automatisch, d.h. innerhalb eines Dev-Container-Images.

Struktur des Projekts

Nehmen wir an, wir haben ein ganz einfaches Projekt, das wie folgt aussieht:

$ tree .
.
├── README.md
├── requirements.txt
├── requirements-dev.txt
├── sales_analysis.py
└── test_sales_analysis.py

Das heißt, wir haben ein Python-Modul mit einem dazugehörigen Test, eine Datei requirements.txt, die unsere Produktionsabhängigkeiten (pyspark) beschreibt, und eine requirements-dev.txt, die Abhängigkeiten beschreibt, die nur in der Entwicklung installiert werden sollen (pytest, black, mypy). Konfigurationsdateien wie .devcontainer/devcontainer.json spielen eine entscheidende Rolle beim Einrichten und Anpassen der Entwicklungsumgebung für verschiedene Projekte oder Teams innerhalb eines Repositorys. Lassen Sie uns nun sehen, wie wir diese Einrichtung um einen Devcontainer erweitern können.

Der Ordner .devcontainer und die Dev-Container-Konfigurationsdateien

Ihre Devcontainer-Spezifikation befindet sich im Ordner .devcontainer. Es wird zwei Hauptdateien geben:

  • devcontainer.json
  • Dockerfile

Diese Dateien stellen die Dev-Container-Funktionen bereit, bei denen es sich um in sich geschlossene, gemeinsam nutzbare Einheiten von Installationscode und Dev-Container-Konfiguration handelt. Diese Funktionen können als OCI-Artefakte veröffentlicht und gemeinsam genutzt werden und können Metadaten in vorgefertigten Images enthalten, was einen schnelleren Start des Containers und eine einfachere Konfiguration ermöglicht.

Erstellen Sie eine neue Datei namens devcontainer.json:

{
    "build": {
        "dockerfile": "Dockerfile",
        "context": ".."
    }
}

Das bedeutet: Verwenden Sie als Basis für unseren Devcontainer den Dockerfile, der sich im aktuellen Verzeichnis befindet, und bauen Sie ihn mit einem aktuellen Arbeitsverzeichnis (cwd) von ...

Wie sieht also diese Dockerfile aus?

FROM python:3.10

# Install Java
RUN apt update && 
    apt install -y sudo && 
    sudo apt install default-jdk -y

## Pip dependencies
# Upgrade pip
RUN pip install --upgrade pip
# Install production dependencies
COPY requirements.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt && 
    rm /tmp/requirements.txt
# Install development dependencies
COPY requirements-dev.txt /tmp/requirements-dev.txt
RUN pip install -r /tmp/requirements-dev.txt && 
    rm /tmp/requirements-dev.txt

Wir bauen unser Image auf python:3.10 auf, einem Debian-basierten Image. Dies ist eine der Linux-Distributionen, auf denen ein Devcontainer erstellt werden kann. Die Hauptanforderung ist, dass Node.js ausgeführt werden kann: VSCode installiert automatisch den VSCode Server auf dem Rechner. Eine ausführliche Liste der unterstützten Distributionen finden Sie unter "Fernentwicklung mit Linux".

Zusätzlich zu python:3.10 installieren wir Java und die erforderlichen Pip-Pakete.

Öffnen des Devcontainers

Der Ordner .devcontainer ist angelegt, so dass es jetzt an der Zeit ist, unseren Devcontainer zu öffnen.

Stellen Sie zunächst sicher, dass Sie die Dev Containers-Erweiterung in VSCode installiert haben (früher "Remote - Containers" genannt). Wenn Sie dann Ihr Projektarchiv erneut öffnen, sollte die Erweiterung Ihren Devcontainer bereits erkennen:

Ordner enthält eine Konfigurationsdatei für den Dev-Container

Alternativ können Sie auch die Befehlspalette öffnen(CMD + Umschalt + P) und "Dev Containers" wählen:In Container neu öffnen":

Dev-Container: Im Container wieder öffnen

Ihr VSCode ist jetzt mit dem Docker-Container verbunden:

VSCode ist jetzt mit dem Docker-Container verbunden

Was unter der Motorhaube passiert

Neben dem Starten des Docker-Images und dem Verbinden des Terminals mit dem Docker-Image erledigt VSCode noch einige weitere Dinge:

  1. VSCode Server wird auf Ihrem Devcontainer installiert. VSCode Server wird als Dienst im Container selbst installiert, damit Ihre VSCode Installation mit dem Container kommunizieren kann. Zum Beispiel, um Erweiterungen zu installieren und auszuführen.
  2. Config wird kopiert. Konfigurationen wie ~/.gitconfig und ~/.ssh/known_hosts werden an ihren jeweiligen Speicherort im Container kopiert. So können Sie Ihr Git-Repository wie gewohnt verwenden, ohne sich erneut authentifizieren zu müssen.
  3. Dateisystem mounten. VSCode kümmert sich automatisch um das Mounten: 1) Den Ordner, von dem aus Sie Devcontainer ausführen und 2) Ihren VSCode-Arbeitsbereich-Ordner.

Öffnen Sie Ihr Repo direkt in einem Devcontainer

Da alle Anweisungen zur Konfiguration Ihrer Entwicklungsumgebung jetzt in einer Dockerdatei definiert sind, können Benutzer Ihren Devcontainer mit nur einer Taste öffnen:

python-devcontainer-template

Öffnen in Remote - Containern

Ist das nicht cool? So können Sie eine Schaltfläche zu Ihrem Repo hinzufügen:

[
    ![Open in Remote - Containers](
        https://xebia.com/media/2025/04/v1.svg    )
](
    https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url= https://github.com/godatadriven/python-devcontainer-template
)

Ändern Sie einfach die GitHub URL ✓.

Wir sehen also, dass die Erstellung eines Devcontainers die Lesbarkeit unserer README erheblich verbessern kann. Welche Art von README hätten Sie denn gerne?

Manuelle InstallationVerwendung eines Devcontainers

Erweiterung des Devcontainers

Wir haben einen funktionierenden Devcontainer gebaut, was großartig ist! Aber es fehlen noch ein paar Dinge. Das wollen wir noch:

  • Installieren Sie einen Nicht-Root-Benutzer für zusätzliche Sicherheit und gute Praktiken
  • Übergeben Sie benutzerdefinierte VSCode-Einstellungen und installieren Sie standardmäßig Erweiterungen
  • Sie können auf die Spark-Benutzeroberfläche zugreifen (Port 4040).
  • Kontinuierliche Integration (CI) im Devcontainer ausführen

Lassen Sie uns sehen, wie.

Installieren eines Nicht-Root-Benutzers

Wenn Sie pip install ein neues Paket erstellen, wird die folgende Meldung angezeigt:

Die Warnmeldung:

Es wird in der Tat nicht empfohlen, als Root-Benutzer zu entwickeln. Es gilt als gute Praxis, einen anderen Benutzer mit weniger Rechten zu erstellen, der in der Produktion eingesetzt wird. Lassen Sie uns also fortfahren und einen Benutzer für dieses Szenario anlegen.

# Add non-root user
ARG USERNAME=nonroot
RUN groupadd --gid 1000 $USERNAME && 
    useradd --uid 1000 --gid 1000 -m $USERNAME
## Make sure to reflect new user in PATH
ENV PATH="/home/${USERNAME}/.local/bin:${PATH}"
USER $USERNAME

Fügen Sie die folgende Eigenschaft zu devcontainer.json hinzu:

    "remoteUser": "nonroot"

Das ist großartig! Wenn wir jetzt den Container starten, sollten wir uns als der Benutzer nonroot verbinden.

Übergabe von benutzerdefinierten VSCode-Einstellungen

Unser Devcontainer ist immer noch ein wenig fade, ohne Erweiterungen und Einstellungen. Abgesehen von den benutzerdefinierten Erweiterungen, die ein Benutzer vielleicht installieren möchte, können wir einige bereits standardmäßig für ihn installieren. Wir können solche Einstellungen in customizations.vscode definieren:

     "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python"
            ],
            "settings": {
                "python.testing.pytestArgs": [
                    "."
                ],
                "python.testing.unittestEnabled": false,
                "python.testing.pytestEnabled": true,
                "python.formatting.provider": "black",
                "python.linting.mypyEnabled": true,
                "python.linting.enabled": true
            }
        }
    }

Die definierten Erweiterungen werden immer im Devcontainer installiert. Die definierten Einstellungen stellen jedoch nur eine Vorgabe für den Benutzer dar und können immer noch durch andere Einstellungsbereiche wie Benutzereinstellungen, Remote-Einstellungen oder Arbeitsbereichseinstellungen überschrieben werden.

Zugriff auf die Spark-Benutzeroberfläche

Da wir pyspark verwenden, möchten wir auf die Spark-Benutzeroberfläche zugreifen können. Wenn wir eine Spark-Sitzung starten, fragt VSCode, ob Sie den spezifischen Port weiterleiten möchten. Da wir bereits wissen, dass es sich um Spark UI handelt, können wir dies automatisch tun:

    "portsAttributes": {
        "4040": {
            "label": "SparkUI",
            "onAutoForward": "notify"
        }
    },

    "forwardPorts": [
        4040
    ]

Wenn wir nun unseren Code ausführen, erhalten wir eine Benachrichtigung, dass wir Spark UI im Browser öffnen können:

Spark UI im Browser öffnen

Das Ergebnis ist die Spark-Benutzeroberfläche, wie wir sie kennen:

Spark UI im Browser

Ausführen unserer CI im Devcontainer

Wäre es nicht praktisch, wenn wir unseren Devcontainer auch für die Ausführung unserer Continuous Integration (CI) Pipeline verwenden könnten? Mit Devcontainern können wir das tatsächlich tun. Ähnlich wie das Devcontainer-Image lokal mit Docker Build erstellt wird, kann dasselbe innerhalb einer CI/CD-Pipeline geschehen. Ein gut definierter Laufzeitstapel innerhalb des Containers sorgt für einen nahtlosen Wechsel der gesamten Entwicklungsumgebung und bietet Zugriff auf die erforderlichen Tools, die Plattform und das Dateisystem.

Es gibt zwei grundlegende Optionen:

  1. Erstellen Sie das Docker-Image innerhalb der CI/CD-Pipeline
  2. Das Bild vorbereiten

Um das Image vorzubilden, muss der Build-Schritt entweder regelmäßig oder immer dann ausgeführt werden, wenn sich die Docker-Definition geändert hat. Da dies eine gewisse Komplexität mit sich bringt, lassen Sie uns zunächst den Devcontainer als Teil der CI/CD-Pipeline erstellen (für die Vorerstellung des Images siehe den Abschnitt "Tolle Ressourcen"). Wir werden dazu GitHub Actions verwenden.

Verwendung von devcontainers/ci

Glücklicherweise wurde bereits eine GitHub-Aktion für uns eingerichtet, um genau das zu tun:

Erstellen und Ausführen von Entwicklungscontainern (devcontainers/ci)

Jetzt ist es ganz einfach, einen Befehl im Devcontainer zu erstellen, zu pushen und auszuführen:

name: Python app

on:
  pull_request:
  push:
    branches:
      - "**"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout (GitHub)
        uses: actions/checkout@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and run dev container task
        uses: devcontainers/ci@v0.2
        with:
          imageName: ghcr.io/${{ github.repository }}/devcontainer
          runCmd: pytest .

Das ist großartig! Immer, wenn dieser Workflow in Ihrem Hauptzweig ausgeführt wird, wird das Image in die konfigurierte Registrierung übertragen; in diesem

Fall GitHub Container Registry (GHCR).

Sehen Sie unten eine Aufzeichnung der ausgeführten GitHub-Aktion:

running-ci-in-the-devcontainer-github-actions

Fantastisch!

Die endgültige Devcontainer-Definition

Wir haben die folgenden Devcontainer-Definitionen erstellt. Erstens: devcontainer.json:

{
    "build": {
        "dockerfile": "Dockerfile",
        "context": ".."
    },

    "remoteUser": "nonroot",

    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python"
            ],
            "settings": {
                "python.testing.pytestArgs": [
                    "."
                ],
                "python.testing.unittestEnabled": false,
                "python.testing.pytestEnabled": true,
                "python.formatting.provider": "black",
                "python.linting.mypyEnabled": true,
                "python.linting.enabled": true
            }
        }
    },

    "portsAttributes": {
        "4040": {
            "label": "SparkUI",
            "onAutoForward": "notify"
        }
    },

    "forwardPorts": [
        4040
    ]
}

Und unsere Dockerfile:

FROM python:3.10

# Install Java
RUN apt update && 
    apt install -y sudo && 
    sudo apt install default-jdk -y

# Add non-root user
ARG USERNAME=nonroot
RUN groupadd --gid 1000 $USERNAME && 
    useradd --uid 1000 --gid 1000 -m $USERNAME
## Make sure to reflect new user in PATH
ENV PATH="/home/${USERNAME}/.local/bin:${PATH}"
USER $USERNAME

## Pip dependencies
# Upgrade pip
RUN pip install --upgrade pip
# Install production dependencies
COPY --chown=nonroot:1000 requirements.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt && 
    rm /tmp/requirements.txt
# Install development dependencies
COPY --chown=nonroot:1000 requirements-dev.txt /tmp/requirements-dev.txt
RUN pip install -r /tmp/requirements-dev.txt && 
    rm /tmp/requirements-dev.txt
Die vollständige Devcontainer-Implementierung und alle oben genannten Schritte finden Sie in den verschiedenen Zweigen des godatadriven/python-devcontainer-template Repo.

Architektur von Docker-Images: Drei Umgebungen

Da die KI nun eingerichtet ist, können wir dasselbe Docker-Image für zwei Zwecke wiederverwenden. Für die lokale Entwicklung und die Durchführung unserer Qualitätsprüfungen. Und wenn wir diese Anwendung in die Produktion überführen, können wir den Devcontainer so konfigurieren, dass er unser Produktions-Image als Basis verwendet und zusätzliche Abhängigkeiten installiert. Wenn wir das CI-Image so optimieren wollen, dass es so schlank wie möglich ist, können wir auch alle zusätzlichen Abhängigkeiten entfernen, die wir in der CI-Umgebung nicht benötigen, z. B. zusätzliche CLI-Tools, eine bessere Shell wie ZSH usw.

Auf diese Weise haben wir 3 verschiedene Images für unseren gesamten Lebenszyklus. Eines für die Entwicklung, eines für CI und schließlich eines für die Produktion. Dies kann folgendermaßen visualisiert werden:

drei-umgebungen-docker-images-devcontainer

Sie sehen also, dass Sie bei der Verwendung eines Devcontainers Ihr Produktions-Image wiederverwenden und darauf aufbauen können. Installieren Sie zusätzliche Tools, stellen Sie sicher, dass sie mit VSCode kommunizieren können, und schon sind Sie fertig.

Weiter gehen

Es gibt noch viele andere Ressourcen, die Sie erkunden können. Devcontainers ist gut dokumentiert und es gibt viele Beiträge darüber. Wenn Sie Lust auf mehr haben, lassen Sie uns sehen, was Sie noch tun können.

Devcontainer-Funktionen

Mit den Devcontainer-Funktionen können Sie Ihre Docker-Definition ganz einfach um gängige Ergänzungen erweitern. Einige nützliche Funktionen sind:

Devcontainer-Vorlagen

Auf der offiziellen Devcontainer-Spezifikationswebsite sind zahlreiche Vorlagen verfügbar. Gut möglich, dass (ein Teil) Ihrer Einrichtung dort zu finden ist. Ein guter Weg, um einen Vorsprung bei der Erstellung Ihres Devcontainers zu bekommen oder schnell loszulegen.

Siehe: Dev Container-Vorlagen

Verzeichnisse montieren

Die Neuauthentifizierung Ihrer CLI-Tools ist lästig. Ein Trick besteht also darin, Ihre AWS/Azure/GCP-Anmeldedaten von Ihrem lokalen Computer in Ihren Devcontainer zu mounten. Auf diese Weise werden Authentifizierungen, die in einer der beiden Umgebungen vorgenommen werden, auch in der anderen Umgebung verwendet. Sie können dies ganz einfach tun, indem Sie dies zu devcontainer.json hinzufügen:

  "mounts": [
    "source=/Users/<your_username>/.aws,target=/home/nonroot/.aws,type=bind,consistency=cached"
  ]

^ das obige Beispiel montiert Ihre AWS-Anmeldedaten, aber der Prozess sollte für andere Cloud-Anbieter (GCP / Azure) ähnlich sein.

Hervorragende Ressourcen

Schlusswort

Mit Devcontainern können Sie Ihre IDE mit einem laufenden Docker-Container verbinden und so eine native Entwicklungserfahrung mit den Vorteilen der Reproduzierbarkeit und Isolierung ermöglichen. Dies erleichtert die Einbindung neuer Mitarbeiter und die Angleichung der Entwicklungsumgebungen zwischen den Teammitgliedern. Devcontainer werden für VSCode sehr gut unterstützt, werden aber jetzt in einer offenen Spezifikation standardisiert. Auch wenn es wahrscheinlich noch eine Weile dauern wird, bis eine breite Akzeptanz erreicht ist, ist die Spezifikation ein guter Kandidat für die Standardisierung von Devcontainern.

Über Uns

Dieser Blogpost wurde von Jeroen Overschie geschrieben, der bei xebia arbeitet.

 


 

GoDataDriven ist ein Spezialist für Daten und KI und bietet hochwertige Beratungsdienste für Kunden in den Niederlanden und darüber hinaus. Fühlen Sie sich im Bereich Daten und KI zu Hause und sind Sie interessiert? Schauen Sie auf unsere Einstellungsseite.

Verfasst von

Jeroen Overschie

Machine Learning Engineer

Jeroen is a Machine Learning Engineer at Xebia.

Contact

Let’s discuss how we can support your journey.