From bd046e626d96e68cc1080fd4a537e300dcdc2a66 Mon Sep 17 00:00:00 2001 From: Frank Engel Date: Tue, 19 May 2026 22:04:17 +0200 Subject: [PATCH] Tag 2 Materialien: Exercises ex05-ex15 + Ubuntu 24.04 Setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - listings/exercises/ex05-ex15: alle Übungsdateien für Tag 2 (Networking, Bind Mounts, Volumes, Env Variables, Compose, Build, Push, Registry) - setup/setup-ubuntu2404.sh: Prep-Script für Ubuntu 24.04 (Noble) Co-Authored-By: Claude Sonnet 4.6 --- .../exercises/ex05-networking/commands.sh | 19 +++ .../exercises/ex06-bind-mount/commands.sh | 12 ++ .../exercises/ex07-named-volume/commands.sh | 14 ++ .../exercises/ex08-persistence/commands.sh | 18 +++ listings/exercises/ex09-env-variables/app.env | 3 + .../exercises/ex09-env-variables/commands.sh | 24 +++ .../ex10-compose-basic/docker-compose.yml | 21 +++ .../ex11-compose-volume/docker-compose.yml | 26 +++ .../ex12-build-inspect/Containerfile | 2 + .../ex12-build-inspect/docker-compose.yml | 5 + .../exercises/ex12-build-inspect/index.html | 4 + .../exercises/ex13-multistage/Containerfile | 8 + listings/exercises/ex13-multistage/go.mod | 3 + listings/exercises/ex13-multistage/main.go | 7 + listings/exercises/ex14-push/commands.sh | 13 ++ .../exercises/ex15-registry-api/commands.sh | 12 ++ setup/setup-ubuntu2404.sh | 150 ++++++++++++++++++ 17 files changed, 341 insertions(+) create mode 100755 listings/exercises/ex05-networking/commands.sh create mode 100755 listings/exercises/ex06-bind-mount/commands.sh create mode 100755 listings/exercises/ex07-named-volume/commands.sh create mode 100755 listings/exercises/ex08-persistence/commands.sh create mode 100644 listings/exercises/ex09-env-variables/app.env create mode 100755 listings/exercises/ex09-env-variables/commands.sh create mode 100644 listings/exercises/ex10-compose-basic/docker-compose.yml create mode 100644 listings/exercises/ex11-compose-volume/docker-compose.yml create mode 100644 listings/exercises/ex12-build-inspect/Containerfile create mode 100644 listings/exercises/ex12-build-inspect/docker-compose.yml create mode 100644 listings/exercises/ex12-build-inspect/index.html create mode 100644 listings/exercises/ex13-multistage/Containerfile create mode 100644 listings/exercises/ex13-multistage/go.mod create mode 100644 listings/exercises/ex13-multistage/main.go create mode 100755 listings/exercises/ex14-push/commands.sh create mode 100755 listings/exercises/ex15-registry-api/commands.sh create mode 100755 setup/setup-ubuntu2404.sh diff --git a/listings/exercises/ex05-networking/commands.sh b/listings/exercises/ex05-networking/commands.sh new file mode 100755 index 0000000..303f210 --- /dev/null +++ b/listings/exercises/ex05-networking/commands.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Exercise 5 — Container Networking + +podman network create appnet + +podman run -d --name backend --network appnet nginx:1.27 +podman run -d --name frontend --network appnet -p 8080:80 nginx:1.27 + +podman network inspect appnet + +# Container-to-container (DNS im appnet) +podman exec -ti frontend curl backend + +# Host-to-container (Port-Mapping) +curl localhost:8080 + +# Cleanup +podman rm -f frontend backend +podman network rm appnet diff --git a/listings/exercises/ex06-bind-mount/commands.sh b/listings/exercises/ex06-bind-mount/commands.sh new file mode 100755 index 0000000..dc6f622 --- /dev/null +++ b/listings/exercises/ex06-bind-mount/commands.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Exercise 6 — Bind Mounts + +# Terminal 1: write dates to /tmp/output +podman run -v /tmp:/data --rm -ti busybox \ + sh -c 'while true; do sleep 1; date >> /data/output; done' + +# Terminal 2: watch the output +podman run -v /tmp:/data --rm busybox tail -f /data/output + +# Cleanup +rm -f /tmp/output diff --git a/listings/exercises/ex07-named-volume/commands.sh b/listings/exercises/ex07-named-volume/commands.sh new file mode 100755 index 0000000..57510a4 --- /dev/null +++ b/listings/exercises/ex07-named-volume/commands.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Exercise 7 — Named Volumes (shared between containers) + +podman volume create pizza + +# Terminal 1: write dates into the volume +podman run -v pizza:/data --rm -ti busybox \ + sh -c 'while true; do sleep 1; date >> /data/output; done' + +# Terminal 2: watch the output +podman run -v pizza:/data --rm busybox tail -f /data/output + +# Cleanup +podman volume rm pizza diff --git a/listings/exercises/ex08-persistence/commands.sh b/listings/exercises/ex08-persistence/commands.sh new file mode 100755 index 0000000..9a06c55 --- /dev/null +++ b/listings/exercises/ex08-persistence/commands.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Exercise 8 — Volume Persistence (data survives container removal) + +podman volume create pasta + +# Create a file inside the container +podman run -v pasta:/data --name pasta --rm -ti busybox \ + sh -c 'touch /data/hello && echo "file created"' + +# Container is gone — volume still exists +podman volume inspect pasta + +# New container, same volume (different mountpoint) +podman run -v pasta:/mnt --name pasta2 --rm -ti busybox \ + ls -la /mnt + +# Cleanup +podman volume rm pasta diff --git a/listings/exercises/ex09-env-variables/app.env b/listings/exercises/ex09-env-variables/app.env new file mode 100644 index 0000000..3382f0d --- /dev/null +++ b/listings/exercises/ex09-env-variables/app.env @@ -0,0 +1,3 @@ +POSTGRES_DB=myapp +POSTGRES_USER=app +POSTGRES_PASSWORD=secret diff --git a/listings/exercises/ex09-env-variables/commands.sh b/listings/exercises/ex09-env-variables/commands.sh new file mode 100755 index 0000000..835bac7 --- /dev/null +++ b/listings/exercises/ex09-env-variables/commands.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Exercise 9 — Environment Variables + +# Single variables via -e +podman run -d --name mydb \ + -e POSTGRES_DB=myapp \ + -e POSTGRES_USER=app \ + -e POSTGRES_PASSWORD=secret \ + postgres:16-alpine + +# Verify +podman exec -ti mydb psql -U app myapp -c "\l" + +podman rm -f mydb + +# Via env-file +podman run -d --name mydb \ + --env-file app.env \ + postgres:16-alpine + +podman exec -ti mydb psql -U app myapp -c "\l" + +# Cleanup +podman rm -f mydb diff --git a/listings/exercises/ex10-compose-basic/docker-compose.yml b/listings/exercises/ex10-compose-basic/docker-compose.yml new file mode 100644 index 0000000..b29f133 --- /dev/null +++ b/listings/exercises/ex10-compose-basic/docker-compose.yml @@ -0,0 +1,21 @@ +services: + db: + image: postgres:16-alpine + environment: + POSTGRES_DB: myapp + POSTGRES_USER: app + POSTGRES_PASSWORD: secret + networks: + - backend + + web: + image: nginx:1.27-alpine + ports: + - "8080:80" + depends_on: + - db + networks: + - backend + +networks: + backend: diff --git a/listings/exercises/ex11-compose-volume/docker-compose.yml b/listings/exercises/ex11-compose-volume/docker-compose.yml new file mode 100644 index 0000000..5111b62 --- /dev/null +++ b/listings/exercises/ex11-compose-volume/docker-compose.yml @@ -0,0 +1,26 @@ +services: + db: + image: postgres:16-alpine + environment: + POSTGRES_DB: myapp + POSTGRES_USER: app + POSTGRES_PASSWORD: secret + volumes: + - db-data:/var/lib/postgresql/data + networks: + - backend + + web: + image: nginx:1.27-alpine + ports: + - "8080:80" + depends_on: + - db + networks: + - backend + +volumes: + db-data: + +networks: + backend: diff --git a/listings/exercises/ex12-build-inspect/Containerfile b/listings/exercises/ex12-build-inspect/Containerfile new file mode 100644 index 0000000..a5d3b0a --- /dev/null +++ b/listings/exercises/ex12-build-inspect/Containerfile @@ -0,0 +1,2 @@ +FROM docker.io/library/nginx:1.27 +COPY index.html /usr/share/nginx/html/index.html diff --git a/listings/exercises/ex12-build-inspect/docker-compose.yml b/listings/exercises/ex12-build-inspect/docker-compose.yml new file mode 100644 index 0000000..c15fb62 --- /dev/null +++ b/listings/exercises/ex12-build-inspect/docker-compose.yml @@ -0,0 +1,5 @@ +services: + nginx: + build: ./ + ports: + - "80:80" diff --git a/listings/exercises/ex12-build-inspect/index.html b/listings/exercises/ex12-build-inspect/index.html new file mode 100644 index 0000000..de2015e --- /dev/null +++ b/listings/exercises/ex12-build-inspect/index.html @@ -0,0 +1,4 @@ + + DEMO + Nothing to see here! + diff --git a/listings/exercises/ex13-multistage/Containerfile b/listings/exercises/ex13-multistage/Containerfile new file mode 100644 index 0000000..a2c58f6 --- /dev/null +++ b/listings/exercises/ex13-multistage/Containerfile @@ -0,0 +1,8 @@ +FROM golang:1.24-alpine AS build +WORKDIR /src +COPY go.mod main.go . +RUN go build -o /bin/hello . + +FROM scratch +COPY --from=build /bin/hello /bin/hello +CMD ["/bin/hello"] diff --git a/listings/exercises/ex13-multistage/go.mod b/listings/exercises/ex13-multistage/go.mod new file mode 100644 index 0000000..3aade56 --- /dev/null +++ b/listings/exercises/ex13-multistage/go.mod @@ -0,0 +1,3 @@ +module hello + +go 1.24 diff --git a/listings/exercises/ex13-multistage/main.go b/listings/exercises/ex13-multistage/main.go new file mode 100644 index 0000000..635db7a --- /dev/null +++ b/listings/exercises/ex13-multistage/main.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("hello, world") +} diff --git a/listings/exercises/ex14-push/commands.sh b/listings/exercises/ex14-push/commands.sh new file mode 100755 index 0000000..478bab0 --- /dev/null +++ b/listings/exercises/ex14-push/commands.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Exercise 14 — Push image to local registry + +# Tag and push +podman build -t localhost:5000/hello:latest . +# OR tag an existing image: +# podman tag hello:latest localhost:5000/hello:latest + +podman push --tls-verify=false localhost:5000/hello:latest + +# Verify +curl http://localhost:5000/v2/_catalog +curl http://localhost:5000/v2/hello/tags/list diff --git a/listings/exercises/ex15-registry-api/commands.sh b/listings/exercises/ex15-registry-api/commands.sh new file mode 100755 index 0000000..78c27d0 --- /dev/null +++ b/listings/exercises/ex15-registry-api/commands.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Exercise 15 — Query the local registry API + +# List all repositories in the registry +curl http://localhost:5000/v2/_catalog + +# List tags for a specific image +curl http://localhost:5000/v2/hello/tags/list + +# Inspect a specific manifest (optional) +curl http://localhost:5000/v2/hello/manifests/latest \ + -H "Accept: application/vnd.docker.distribution.manifest.v2+json" diff --git a/setup/setup-ubuntu2404.sh b/setup/setup-ubuntu2404.sh new file mode 100755 index 0000000..2532eef --- /dev/null +++ b/setup/setup-ubuntu2404.sh @@ -0,0 +1,150 @@ +#!/bin/bash +# Container Training — Ubuntu 24.04 (Noble) Setup +# Als root oder mit sudo ausführen: sudo bash setup-ubuntu2404.sh + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +ok() { echo -e "${GREEN}[OK]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +fail() { echo -e "${RED}[FEHLER]${NC} $*"; exit 1; } + +[ "$(id -u)" -eq 0 ] || fail "Bitte als root oder mit sudo ausführen." + +# Ubuntu 24.04 prüfen +if [ -f /etc/os-release ]; then + . /etc/os-release + if [ "$ID" != "ubuntu" ] || [ "$VERSION_CODENAME" != "noble" ]; then + warn "Dieses Script ist für Ubuntu 24.04 (Noble) geschrieben — läuft auf: $PRETTY_NAME" + fi +fi + +echo "================================================" +echo " Container-Schulung — Setup (Ubuntu 24.04)" +echo "================================================" +echo "" + +# Trainingsuser ermitteln +TRAINING_USER=${SUDO_USER:-""} +if [ -z "$TRAINING_USER" ]; then + warn "SUDO_USER nicht gesetzt — Linger wird nicht konfiguriert." + warn "Ggf. manuell ausführen: loginctl enable-linger " +fi + +# ------------------------------------------------------- +echo "" +echo "[1/5] Basis-Tools..." +# ------------------------------------------------------- +apt-get update -q +apt-get install -y \ + iputils-ping \ + iproute2 \ + net-tools \ + dnsutils \ + curl \ + wget \ + git \ + vim \ + jq \ + bash-completion +ok "Basis-Tools installiert." + +# ------------------------------------------------------- +echo "" +echo "[2/5] Podman + rootless-Abhängigkeiten..." +# ------------------------------------------------------- +# Ubuntu 24.04 liefert Podman >= 4.9 aus dem universe-Repo — kein Fremdrepo nötig +add-apt-repository -y universe +apt-get update -q +apt-get install -y \ + podman \ + slirp4netns \ + fuse-overlayfs \ + uidmap \ + dbus-user-session \ + systemd-container + +PODMAN_VER=$(podman --version | awk '{print $3}') +PODMAN_MINOR=$(echo "$PODMAN_VER" | cut -d. -f2) +PODMAN_MAJOR=$(echo "$PODMAN_VER" | cut -d. -f1) + +if [ "$PODMAN_MAJOR" -gt 4 ] || { [ "$PODMAN_MAJOR" -eq 4 ] && [ "$PODMAN_MINOR" -ge 4 ]; }; then + ok "Podman $PODMAN_VER — Quadlets werden unterstützt." +else + warn "Podman $PODMAN_VER — Quadlets brauchen >= 4.4! Tag 3 könnte Probleme machen." +fi + +# ------------------------------------------------------- +echo "" +echo "[3/5] Registry-Konfiguration..." +# ------------------------------------------------------- +# Drop-in statt Hauptdatei überschreiben — sauber und updatefest +mkdir -p /etc/containers/registries.conf.d +cat > /etc/containers/registries.conf.d/10-unqualified-search.conf << 'EOF' +# Kurzname-Auflösung: docker.io und quay.io werden automatisch durchsucht +unqualified-search-registries = ['docker.io', 'quay.io'] +EOF +ok "unqualified-search-registries konfiguriert (docker.io, quay.io)." + +# ------------------------------------------------------- +echo "" +echo "[4/5] podman-compose + trivy..." +# ------------------------------------------------------- +apt-get install -y podman-compose 2>/dev/null \ + || pip3 install --quiet podman-compose +ok "podman-compose installiert." + +# trivy +curl -fsSL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \ + | sh -s -- -b /usr/local/bin latest +ok "trivy installiert: $(trivy --version | head -1)" + +# ------------------------------------------------------- +echo "" +echo "[5/5] Benutzer-Setup ($TRAINING_USER)..." +# ------------------------------------------------------- +if [ -n "$TRAINING_USER" ]; then + loginctl enable-linger "$TRAINING_USER" + ok "Linger aktiviert für $TRAINING_USER — systemctl --user überlebt Logout." + + # subuid/subgid für rootless Container + if ! grep -q "^${TRAINING_USER}:" /etc/subuid 2>/dev/null; then + usermod --add-subuids 100000-165535 "$TRAINING_USER" + usermod --add-subgids 100000-165535 "$TRAINING_USER" + ok "subuid/subgid konfiguriert." + else + ok "subuid/subgid bereits vorhanden." + fi + + # podman socket für den User aktivieren (für podman compose) + systemctl enable --now podman.socket 2>/dev/null || true + su - "$TRAINING_USER" -c "systemctl --user enable --now podman.socket" 2>/dev/null || true + ok "Podman socket aktiviert." +else + warn "Kein Trainingsuser — Linger, subuid/subgid und socket übersprungen." +fi + +# ------------------------------------------------------- +echo "" +echo "================================================" +echo " Zusammenfassung" +echo "================================================" +podman --version +podman-compose --version 2>/dev/null | head -1 || true +trivy --version | head -1 +echo "" +echo "Registry-Konfiguration:" +cat /etc/containers/registries.conf.d/10-unqualified-search.conf +echo "" + +if [ -n "$TRAINING_USER" ]; then + echo "Benutzer: $TRAINING_USER" + echo "Linger: $(loginctl show-user "$TRAINING_USER" --property=Linger --value 2>/dev/null || echo 'unbekannt')" +fi + +echo "" +ok "Setup abgeschlossen. Bitte einmal aus- und wieder einloggen."