nginx Blue Green deployment workflow

Here’s how it works:

  1. No Deployment has happened (mark blue as version to assign to the next deployment)
  2. V1 is deployed to blue and will be marked as active if it responds to a call to the version endpoint
    • deploy
    • check version endpoint
    • create /opt/myapp/canary/blue
  3. V2 is deployed to green and will be marked active if it responds to a call to its version endpoint
    • deploy
    • check version endpoint
    • delete /opt/myapp/canary/blue
    • create /opt/myapp/canary/green

Upstream (Target Groups)

upstream blue-app {
  include /etc/nginx/upstream-blue.conf;
  keepalive 256;
}

upstream green-app {
  include /etc/nginx/upstream-green.conf;
  keepalive 256;
}

server {
  listen 80;

  location / {
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    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-Host $host;
    proxy_set_header X-Forwarded-Server $host;

    if (-e /etc/nginx/switch/blue) {
      proxy_pass http://blue-app;
    }

    if (-e /etc/nginx/switch/green) {
      proxy_pass http://green-app;
    }
  }
}

/etc/nginx/upstream-blue.conf:

server 172.16.40.73:9080

/etc/nginx/upstream-green.conf:

server 172.16.40.73:9080

switchDeploy.sh

#!/bin/bash
##########################################
# Cfg
blue="/etc/nginx/sites-enabled/blue"
green="/etc/nginx/sites-enabled/green"

# Functions
reloadNg (){
  systemctl reload nginx
}

switch2Green () {
  echo "Switching to: green"
  rm -rf $blue
  ln -s /etc/nginx/sites-available/green $green
  reloadNg
  exit 0
}

switch2Blue () {
  echo "Switching to: blue"
  rm -rf $green
  ln -s /etc/nginx/sites-available/blue $blue
  reloadNg
  exit 0
}

findActive () {
  if [ -L $blue ]; then
    echo "ActiveSite:blue"
    switch2Green
  fi

  if [ -L $green ]; then
    echo "ActiveSite:green"
    switch2Blue
  fi

  echo "No active site!"
  switch2Blue
}

# Now some action
findActive

docker-compose.yml

version: '3.5'

services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./data/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./data/conf.d/etc/nginx/conf.d/:ro
  app1:
    image: containous/whoami
  app2:
    image: containous/whoami