diff --git a/listings/exercises/ex05-networking/commands.sh b/listings/exercises/ex05-networking/commands.txt old mode 100755 new mode 100644 similarity index 97% rename from listings/exercises/ex05-networking/commands.sh rename to listings/exercises/ex05-networking/commands.txt index 303f210..9c24c00 --- a/listings/exercises/ex05-networking/commands.sh +++ b/listings/exercises/ex05-networking/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 5 — Container Networking podman network create appnet diff --git a/listings/exercises/ex06-bind-mount/commands.sh b/listings/exercises/ex06-bind-mount/commands.txt old mode 100755 new mode 100644 similarity index 97% rename from listings/exercises/ex06-bind-mount/commands.sh rename to listings/exercises/ex06-bind-mount/commands.txt index 39954b4..d42b409 --- a/listings/exercises/ex06-bind-mount/commands.sh +++ b/listings/exercises/ex06-bind-mount/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 6 — Bind Mounts # Terminal 1: write dates to /tmp/output (detached) diff --git a/listings/exercises/ex07-named-volume/commands.sh b/listings/exercises/ex07-named-volume/commands.txt old mode 100755 new mode 100644 similarity index 97% rename from listings/exercises/ex07-named-volume/commands.sh rename to listings/exercises/ex07-named-volume/commands.txt index c637232..3fadbb2 --- a/listings/exercises/ex07-named-volume/commands.sh +++ b/listings/exercises/ex07-named-volume/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 7 — Named Volumes (shared between containers) podman volume create pizza diff --git a/listings/exercises/ex08-persistence/commands.sh b/listings/exercises/ex08-persistence/commands.txt old mode 100755 new mode 100644 similarity index 97% rename from listings/exercises/ex08-persistence/commands.sh rename to listings/exercises/ex08-persistence/commands.txt index 9a06c55..7ef4609 --- a/listings/exercises/ex08-persistence/commands.sh +++ b/listings/exercises/ex08-persistence/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 8 — Volume Persistence (data survives container removal) podman volume create pasta diff --git a/listings/exercises/ex09-env-variables/commands.sh b/listings/exercises/ex09-env-variables/commands.txt old mode 100755 new mode 100644 similarity index 97% rename from listings/exercises/ex09-env-variables/commands.sh rename to listings/exercises/ex09-env-variables/commands.txt index 835bac7..fa90f77 --- a/listings/exercises/ex09-env-variables/commands.sh +++ b/listings/exercises/ex09-env-variables/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 9 — Environment Variables # Single variables via -e diff --git a/listings/exercises/ex13-multistage/commands.sh b/listings/exercises/ex13-multistage/commands.txt old mode 100755 new mode 100644 similarity index 93% rename from listings/exercises/ex13-multistage/commands.sh rename to listings/exercises/ex13-multistage/commands.txt index d72e272..8dfe0b4 --- a/listings/exercises/ex13-multistage/commands.sh +++ b/listings/exercises/ex13-multistage/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 13 — Multi-stage Build # Build diff --git a/listings/exercises/ex14-push/commands.sh b/listings/exercises/ex14-push/commands.txt old mode 100755 new mode 100644 similarity index 96% rename from listings/exercises/ex14-push/commands.sh rename to listings/exercises/ex14-push/commands.txt index 478bab0..47a44c7 --- a/listings/exercises/ex14-push/commands.sh +++ b/listings/exercises/ex14-push/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 14 — Push image to local registry # Tag and push diff --git a/listings/exercises/ex15-registry-api/commands.sh b/listings/exercises/ex15-registry-api/commands.txt old mode 100755 new mode 100644 similarity index 96% rename from listings/exercises/ex15-registry-api/commands.sh rename to listings/exercises/ex15-registry-api/commands.txt index 78c27d0..b1c7119 --- a/listings/exercises/ex15-registry-api/commands.sh +++ b/listings/exercises/ex15-registry-api/commands.txt @@ -1,4 +1,3 @@ -#!/bin/bash # Exercise 15 — Query the local registry API # List all repositories in the registry diff --git a/listings/exercises/ex16-local-registry/commands.txt b/listings/exercises/ex16-local-registry/commands.txt new file mode 100644 index 0000000..bd77409 --- /dev/null +++ b/listings/exercises/ex16-local-registry/commands.txt @@ -0,0 +1,19 @@ +# Exercise 16 — Start a local registry and push the VisitCounter + +# Start the registry container +podman run -d --name local-registry -p 5000:5000 registry:2 + +# Build the VisitCounter image +cd listings/visitcounter/app +podman build -t localhost:5000/visitcounter:latest . + +# Push to the local registry +podman push --tls-verify=false localhost:5000/visitcounter:latest + +# Verify: list all repositories +curl http://localhost:5000/v2/_catalog +# → {"repositories":["visitcounter"]} + +# Verify: list tags +curl http://localhost:5000/v2/visitcounter/tags/list +# → {"name":"visitcounter","tags":["latest"]} diff --git a/listings/exercises/ex17-update-cycle/commands.txt b/listings/exercises/ex17-update-cycle/commands.txt new file mode 100644 index 0000000..43e76b2 --- /dev/null +++ b/listings/exercises/ex17-update-cycle/commands.txt @@ -0,0 +1,18 @@ +# Exercise 17 — Full update cycle (edit → build → push → restart) + +# 1. Change the page title in main.go +sed -i 's|

