DarkWolfCave
docker

Eigenen Docker Container erstellen

Eigenen Docker Container erstellen - Schritt für Schritt Anleitung
DarkWolf Maskottchen KI-Bild Generiert mit Gemini

Eigenen Docker Container erstellen: Schritt-für-Schritt Anleitung

In diesem Artikel zeige ich dir, wie du deinen eigenen Docker Container als Base-Image für deine Entwicklungsumgebung erstellen kannst. Egal ob du schon Erfahrung mit Docker hast oder gerade erst einsteigst - ich erkläre dir Schritt für Schritt den Weg vom Dockerfile über Docker Compose bis hin zu Volumes für persistente Daten.

DarkWolfCave.de

Update März 2026: Dieser Artikel wurde grundlegend überarbeitet. Die wichtigsten Änderungen:

  • Python Base-Image von python:3.11 (900 MB) auf python:3.13-slim-bookworm (45 MB) aktualisiert
  • Alle Python-Pakete auf aktuelle Versionen gebracht (Flask 3.1, requests 2.32, tabulate 0.10)
  • Docker Compose als empfohlenen Weg zum Starten hinzugefügt
  • Volumes (Bind Mounts und Named Volumes) ausführlich erklärt
  • Security Best Practices: Non-Root User, .dockerignore, --no-cache-dir
  • Neuer Abschnitt: Aktuelle Versionen selbst prüfen, damit die Anleitung nicht veraltet

Eigenen Docker Container erstellen - Was brauchen wir?

Auf deinem Server oder Raspberry Pi muss der Docker-Dienst installiert sein. Portainer ist hilfreich, aber optional. Solltest du bisher noch kein Docker nutzen, empfehle ich dir erst einmal folgenden Artikel von mir durchzugehen:

Raspberry Pi Docker ohne Probleme installieren

Eigene Entwicklungsumgebung in einem Docker Container

Bevor wir starten und einen eigenen Container (Image) erstellen, mit dem wir dann weiter experimentieren und ihn anpassen können, hier ein kleiner Hinweis zur Begrifflichkeit:

Wenn ich im Folgenden von “dev-env” spreche, meine ich damit “development environment” - also eine Entwicklungsumgebung.

Wozu du letztendlich deinen eigenen Docker Container erstellen willst, ist erst einmal nicht wichtig. Ich möchte dir aufzeigen, wie du einen solchen Base-Container generell erstellen und an deine Bedürfnisse anpassen kannst.

Unsere Ausgangslage: Wir erstellen einen Docker Container als Basis-Image zum Entwickeln von Python-Applikationen. Dieser Container dient als Grundlage, um direkt in einer sauberen, isolierten Umgebung arbeiten zu können.

Das Ganze läuft bei mir auf folgenden Komponenten:

Das komplette Setup für den Raspberry Pi 5 mit NVMe Boot

Werbung

Mein Raspberry Pi 5 Setting

Bild Produkt Preis
Produktdaten werden geladen...
Letzte Aktualisierung: - | Infos zu Affiliate Links | Bilder von der Amazon Product Advertising API

Wir nutzen wie immer einen Raspberry Pi und erstellen uns erst einmal eine Ordnerstruktur. In meinem Fall speichere ich alles unter dem angemeldeten User im Verzeichnis tutorials/eigene_docker_container/dev-env.

Verbinde dich auf deinem Raspberry per Terminal und erstelle die Ordner:

mkdir -p ~/tutorials/eigene_docker_container/dev-env
cd ~/tutorials/eigene_docker_container/dev-env

Aktuelle Versionen prüfen - bevor du loslegst

Software-Versionen ändern sich ständig. Bevor du dein Dockerfile schreibst, solltest du kurz prüfen, welche Versionen aktuell stabil sind. So stellst du sicher, dass dein Container von Anfang an auf dem neuesten Stand ist.

Python Base-Image auf Docker Hub prüfen:

# Zeigt dir die verfügbaren Tags für das offizielle Python-Image
docker search python --limit 5

# Oder direkt auf Docker Hub nachschauen:
# https://hub.docker.com/_/python/tags
# Filtere dort nach "slim-bookworm" für schlanke Debian-basierte Images

Zum Zeitpunkt der letzten Überarbeitung (März 2026) ist python:3.13-slim-bookworm eine gute Wahl - schlank (~45 MB), stabil und auf dem aktuellen Debian Bookworm basierend. Das volle Image (python:3.13) wäre über 900 MB groß und enthält viele Pakete, die du im Container nicht brauchst.

