linux-cli-shell automation deployment scripting git nginx ci-cd

Lab: Deployment & Infrastructure Scripts (Artikel 297)

Entwicklung von Deployment-Skripten für moderne Web-Applikationen. Erfahren Sie alles über atomare Verzeichniswechsel via Symlinks und das automatisierte Ausrollen von Code.

# Deployment Lab: Automatisches Ausrollen ohne Downtime

TL;DR / Management Summary Wer Code händisch via FTP auf einen Server lädt, lebt im letzten Jahrzehnt. Ein Senior Admin nutzt Deployment-Skripte, die den Code aus Git ziehen, Abhängigkeiten installieren und Dienste neu starten. In diesem Lab bauen wir ein Blue-Green-Deployment Skript: Wir laden den neuen Code in ein separates Verzeichnis und schalten erst bei Erfolg mittels eines Symlinks blitzschnell um. Das Ergebnis: Null-Sekunden Downtime und ein sofortiges Rollback-Szenario.


Atomarer Austausch.

Anstatt Dateien im laufenden Verzeichnis (/var/www/html) zu überschreiben, arbeiten wir mit Versionen.

graph TD
    A[Git Push / Trigger] --> B[Clone into /apps/releases/v2]
    B --> C[Run Tests / Install Deps]
    C -->|Success| D[Atomic Switch: ln -sfn v2 current]
    C -->|Failure| E[Abort & Keep v1 active]
    D --> F[Reload Nginx/PHP-FPM]
    subgraph "Filesystem"
        G[current link] --> H[v1]
        G -.-> I[v2]
    end

# 2. Das Skript: deploy_app.sh

Sicherer Rollout.

#!/bin/bash
set -euo pipefail

# --- 1. CONFIGURATION ---
readonly APP_NAME="my-web-app"
readonly BASE_DIR="/opt/apps/${APP_NAME}"
readonly RELEASES_DIR="${BASE_DIR}/releases"
readonly CURRENT_LINK="${BASE_DIR}/current"
readonly TIMESTAMP=$(date +%Y%m%d_%H%M%S)
readonly REPO_URL="https://github.com/company/myapp.git"

# --- 2. PREPARATION ---
log() { echo "[$(date +'%F %T')] $*"; }

mkdir -p "$RELEASES_DIR"
NEW_RELEASE="${RELEASES_DIR}/${TIMESTAMP}"

# --- 3. THE WORKFLOW ---

log "INFO: Cloning latest code..."
git clone --depth 1 "$REPO_URL" "$NEW_RELEASE"

log "INFO: Installing dependencies (npm/pip)..."
# cd "$NEW_RELEASE" && npm install --production

log "INFO: Performing Atomic Switch..."
# -s: symbolic, -f: force, -n: treat link as file (no nesting)
ln -sfn "$NEW_RELEASE" "$CURRENT_LINK"

log "INFO: Reloading services..."
sudo systemctl reload nginx

# --- 4. CLEANUP ---
log "INFO: Keeping only last 5 releases..."
cd "$RELEASES_DIR" && ls -1t | tail -n +6 | xargs -d '\n' rm -rf --

log "SUCCESS: Deployment finished."

# 3. Integration in Nginx

Den Link nutzen.

Konfigurieren Sie Ihren Webserver so, dass er auf das current Verzeichnis zeigt:

server {
    listen 80;
    root /opt/apps/my-web-app/current/public;
    # ...
}

# 4. Day-2 Operations: Rollback

Zurück zur letzten stabilen Version.

Wenn die neue Version Bugs enthält, ist der Weg zurück extrem einfach:

# Zeige alle Versionen
ls -lh /opt/apps/my-web-app/releases/

# Schalte manuell zurück
ln -sfn /opt/apps/my-web-app/releases/20231025_120000 /opt/apps/my-web-app/current
sudo systemctl reload nginx

# 5. Troubleshooting & “War Stories”

Wenn der Link ins Leere zeigt.

# Story 1: “Der hängende Root-Service”

Symptom: Das Skript bricht beim Symlink-Wechsel ab, weil der Admin-User keine Schreibrechte im /opt/apps Verzeichnis hat. Ursache: Fehlende Sudoers-Konfiguration (Artikel 288). Lösung: Erlauben Sie dem Deployment-User (deploy-bot) das Ausführen von ln und systemctl reload ohne Passwort.

# Story 2: “Das Cache-Dilemma”

Symptom: Der Symlink wurde gewechselt, aber die Webseite zeigt noch den alten Inhalt. Ursache: Der PHP-OpCache (Artikel 031) hat die alten Dateien noch im RAM und bemerkt den Symlink-Wechsel nicht sofort. Lösung: Fügen Sie sudo systemctl reload php8.1-fpm zum Skript hinzu oder nutzen Sie ein Tool wie cachetool, um den OpCache gezielt zu flushen.


# 6. Fazit & Empfehlung

  • Atomarität: Nutzen Sie ln -sfn. Es ist ein atomarer System-Call auf Kernel-Ebene. Es gibt keinen Moment, in dem der Link nicht existiert.
  • Wartung: Begrenzen Sie die Anzahl der Releases (Cleanup), um die Disk nicht zu füllen.
  • Wahl: Für sehr komplexe Stacks (Kubernetes, hunderte Microservices) nutzen Sie GitOps Tools wie ArgoCD. Für klassische VMs ist dieses Skript unschlagbar.

# Anhang: Cheatsheet

Aufgabe Befehl
Atomarer Link-Wechsel ln -sfn <target> <link>
Repo ohne Historie git clone --depth 1
Verzeichnisse sortieren ls -1t (Neu nach alt)
Letzte X behalten `tail -n +6
Link Ziel prüfen readlink -f <link>
Permissions fixen chown -R www-data:www-data ...