VisitCounter

|

My Counter

|' \ + listings/visitcounter/app/main.go + +# 2. Rebuild +cd listings/visitcounter/app +podman build -t localhost:5000/visitcounter:latest . + +# 3. Push +podman push --tls-verify=false localhost:5000/visitcounter:latest + +# 4. Restart the Quadlet service +systemctl --user restart visitcounter-app.service + +# 5. Verify — new title should appear +curl localhost:8080 diff --git a/listings/exercises/ex18-quadlets/commands.txt b/listings/exercises/ex18-quadlets/commands.txt new file mode 100644 index 0000000..40d72c5 --- /dev/null +++ b/listings/exercises/ex18-quadlets/commands.txt @@ -0,0 +1,31 @@ +# Exercise 18 — Deploy VisitCounter via Quadlets + +# Create the Quadlet directory +mkdir -p ~/.config/containers/systemd/ + +# Copy all Quadlet unit files +cp listings/visitcounter/quadlets/* ~/.config/containers/systemd/ + +# Reload systemd to pick up the new units +systemctl --user daemon-reload + +# Check that units were generated +systemctl --user list-unit-files | grep visitcounter +# → visitcounter-app.service generated +# → visitcounter-db.service generated +# → visitcounter-proxy.service generated + +# Start only the proxy — systemd resolves After= dependencies automatically +systemctl --user start visitcounter-proxy.service + +# Verify all three services are running +systemctl --user status visitcounter-db.service +systemctl --user status visitcounter-app.service +systemctl --user status visitcounter-proxy.service + +# Test +curl localhost:8080 + +# Bonus: kill the app container and watch systemd restart it +podman stop systemd-visitcounter-app +systemctl --user status visitcounter-app.service diff --git a/listings/exercises/ex19-harden/commands.txt b/listings/exercises/ex19-harden/commands.txt new file mode 100644 index 0000000..5935680 --- /dev/null +++ b/listings/exercises/ex19-harden/commands.txt @@ -0,0 +1,64 @@ +# Exercise 19 — Harden a container step by step + +# Baseline — works fine +podman run -d --name insecure -p 8080:80 nginx:1.27 +curl localhost:8080 +podman rm -f insecure + +# Step 1: read-only filesystem +podman run -d --name step1 -p 8080:80 --read-only nginx:1.27 +podman logs step1 +# → fails: mkdir /var/cache/nginx/client_temp: Read-only file system +podman rm -f step1 + +podman run -d --name step1 -p 8080:80 \ + --read-only \ + --tmpfs /var/cache/nginx \ + --tmpfs /var/run \ + nginx:1.27 +curl localhost:8080 +podman rm -f step1 + +# Step 2: no-new-privileges +podman run -d --name step2 -p 8080:80 \ + --read-only \ + --tmpfs /var/cache/nginx \ + --tmpfs /var/run \ + --security-opt no-new-privileges \ + nginx:1.27 +curl localhost:8080 +podman rm -f step2 + +# Step 3: drop all capabilities +podman run -d --name step3 -p 8080:80 \ + --read-only \ + --tmpfs /var/cache/nginx \ + --tmpfs /var/run \ + --security-opt no-new-privileges \ + --cap-drop ALL \ + nginx:1.27 +podman logs step3 +# → fails: bind() to 0.0.0.0:80 failed (13: Permission denied) +podman rm -f step3 + +# Step 4: add back only what nginx needs +podman run -d --name secure -p 8080:80 \ + --read-only \ + --tmpfs /var/cache/nginx \ + --tmpfs /var/run \ + --security-opt no-new-privileges \ + --cap-drop ALL \ + --cap-add CHOWN \ + --cap-add SETUID \ + --cap-add SETGID \ + --cap-add NET_BIND_SERVICE \ + nginx:1.27 + +curl localhost:8080 +# → 200 OK + +# Inspect the final capability set +podman inspect secure \ + --format 'Add: {{.HostConfig.CapAdd}} Drop: {{.HostConfig.CapDrop}}' + +podman rm -f secure