Python-Pakete auf PyPI prüfen:

Die aktuellen stabilen Versionen findest du direkt auf pypi.org - einfach nach dem Paketnamen suchen (z.B. pypi.org/project/Flask). Dort steht immer die neueste Version ganz oben.

Alternativ kannst du auch im Terminal prüfen:

pip index versions flask

Projektdateien erstellen

In unserem Projektverzeichnis brauchen wir drei Dateien. Beachte dabei, dass Dockerfile mit großem D geschrieben wird:

touch Dockerfile requirements.txt .dockerignore

requirements.txt

Hier tragen wir unsere Python-Abhängigkeiten mit festen Versionsnummern ein. Feste Versionen sind wichtig, damit dein Build jederzeit reproduzierbar ist - also heute und in drei Monaten das gleiche Ergebnis liefert.

Bearbeite die requirements.txt und füge folgendes hinzu:

Flask==3.1.3
requests==2.32.5
tabulate==0.10.0

Solltest du im Laufe der Entwicklung weitere Bibliotheken benötigen, trägst du sie hier ein und baust das Image einfach neu.

.dockerignore

Die .dockerignore-Datei funktioniert wie eine .gitignore - sie verhindert, dass unnötige oder sensible Dateien ins Image kopiert werden:

__pycache__/
*.py[cod]
.venv/
venv/
.git/
.gitignore
.env
.env.*
*.egg-info/
dist/
build/

Dockerfile

Jetzt das Herzstück - unser Dockerfile. Es beschreibt Schritt für Schritt, wie Docker das Image zusammenbauen soll.

Für mehr Details zu den einzelnen Befehlen schaue in die offizielle Dockerfile-Referenz.

# Schlankes Python-Image als Basis (~45 MB statt ~900 MB)
FROM python:3.13-slim-bookworm

# Arbeitsverzeichnis im Container festlegen
WORKDIR /app

# Zuerst nur requirements.txt kopieren (Docker-Cache nutzen!)
# Solange sich requirements.txt nicht ändert, wird dieser Layer gecacht
COPY requirements.txt requirements.txt

# Python-Abhängigkeiten installieren
# --no-cache-dir spart Speicher, da pip keinen Download-Cache anlegt
RUN pip install --no-cache-dir -r requirements.txt

