0 55

Was ist ein Dockerfile?

Ein Dockerfile ist eine Textdatei mit Anweisungen, wie Docker ein Image erstellen soll. Es ist das „Rezept“ für Ihr Container-Image.

Analogie: Ein Dockerfile ist wie ein Kochrezept:

  • Zutaten (Base Image, Dependencies)
  • Schritte (RUN, COPY Befehle)
  • Endprodukt (Fertiges Image)

Ihr erstes Dockerfile

Erstellen Sie eine Datei namens Dockerfile (ohne Endung):

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
EXPOSE 80

Erstellen Sie index.html:

<h1>Mein erstes Docker-Image!</h1>

Image bauen:

docker build -t meine-webseite:v1 .

Container starten:

docker run -d -p 8080:80 meine-webseite:v1

Besuchen Sie http://localhost:8080

Die wichtigsten Dockerfile-Befehle

FROM – Base Image wählen

# Offizielles Nginx-Image
FROM nginx:alpine

# Node.js 18
FROM node:18-alpine

# Python 3.11
FROM python:3.11-slim

# Ubuntu 22.04
FROM ubuntu:22.04

Best Practice: Verwenden Sie Alpine-Versionen für kleinere Images.

WORKDIR – Arbeitsverzeichnis setzen

FROM node:18-alpine
WORKDIR /app
# Alle folgenden Befehle laufen in /app

COPY – Dateien kopieren

# Einzelne Datei
COPY package.json /app/

# Mehrere Dateien
COPY package.json package-lock.json /app/

# Verzeichnis kopieren
COPY ./src /app/src

# Alles kopieren
COPY . /app/

RUN – Befehle ausführen

# Pakete installieren
RUN apt-get update && apt-get install -y curl

# Node Packages installieren
RUN npm install

# Mehrere Befehle kombinieren
RUN apt-get update && \
    apt-get install -y curl wget && \
    rm -rf /var/lib/apt/lists/*

Wichtig: Kombinieren Sie RUN-Befehle mit && um Layer zu reduzieren.

ENV – Umgebungsvariablen

ENV NODE_ENV=production
ENV PORT=3000
ENV DATABASE_URL=mysql://db:3306/mydb

EXPOSE – Ports dokumentieren

EXPOSE 80
EXPOSE 3000
EXPOSE 8080 8443

Hinweis: EXPOSE öffnet Ports nicht wirklich, es ist nur Dokumentation.

CMD – Standard-Befehl

# Shell-Form
CMD npm start

# Exec-Form (bevorzugt)
CMD ["npm", "start"]

# Nur ein CMD pro Dockerfile!

ENTRYPOINT – Haupt-Executable

ENTRYPOINT ["python", "app.py"]

# Mit CMD für Default-Argumente
ENTRYPOINT ["python"]
CMD ["app.py"]

Praktische Beispiele

Node.js-Anwendung

FROM node:18-alpine

WORKDIR /app

# Dependencies zuerst (für besseres Caching)
COPY package*.json ./
RUN npm ci --only=production

# Dann Source Code
COPY . .

EXPOSE 3000

ENV NODE_ENV=production

CMD ["node", "server.js"]

PHP mit Apache

FROM php:8.2-apache

# PHP Extensions installieren
RUN docker-php-ext-install pdo pdo_mysql mysqli

# Apache Rewrite aktivieren
RUN a2enmod rewrite

# Code kopieren
COPY ./src /var/www/html/

# Berechtigungen setzen
RUN chown -R www-data:www-data /var/www/html

EXPOSE 80

Python Flask-App

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

ENV FLASK_APP=app.py
ENV FLASK_ENV=production

CMD ["flask", "run", "--host=0.0.0.0"]

Image bauen

# Basis-Build
docker build -t mein-image .

# Mit Tag
docker build -t mein-image:1.0.0 .

# Mit mehreren Tags
docker build -t mein-image:1.0.0 -t mein-image:latest .

# Ohne Cache
docker build --no-cache -t mein-image .

# Mit Build-Argumenten
docker build --build-arg VERSION=1.0 -t mein-image .

# Anderes Dockerfile
docker build -f Dockerfile.prod -t mein-image:prod .

.dockerignore erstellen

Erstellen Sie .dockerignore um Dateien auszuschließen:

node_modules
npm-debug.log
.git
.env
*.md
Dockerfile
.dockerignore
dist
coverage
.vscode
.idea
__pycache__
*.pyc

Das beschleunigt den Build und reduziert die Image-Größe.

Build-Argumente (ARG)

FROM node:18-alpine

ARG VERSION=latest
ARG BUILD_DATE

LABEL version=$VERSION
LABEL build-date=$BUILD_DATE

WORKDIR /app
COPY . .

RUN npm install

CMD ["node", "server.js"]

Bauen mit Argumenten:

docker build \
  --build-arg VERSION=1.2.3 \
  --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
  -t myapp:1.2.3 .

Layer-Caching verstehen

Docker cached jede Anweisung als Layer. Wenn eine Layer sich ändert, müssen alle folgenden neu gebaut werden.

Schlechtes Beispiel:

FROM node:18-alpine
COPY . /app
RUN npm install

Jede Code-Änderung triggert npm install neu!

Gutes Beispiel:

FROM node:18-alpine
COPY package*.json /app/
RUN npm install
COPY . /app

npm install läuft nur neu, wenn package.json sich ändert.

Best Practices

1. Minimale Base Images

# Groß (>1GB)
FROM node:18

# Klein (~150MB)
FROM node:18-alpine

2. Multi-Stage Builds (Preview)

# Build Stage
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build

# Production Stage
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

3. Nicht-Root-User

FROM node:18-alpine

RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

WORKDIR /app
COPY --chown=nodejs:nodejs . .

USER nodejs

CMD ["node", "server.js"]

4. Labels für Metadaten

LABEL maintainer="email@example.com"
LABEL version="1.0"
LABEL description="Meine Anwendung"

5. Aufräumen in der gleichen Layer

RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

Troubleshooting

Build schlägt fehl

# Verbose Output
docker build --progress=plain -t myapp .

# Bestimmte Stage bauen
docker build --target builder -t myapp:builder .

Image zu groß

# Image-Größe prüfen
docker images

# Layer-Historie anschauen
docker history mein-image:latest

Cache-Probleme

# Ohne Cache neu bauen
docker build --no-cache -t myapp .

# Nur ab bestimmter Stage ohne Cache
docker build --no-cache --target production -t myapp .

Zusammenfassung

  • Dockerfiles sind Bauanleitungen für Images
  • Layer-Caching nutzen für schnellere Builds
  • Alpine-Images für kleinere Größen
  • .dockerignore nicht vergessen
  • Kombinieren Sie RUN-Befehle
  • Non-Root-User verwenden

Author: Andreas Lang

Sphinx-Flashdesign.de

Andreas Lang konzentriert sich seit zwei Jahrzehnten auf die Webentwicklung und Webdesign mit dem Schwerpunkt PHP, Laravel und Javascript und betreut seine Kunden mit Herz und Seele in allen Bereichen von Entwicklung, Design, Suchmaschinenoptimierung, IT-Recht, IT-Sicherheit etc.