Dockerfile
Dockerfile ist eine Textdatei mit Anweisungen wie ein Docker Image gebaut werden soll.
Wie ein Kochrezept das Schritt für Schritt erklärt was in den Container gehört.
Visualisierung: Dockerfile → Image
DOCKERFILE BUILD PROCESS:
┌───────────────────┐
│ Dockerfile │
│ │
│ FROM ubuntu │─┐
│ RUN apt-get... │ ├─► docker build
│ COPY app.py . │ │
│ CMD python app.py │─┘
└───────────────────┘
│
├─ Layer 1: ubuntu
├─ Layer 2: apt-get install
├─ Layer 3: copy app.py
└─ Layer 4: CMD
│
▼
┌───────────────────┐
│ Docker Image │
│ myapp:latest │
└───────────────────┘
│
│ docker run
▼
┌───────────────────┐
│ Container │
│ (Running) │
└───────────────────┘
Grundstruktur
Minimal Dockerfile
# Kommentar: Base Image auswählen
FROM ubuntu:20.04
# Arbeitsverzeichnis setzen
WORKDIR /app
# Dateien kopieren
COPY . .
# Befehl ausführen
RUN apt-get update && apt-get install -y python3
# Standard Startbefehl
CMD ["python3", "app.py"]
Vollständiges Beispiel
# Base Image (immer zuerst!)
FROM node:16-alpine
# Maintainer Info (optional)
LABEL maintainer="[email protected]"
LABEL version="1.0"
LABEL description="My awesome app"
# Arbeitsverzeichnis
WORKDIR /app
# System-Dependencies
RUN apk add --no-cache \
python3 \
make \
g++
# Package Files kopieren (für Caching!)
COPY package*.json ./
# Dependencies installieren
RUN npm ci --only=production
# App Code kopieren
COPY . .
# Port dokumentieren
EXPOSE 3000
# Umgebungsvariablen
ENV NODE_ENV=production
ENV PORT=3000
# Nicht-root User
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# Health Check
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# Volume definieren
VOLUME ["/app/data"]
# Startbefehl
CMD ["node", "server.js"]
Dockerfile Befehle
FROM - Base Image
# Offizielle Images
FROM ubuntu:20.04
FROM node:16-alpine
FROM python:3.9-slim
# Multi-stage: Named Stage
FROM node:16 AS builder
# Scratch (leeres Image)
FROM scratch
RUN - Befehle ausführen
# Einfacher Befehl
RUN apt-get update
# Mehrere Befehle (kombiniert für weniger Layers)
RUN apt-get update && \
apt-get install -y \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
# Shell Form vs Exec Form
RUN apt-get update # Shell: /bin/sh -c
RUN ["apt-get", "update"] # Exec: Direkt ausführen
COPY & ADD
# COPY - Dateien kopieren
COPY app.py /app/
COPY . /app/
COPY --chown=user:group file.txt /app/
# ADD - Kopieren + Auto-Extract
ADD app.tar.gz /app/ # Wird automatisch entpackt
ADD https://example.com/file /app/ # URLs herunterladen
# Best Practice: COPY bevorzugen
COPY package*.json ./ # Nur was gebraucht wird
WORKDIR
# Arbeitsverzeichnis setzen
WORKDIR /app
# Erstellt Verzeichnis wenn nicht existiert
# Relativ zum vorherigen WORKDIR
WORKDIR /app
WORKDIR src # Jetzt: /app/src
CMD - Default Command
# Exec Form (empfohlen)
CMD ["node", "server.js"]
CMD ["python", "app.py"]
# Shell Form
CMD node server.js
# Mit ENTRYPOINT kombiniert
ENTRYPOINT ["python"]
CMD ["app.py"] # Default Argument
ENTRYPOINT
# Container als Executable
ENTRYPOINT ["python"]
CMD ["app.py"]
# Startet als: python app.py
# Override möglich: docker run image other.py
ENV - Umgebungsvariablen
# Einzeln
ENV NODE_ENV=production
ENV PORT=3000
# Mehrere
ENV NODE_ENV=production \
PORT=3000 \
LOG_LEVEL=info
# Verwendet in anderen Befehlen
ENV APP_HOME=/app
WORKDIR $APP_HOME
EXPOSE - Port dokumentieren
# Port freigeben (nur Dokumentation!)
EXPOSE 80
EXPOSE 443
EXPOSE 3000/tcp
EXPOSE 53/udp
# Tatsächliches Publishing: docker run -p
VOLUME
# Mount Point definieren
VOLUME /data
VOLUME ["/var/log", "/var/db"]
# Anonymous Volume zur Runtime
docker run -v /data myimage
USER
# Benutzer wechseln
USER node
USER 1000:1000
# Best Practice: Non-root
RUN adduser -D appuser
USER appuser
ARG - Build Arguments
# Build-Time Variable
ARG VERSION=1.0
ARG NODE_ENV
# Verwenden
FROM node:${VERSION}
RUN echo "Building for $NODE_ENV"
# Übergeben beim Build
docker build --build-arg VERSION=16 --build-arg NODE_ENV=prod .
HEALTHCHECK
# Health Check definieren
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# Oder
HEALTHCHECK CMD wget --quiet --tries=1 --spider http://localhost:8080/health || exit 1
# Deaktivieren
HEALTHCHECK NONE
LABEL
# Metadata hinzufügen
LABEL version="1.0"
LABEL description="My Application"
LABEL maintainer="[email protected]"
Multi-Stage Builds
Warum Multi-Stage?
SINGLE STAGE: MULTI-STAGE:
┌──────────────────┐ ┌──────────────────┐
│ Build Tools │ │ Build Tools │
│ Dependencies │ │ Dependencies │
│ Source Code │ │ Source Code │
│ Compiled App │ │ Compiled App │
└──────────────────┘ └────────┬─────────┘
Image: 1.5 GB │ Copy only app
┌───────▼──────────┐
│ Compiled App │
│ Runtime Only │
└──────────────────┘
Image: 100 MB ✅
Node.js Beispiel
# Build Stage
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production Stage
FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
USER node
CMD ["node", "dist/server.js"]
Go Beispiel
# Build
FROM golang:1.19 AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp
# Production (minimal!)
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]
Spezifischen Stage bauen
# Nur builder Stage
docker build --target builder -t myapp:build .
# Production Stage (default)
docker build -t myapp:prod .
Best Practices
1. Layer Caching optimal nutzen
# ❌ SCHLECHT - Bei jeder Code-Änderung neu installieren
COPY . .
RUN npm install
# ✅ GUT - npm install wird gecached
COPY package*.json ./
RUN npm install
COPY . .
2. Layers minimieren
# ❌ SCHLECHT - Viele Layers
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get install -y pip
RUN apt-get clean
# ✅ GUT - Ein Layer
RUN apt-get update && \
apt-get install -y \
python3 \
python3-pip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
3. .dockerignore verwenden
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.DS_Store
dist
coverage
*.log
4. Alpine Images
# ✅ Klein und sicher
FROM node:16-alpine # ~100MB
FROM python:3.9-alpine # ~50MB
# ❌ Groß
FROM node:16 # ~900MB
FROM python:3.9 # ~900MB
5. Non-root User
# ✅ Sicher
RUN adduser -D -s /bin/sh appuser
USER appuser
# ❌ Unsicher - läuft als root
# (Standard wenn nicht angegeben)
6. Spezifische Tags
# ✅ Vorhersagbar
FROM node:16.14.2-alpine
# ❌ Unvorhersagbar - ändert sich!
FROM node:latest
Praktische Beispiele
Python Flask App
FROM python:3.9-slim
WORKDIR /app
# Dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# App Code
COPY . .
# Non-root
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
EXPOSE 5000
CMD ["flask", "run", "--host=0.0.0.0"]
React Build
# Build Stage
FROM node:16-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production Stage
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Java Spring Boot
FROM openjdk:17-jdk-slim AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
FROM openjdk:17-jre-slim
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Troubleshooting
Build schlägt fehl
# Mit Details
docker build --progress=plain -t myapp .
# Ohne Cache (clean build)
docker build --no-cache -t myapp .
# Bestimmten Layer anschauen
docker build --target builder -t myapp:debug .
docker run -it myapp:debug sh
Image zu groß
# Layers analysieren
docker history myapp:latest
# Layer Größen
docker history --no-trunc myapp:latest
# Tools verwenden
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive:latest myapp:latest
Zusammenfassung
Dockerfile Kernpunkte
- Rezept für Images: Schritt-für-Schritt Anleitung
- Layers: Jeder Befehl = Ein Layer
- Caching: Layers werden wiederverwendet
- Multi-stage: Kleine Production Images
- Best Practices: Alpine, Non-root, .dockerignore
Dockerfile Checkliste
Verwandte Konzepte
- Docker - Hauptnotiz
- Docker Image - Dockerfile erstellt Images
- Docker Container - Images werden zu Containern
- Docker Compose - Orchestrierung mit docker-compose.yml