vcard4reseller/deploy/terraform/cloud-init-app.yaml.tftpl
Thomas Peterson 03355f89f3 Deploy-Fix: composer install + privates NIC im cloud-init
Zwei Bugs, die den ersten Live-Deploy lahmlegten:
1. composer install fehlte → vendor/ (gitignored, /app gemountet) fehlte →
   Symfony bootete nicht (autoload_runtime.php missing), Migrationen/Seed
   fielen durch. Jetzt: composer install --no-dev im php-Container nach up.
2. Hetzner-Privatnetz-NIC kam auf einem Node nicht hoch → DB unerreichbar
   (/health degraded). Jetzt: privates Interface defensiv per DHCP hochziehen
   und auf 10.x-IP warten, bevor migriert wird.

Manuell auf den Live-Nodes bereits nachgezogen; dieser Fix macht Re-Deploys
reproduzierbar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 18:43:45 +02:00

80 lines
3.6 KiB
Plaintext

#cloud-config
package_update: true
write_files:
- path: /opt/secrets/.env.prod.local
permissions: '0600'
content: |
APP_ENV=prod
APP_DEBUG=0
APP_SECRET=${app_secret}
APP_PORTAL_DOMAIN=${domain}
DATABASE_URL="${database_url}"
CORS_ALLOW_ORIGIN=${cors_allow_origin}
TRUSTED_PROXIES=10.0.0.0/16
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=${jwt_passphrase}
S3_ENDPOINT=${s3_endpoint}
S3_REGION=${s3_region}
S3_BUCKET=${s3_bucket}
S3_KEY=${s3_key}
S3_SECRET=${s3_secret}
S3_PATH_STYLE=true
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
- path: /opt/secrets/private.pem.b64
permissions: '0600'
content: ${base64encode(jwt_private_key)}
- path: /opt/secrets/public.pem.b64
permissions: '0644'
content: ${base64encode(jwt_public_key)}
- path: /opt/secrets/deploy.vars
permissions: '0600'
content: |
REPO_URL=${repo_url}
REPO_BRANCH=${repo_branch}
DOMAIN=${domain}
RUN_MIGRATIONS=${run_migrations}
- path: /opt/deploy.sh
permissions: '0755'
content: |
#!/usr/bin/env bash
set -euo pipefail
. /opt/secrets/deploy.vars
export DEBIAN_FRONTEND=noninteractive
command -v docker >/dev/null 2>&1 || curl -fsSL https://get.docker.com | sh
apt-get update && apt-get install -y git
rm -rf /opt/vcard4
git clone --branch "$REPO_BRANCH" --depth 1 "$REPO_URL" /opt/vcard4
cd /opt/vcard4
cp /opt/secrets/.env.prod.local backend/.env.prod.local
mkdir -p backend/config/jwt
base64 -d /opt/secrets/private.pem.b64 > backend/config/jwt/private.pem
base64 -d /opt/secrets/public.pem.b64 > backend/config/jwt/public.pem
chmod 640 backend/config/jwt/private.pem
# SPA bauen (Profil-/QR-Links zeigen auf die öffentliche Domain)
docker run --rm -e VITE_PUBLIC_BASE="https://$DOMAIN" -v "$PWD/frontend":/app -w /app node:25-alpine sh -c "npm ci && npm run build"
chown -R 1000:1000 /opt/vcard4
# Hetzner-Privatnetz-NIC (nicht eth0) sicher per DHCP hochziehen (für DB-Zugriff).
# Manchmal kommt das private Interface beim ersten Boot nicht hoch → DB unerreichbar.
PRIV=$(ls /sys/class/net | grep -E '^(enp|ens)' | grep -v '^eth0$' | head -1 || true)
if [ -n "${PRIV:-}" ] && ! ip -4 addr show "$PRIV" | grep -q 'inet 10\.'; then
printf '[Match]\nName=%s\n[Network]\nDHCP=ipv4\n' "$PRIV" > "/etc/systemd/network/10-$PRIV.network"
ip link set "$PRIV" up || true
systemctl restart systemd-networkd || true
for i in $(seq 1 30); do ip -4 addr | grep -q 'inet 10\.' && break; sleep 2; done
fi
COMPOSE="docker compose --project-directory /opt/vcard4 -f deploy/compose/docker-compose.prod.yml"
$COMPOSE up -d --build
sleep 20
# PHP-Abhängigkeiten installieren: vendor/ ist gitignored und /app ist als Volume
# gemountet (überdeckt ein im Image gebautes vendor) → hier in den Container hinein.
$COMPOSE exec -T -e COMPOSER_HOME=/tmp/composer php composer install --no-dev --optimize-autoloader --no-interaction --no-scripts
if [ "$RUN_MIGRATIONS" = "true" ]; then
$COMPOSE exec -T php php bin/console doctrine:migrations:migrate --no-interaction || true
# Erst-Befüllung (idempotent: überspringt, wenn admin@vcard4reseller.de existiert)
$COMPOSE exec -T php php bin/console app:seed || true
fi
$COMPOSE exec -T php php bin/console cache:clear || true
runcmd:
- bash /opt/deploy.sh > /var/log/vcard4-deploy.log 2>&1