# Entwicklertools installieren
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    curl \
    git \
    && rm -rf /var/lib/apt/lists/*

# Eigenen App-Code in den Container kopieren
COPY . .

# Nicht-Root User erstellen (Security Best Practice)
RUN groupadd -r -g 1001 appgroup \
    && useradd -r -u 1001 -g appgroup -d /app -s /sbin/nologin appuser \
    && chown -R appuser:appgroup /app

# Als normaler User statt root ausführen
USER appuser

# Standard-Befehl beim Containerstart
CMD ["python"]

Warum die Reihenfolge wichtig ist: Docker arbeitet mit Layer-Caching. Dateien die sich selten ändern (requirements.txt) sollten vor Dateien kopiert werden, die sich oft ändern (dein Code). So muss Docker bei einer Code-Änderung nicht jedes Mal alle Abhängigkeiten neu installieren.

Warum ein eigener User? Container laufen standardmäßig als root. Das ist ein Sicherheitsrisiko - wenn jemand aus dem Container ausbricht, hat er root-Rechte auf dem Host. Mit einem eigenen User ohne root-Rechte begrenzt du den möglichen Schaden.

Hinweis: Als appuser kannst du im Container keine Systempakete mit apt-get nachinstallieren. Wenn du im Container experimentieren und Pakete testen willst, verbinde dich einfach als root:

docker compose exec -u root dev-env bash

Sobald du weißt, welche Pakete du brauchst, trägst du sie ins Dockerfile ein und baust das Image neu. So bleibt dein Image sauber dokumentiert.

Image bauen und Container starten

Image bauen

docker build -t dev-env:v1 .

Der Punkt am Ende ist wichtig - er sagt Docker, dass das Dockerfile im aktuellen Verzeichnis liegt.

Container starten (Terminal)

docker run --name dev-env -it dev-env:v1 bash

Der Befehl startet den Container und verbindet dich direkt mit einer Bash-Shell. Du solltest dann im Prompt appuser@<container-id>:/app$ sehen - dein festgelegtes Arbeitsverzeichnis. Mit exit verlässt und beendest du den Container wieder.

Docker Compose - der bessere Weg

Den Container jedes Mal mit einem langen docker run-Befehl zu starten, ist umständlich und fehleranfällig. Mit Docker Compose definierst du alles in einer Datei - Ports, Volumes, Restart-Verhalten - und startest mit einem einzigen Befehl.

Erstelle eine docker-compose.yml im selben Verzeichnis:

services:
  dev-env:
    build: .
    container_name: dev-env
    ports:
      - "5666:5000"
    volumes:
      - ./src:/app/src
    stdin_open: true
    tty: true
    restart: unless-stopped

Was passiert hier?

  • build: . - baut das Image aus dem Dockerfile im aktuellen Verzeichnis
  • ports - leitet Port 5666 auf dem Host zu Port 5000 im Container weiter (z.B. für Flask)
  • volumes - verbindet dein lokales src/-Verzeichnis mit /app/src im Container (dazu gleich mehr)
  • stdin_open und tty - entspricht -it bei docker run, damit du dich per Terminal verbinden kannst
  • restart: unless-stopped - der Container startet nach einem Reboot automatisch neu, es sei denn du hast ihn bewusst gestoppt

Starten und stoppen:

# Container bauen und im Hintergrund starten
docker compose up -d --build

# Logs anzeigen
docker compose logs -f dev-env

# Container stoppen
docker compose down

Volumes - deine Daten überleben den Container

Ein wichtiger Punkt, der gerade am Anfang für Verwirrung sorgt: Container sind flüchtig. Alles was du innerhalb eines Containers erstellst oder veränderst, ist weg, sobald du den Container löschst und neu erstellst. Ein einfacher Stopp und Neustart behält die Daten - aber ein docker compose down gefolgt von up nicht.

Die Lösung sind Volumes - sie verbinden ein Verzeichnis auf deinem Host mit einem Verzeichnis im Container.

Bind Mounts für Entwicklung

In unserer docker-compose.yml haben wir bereits einen Bind Mount definiert:

volumes:
  - ./src:/app/src

Das bedeutet: Dein lokales src/-Verzeichnis wird direkt in den Container unter /app/src eingebunden. Änderungen auf beiden Seiten sind sofort sichtbar - du kannst auf dem Host programmieren und im Container ausführen.

Erstelle das Verzeichnis und teste es:

# Lokales src-Verzeichnis erstellen
mkdir -p src

# Eine Test-Datei anlegen
echo 'print("Hallo aus dem Container!")' > src/hello.py

# Container starten und Script ausführen
docker compose up -d --build
docker compose exec dev-env python src/hello.py

Named Volumes für persistente Daten

Für Daten die unabhängig vom Host-Dateisystem existieren sollen (z.B. Datenbanken), nutzt du Named Volumes:

services:
  dev-env:
    build: .
    volumes:
      - ./src:/app/src
      - app-data:/app/data

volumes:
  app-data:

Named Volumes werden von Docker verwaltet und überleben auch ein docker compose down. Erst docker compose down -v löscht sie explizit.

Du willst Docker nicht selbst einrichten? Ich übernehme das für dich — schau dir meine Services an

Container über Portainer bereitstellen

Alternativ kannst du deinen Container auch über Portainer verwalten. Trage den Namen des Images bei “Create Container” unter “Image” ein. Lass dich nicht durch das docker.io irritieren - da Portainer lokal auf deine Images zugreift, findet er dein selbst erstelltes Image auch ohne Registry.

Eigenen Docker Container erstellen - Portainer Image Auswahl

Gib den Port an (in unserem Beispiel 5666) und wähle unter “Advanced container settings”“Console” die Option “Interactive & TTY” aus.

Eigenen Docker Container erstellen - Portainer Port und Console Einstellung

Mit Container verbinden

Deinen laufenden Container erreichst du über das Terminal oder über Portainer.

Per Terminal:

docker compose exec dev-env bash

# oder ohne Docker Compose:
docker exec -it dev-env /bin/bash

# mit exit verlässt du den Container wieder

Per Portainer:

In der Container-Übersicht den Console-Button klicken und auf Connect. Damit das funktioniert, muss die Option “Interactive & TTY” beim Deployment aktiviert sein.

Eigenen Docker Container erstellen - Portainer Console Verbindung

Wenn du meiner Anleitung gefolgt bist, befindest du dich jetzt innerhalb deines Containers im Pfad /app. Python startest du einfach mit python und verlässt die Python-Umgebung wieder mit exit().

Wie geht es jetzt weiter?

Du hast jetzt ein eigenes Base-Image, das du als Grundlage für weitere Projekte nutzen kannst. Probier es direkt aus - erstelle eine kleine Flask-App in deinem src/-Verzeichnis:

# src/app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1>Mein erster Docker Container!</h1>"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Starte den Container und rufe die App auf:

docker compose up -d --build
docker compose exec dev-env python src/app.py

Öffne jetzt im Browser http://<deine-raspberry-ip>:5666 - du solltest die Ausgabe deiner Flask-App sehen.

Weitere Ideen:

  • Anderes Base-Image: Statt Python kannst du z.B. node:22-slim-bookworm oder ubuntu:24.04 als Basis nehmen
  • Eigene Tools: Erweitere das Dockerfile mit allem, was du brauchst - Datenbanken, Build-Tools, CLI-Werkzeuge

Alles was du an dein Dockerfile anpasst, baust du einfach neu mit docker compose up -d --build.

Ich hoffe ich konnte dir helfen. Bei Fragen schreibe in den Kommentaren oder schau auf meinem Discord-Kanal vorbei.

Kurze Zusammenfassung

  • Versionen prüfen: Vor dem Start auf Docker Hub und PyPI die aktuellen stabilen Versionen nachschauen
  • Projektdateien erstellen: Dockerfile, requirements.txt, .dockerignore und docker-compose.yml
  • Schlankes Base-Image nutzen: python:3.13-slim-bookworm statt des vollen Images
  • Feste Versionen pinnen: In der requirements.txt immer mit == arbeiten
  • Docker Compose nutzen: Ports, Volumes und Restart-Verhalten deklarativ in einer Datei
  • Volumes für Daten: Bind Mounts für deinen Code, Named Volumes für persistente Daten
  • Image bauen: docker compose up -d --build
  • Container verbinden: docker compose exec dev-env bash
  • Iterativ erweitern: Neue Pakete in requirements.txt oder Dockerfile eintragen und neu bauen

Du hast weitere Fragen oder benötigst Hilfe? Nutze die Kommentar-Sektion oder schau auf meinem Discord-Kanal vorbei.

VIP Support
Wolf Support Avatar

Du wirst hier einen groben Überblick finden.
Allerdings biete ich dir auch noch etwas mehr Support an:

  • Du benötigst persönlichen Support
  • Du möchtest von Beginn an Unterstützung bei deinem Projekt
  • Du möchtest ein hier vorgestelltes Plugin durch mich installieren und einrichten lassen
  • Du würdest gerne ein von mir erstelltes Script etwas mehr an deine Bedürfnisse anpassen

Für diese Punkte und noch einiges mehr habe ich einen limitierten VIP-Tarif eingerichtet.

Falls der Tarif gerade nicht verfügbar ist, kontaktiere mich auf Discord!

FAQ - Frequently Asked Questions DarkWolfCave
DarkWolf hilft bei FAQs

Häufig gestellte Fragen

Was ist Docker?
Docker ist eine Container-Plattform, die es ermöglicht, Anwendungen und deren Abhängigkeiten in isolierten Umgebungen, sogenannten Containern, zu verpacken und auszuführen. Diese Container sind leichtgewichtige, tragbare und konsistente Einheiten, die eine reibungslose Bereitstellung von Anwendungen über verschiedene Umgebungen hinweg ermöglichen.
Was ist das Ziel dieses Artikels?
Dieser Artikel zeigt, wie du deinen eigenen Docker Container als Base-Image für Entwicklungszwecke erstellen kannst. Du lernst Dockerfile, Docker Compose, Volumes und aktuelle Best Practices kennen - alles Schritt für Schritt erklärt.
Welche Voraussetzungen sind notwendig?
Auf deinem Server oder Raspberry Pi muss der Docker-Dienst installiert sein. Portainer ist hilfreich, aber optional. Falls du bisher noch kein Docker nutzt, wird ein empfohlener Artikel bereitgestellt, den du vorab durchgehen kannst.
Was bedeutet "dev-env" in diesem Kontext?
Wenn im Folgenden von "dev-env" die Rede ist, bezieht sich dies auf "development environment" - also eine Entwicklungsumgebung.
Warum ein slim-Image statt des vollen Python-Images?
Das volle Python-Image ist über 900 MB groß und enthält viele Pakete, die du in einem Container nicht brauchst. Die slim-Variante basiert auf Debian, ist nur ca. 45 MB groß und reicht für die allermeisten Python-Projekte völlig aus.

Kommentare

URLs werden automatisch verlinkt
Kommentare werden geladen...