Ik merk steeds vaker dat klanten geen enkele seconde downtime kunnen tolereren tijdens deployments. Een simpele git pull en composer install op de productieserver betekent dat bezoekers even een foutmelding zien, wat bij webshops direct omzetverlies betekent. Blue-green deployment lost dit probleem op door twee identieke productieomgevingen te onderhouden en instant te wisselen tussen de actieve en standby versie.
Nginx upstream configuratie voor blue-green switching
Het hart van deze deployment strategie ligt in nginx upstream configuratie. Ik configureer altijd twee upstream blocks in mijn nginx setup, één voor elke omgeving. De eerste upstream wijst naar de "blue" omgeving op poort 8001, de tweede naar "green" op poort 8002. Beide omgevingen draaien parallel op dezelfde server, maar alleen één ontvangt daadwerkelijk traffic via de load balancer.
upstream app_blue {
server 127.0.0.1:8001;
}
upstream app_green {
server 127.0.0.1:8002;
}
upstream app_active {
server 127.0.0.1:8001;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_active;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
De app_active upstream fungeert als een alias die ik kan wijzigen zonder de hele server configuratie aan te passen. Wanneer ik wil wisselen van blue naar green, pas ik alleen deze upstream aan en herlaad nginx. Dit gebeurt binnen milliseconden zonder dat er connecties verloren gaan.
Laravel applicatie isolatie per omgeving
Elke omgeving heeft zijn eigen volledige Laravel installatie met aparte database en cache configuratie. Ik creëer twee aparte directory's op de server: /var/www/blue en /var/www/green. Beide directories bevatten een complete copy van de applicatie, inclusief eigen .env bestanden met verschillende database namen en cache prefixes.
# Directory structuur
/var/www/blue/
├── app/
├── config/
├── database/
├── .env
└── ...
/var/www/green/
├── app/
├── config/
├── database/
├── .env
└── ...
Voor de database isolatie maak ik aparte databases aan: myapp_blue en myapp_green. Elke omgeving heeft zijn eigen database connectie geconfigureerd in het bijbehorende .env bestand. Cache keys krijgen een prefix zodat Redis data niet conflicteert tussen de omgevingen.
// config/cache.php aanpassing voor blue/green isolatie
'prefix' => env('CACHE_PREFIX', 'myapp_' . env('APP_ENV', 'production')),
Database migraties draai ik altijd eerst op de standby omgeving. Als de actieve omgeving "blue" is, deploy ik nieuwe code naar "green", draai daar de migraties en test de applicatie volledig voordat ik wissel.
Geautomatiseerde deployment pipeline
Mijn deployment script beheert het volledige blue-green proces, van code deployment tot database synchronisatie en nginx switching. Het script detecteert eerst welke omgeving actief is door de nginx configuratie te lezen, waarna het de standby omgeving update met de nieuwe code.
#!/bin/bash
# Detecteer huidige actieve omgeving
CURRENT_ENV=$(grep -oP 'server 127.0.0.1:\K\d+' /etc/nginx/sites-available/myapp | head -1)
if [ "$CURRENT_ENV" == "8001" ]; then
ACTIVE="blue"
STANDBY="green"
NEW_PORT="8002"
else
ACTIVE="green"
STANDBY="blue"
NEW_PORT="8001"
fi
echo "Huidige actieve omgeving: $ACTIVE"
echo "Deploying naar standby omgeving: $STANDBY"
# Update code in standby omgeving
cd /var/www/$STANDBY
git pull origin main
composer install --no-dev --optimize-autoloader
npm ci && npm run build
# Database migraties alleen als nodig
if php artisan migrate:status | grep -q "pending"; then
php artisan migrate --force
fi
# Clear caches
php artisan config:clear
php artisan route:clear
php artisan view:clear
# Health check op standby omgeving
if curl -f "http://127.0.0.1:$NEW_PORT/health" > /dev/null 2>&1; then
echo "Health check geslaagd, switching nginx upstream..."
# Update nginx upstream
sed -i "s/server 127.0.0.1:[0-9]*/server 127.0.0.1:$NEW_PORT/" /etc/nginx/sites-available/myapp
nginx -s reload
echo "Deployment succesvol! $STANDBY is nu actief"
else
echo "Health check gefaald, deployment gestopt"
exit 1
fi
Health checks zijn cruciaal in deze pipeline. Voordat ik nginx vertel naar de nieuwe omgeving te wijzen, test ik of de applicatie daadwerkelijk bereikbaar is en correct reageert. Als de health check faalt, blijft de oude omgeving actief en verlies ik geen traffic.
Database synchronisatie en rollback strategieën
Database synchronisatie tussen blue en green omgevingen vereist zorgvuldige planning, vooral bij backward-incompatible schema wijzigingen. Ik splits complexe migraties altijd op in meerdere deployment rounds. Eerst voeg ik nieuwe kolommen toe als nullable, deploy beide omgevingen, migreer data, en pas daarna maak ik kolommen required of verwijder ik oude kolommen.
// Voorbeeld van backward-compatible migratie
public function up()
{
Schema::table('users', function (Blueprint $table) {
// Nieuwe kolom eerst als nullable
$table->string('new_field')->nullable();
// Index toevoegen voor performance
$table->index('new_field');
});
}
Voor data synchronisatie tussen actieve en standby databases werk ik met read-only replica's waar mogelijk. Als dat niet beschikbaar is, kopieer ik data handmatig vlak voor de switch. Critical transactional data synchroniseer ik real-time via database triggers of applicatie events.
Rollback procedures zijn net zo belangrijk als forward deployment. Wanneer er een probleem ontstaat na de switch, kan ik binnen seconden terug naar de vorige omgeving door de nginx upstream weer om te draaien. Database rollbacks zijn complexer en vereisen backup strategies die ik vooraf test.
De standby omgeving bewaar ik altijd in de staat van de vorige release totdat ik zeker weet dat de nieuwe deployment stabiel draait. Dit geeft me een betrouwbare fallback optie zonder dat ik code hoef terug te draaien of databases moet restoren.
Blue-green deployment met nginx upstream switching heeft mijn deployment stress aanzienlijk verminderd. Klanten merken niets van updates en ik kan complexere releases uitrollen zonder de angst voor downtime. Het vraagt wel meer server resources omdat je twee complete omgevingen draait, maar die investering verdient zichzelf terug in uptime en gebruikerservaring.