Zum Inhalt

Block 5 – Dockerfiles lesen & verstehen (Optional)

Dauer: ca. 20 Minuten
Ziel: Dockerfiles lesen und verstehen – nicht selbst schreiben, sondern wissen was ein Container macht.

Dieser Block ist optional – er wird durchgeführt wenn Zeit vorhanden ist.


5.1 Was ist ein Dockerfile?

Ein Dockerfile (auf RHEL auch Containerfile genannt) ist die Bauanleitung für ein Image. Als Sysadmin musst du es nicht selbst schreiben – aber lesen können ist wichtig um zu verstehen warum ein Container so läuft wie er läuft.

# Jede Zeile = ein Layer im Image
FROM ubi9/ubi-minimal          # Basis-Image
RUN dnf install -y nginx       # Paket installieren  Layer
COPY nginx.conf /etc/nginx/    # Datei kopieren  Layer
EXPOSE 80                      # Port dokumentieren (kein Forwarding!)
CMD ["nginx", "-g", "daemon off;"]  # Startbefehl

5.2 Die wichtigsten Anweisungen

Anweisung Bedeutung Beispiel
FROM Basis-Image FROM ubi9/ubi-minimal
RUN Befehl beim Bauen ausführen RUN dnf install -y nginx
COPY Datei ins Image kopieren COPY index.html /usr/share/nginx/html/
ADD Wie COPY, entpackt auch Archive ADD app.tar.gz /opt/
EXPOSE Port dokumentieren EXPOSE 80
ENV Umgebungsvariable setzen ENV APP_PORT=3000
USER User für Prozess setzen USER nginx
WORKDIR Arbeitsverzeichnis setzen WORKDIR /opt/app
CMD Standardbefehl beim Start CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT Fest gesetzter Startbefehl ENTRYPOINT ["/docker-entrypoint.sh"]

CMD vs ENTRYPOINT

# CMD kann überschrieben werden:
CMD ["nginx", "-g", "daemon off;"]
# → podman run nginx bash  (bash statt nginx)

# ENTRYPOINT wird immer ausgeführt, CMD sind Argumente:
ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx"]
# → /entrypoint.sh nginx  (immer entrypoint.sh)

5.3 Layer-Caching verstehen

Beim Bauen eines Images cached Podman jeden Layer. Ändert sich eine Zeile, werden alle folgenden Layers neu gebaut:

FROM ubi9/ubi-minimal
RUN dnf install -y nginx        # Layer 1  gecacht solange sich nix ändert
COPY nginx.conf /etc/nginx/     # Layer 2  neu wenn nginx.conf sich ändert
COPY index.html /usr/share/nginx/html/  # Layer 3

"Layer-Caching ist wie make – nur die Schritte die sich verändert haben, werden neu ausgeführt. Deshalb: Sachen die sich selten ändern (Pakete installieren) an den Anfang, Sachen die sich oft ändern (App-Code) ans Ende."


5.4 Ein Image bauen

# Containerfile erstellen
mkdir -p ~/mein-image && cd ~/mein-image

cat > Containerfile << 'EOF'
FROM docker.io/library/nginx:latest
COPY index.html /usr/share/nginx/html/
EOF

# Eigene index.html
echo "<h1>Mein eigenes Image</h1>" > index.html

# Image bauen
podman build -t mein-nginx:v1 .

# Image anzeigen
podman images | grep mein-nginx

# Container aus eigenem Image starten
podman run -d --name eigenes-nginx -p ${PORT}:80 mein-nginx:v1
curl http://localhost:${PORT}

💡 buildah: Podman verwendet intern buildah zum Bauen. Im Alltag reicht podman build vollständig.

Image-Grösse im Blick behalten

podman images
# Eigenes Image sollte nicht viel grösser sein als Basis

# History zeigt Layer-Grössen
podman history mein-nginx:v1

Häufige Fehler die Images unnötig gross machen:

# Schlecht – Package-Cache bleibt im Layer
RUN dnf install -y nginx

# Besser – Cache bereinigen im gleichen Layer
RUN dnf install -y nginx && dnf clean all


5.5 Environments und Secrets

Umgebungsvariablen

# Beim Start übergeben
podman run -e APP_ENV=production nginx
podman run -e DB_HOST=mydb -e DB_PORT=5432 nginx

# Aus einer Datei laden
cat > ~/app.env << EOF
DB_HOST=mydb
DB_PORT=5432
APP_ENV=production
EOF

podman run --env-file ~/app.env nginx

# Im Container prüfen
podman exec mein-nginx env | grep DB_

"Konfiguration via Umgebungsvariablen statt in Config-Dateien hardcoded – der Container bleibt generisch, die Umgebung macht ihn spezifisch."

Podman Secrets

Für sensitive Daten wie Passwörter:

# Secret erstellen
echo "geheim123" | podman secret create db-password -

# Secret anzeigen (Wert nicht sichtbar!)
podman secret ls

# Container mit Secret starten
podman run -d \
  --secret db-password \
  --name meine-app \
  nginx

# Im Container unter /run/secrets/<name> verfügbar
podman exec meine-app cat /run/secrets/db-password

"Secrets sind sicherer als -e PASSWORD=... weil sie nicht in podman inspect oder ps auftauchen."


Übung 5 – Eigenes Image bauen (optional)

Aufgabe 5a – Dockerfile lesen

Schau dir folgendes Dockerfile an und beantworte die Fragen:

FROM docker.io/library/nginx:latest
ENV NGINX_HOST=localhost
RUN mkdir -p /usr/share/nginx/html/app
COPY --chown=nginx:nginx ./html/ /usr/share/nginx/html/app/
EXPOSE 80 443
USER nginx
CMD ["nginx", "-g", "daemon off;"]

Fragen: 1. Welches Basis-Image wird verwendet? 2. Mit welchem User startet nginx? 3. Wohin werden die HTML-Dateien kopiert? 4. Welche Ports werden exponiert?

Aufgabe 5b – Eigenes Image bauen

mkdir -p ~/mein-image && cd ~/mein-image

cat > Containerfile << 'EOF'
FROM docker.io/library/nginx:latest
COPY index.html /usr/share/nginx/html/
EOF

echo "<h1>Gebaut von $(whoami)</h1>" > index.html

podman build -t mein-nginx:v1 .
podman images | grep mein-nginx
podman run -d --name eigenes-nginx -p ${PORT}:80 mein-nginx:v1
curl http://localhost:${PORT}

Musterlösung

5a

  1. docker.io/library/nginx:latest
  2. nginx (USER-Anweisung)
  3. /usr/share/nginx/html/app/
  4. Port 80 und 443

5b

podman build -t mein-nginx:v1 .
# STEP 1/2: FROM nginx:latest
# STEP 2/2: COPY index.html /usr/share/nginx/html/
# Successfully tagged localhost/mein-nginx:v1

curl http://localhost:${PORT}
# <h1>Gebaut von teilnehmer01!</h1>

Thema Link
Containerfile Referenz docs.podman.io – Containerfile
Red Hat – Images bauen access.redhat.com – Building container images