NGINX: управление конфигурацией прокси

Автор: | 05/03/2016
 

nginx_logoСистема управления прокси-сервером под NGINX на Ubuntu 14.04 в Azure.

Файлы конфигураций бекенд-хостов хранятся в Atlassian Stash, в роли CI/CD сервера выступает GoCD от Hashicorp.

Предназначена для предоставления девелоперам возможности управления конфигурацией хостов в процессе переноса сайтов проекта со старых на новые версии.

  • Репозиторий
  • Скрипты
    • Скрипт backup.sh
    • Скрипт nginx_update.sh
  • GoCD

Репозиторий

Структура репозитория выглядит так:

$ tree azure-proxy/
azure-proxy/
├── conf.d
│   └── domain.tld.conf
├── scripts
│   ├── backup.sh
│   └── nginx_update.sh
└── vhosts-backup
    ├── domain.tld.conf
    └── default
  • conf.d: содержит файлы конфигураций
  • scripts: скрипты для GoCD
  • vhosts-backup: последний бекап предыдущей версии файлов

Скрипты

Скрипт backup.sh

Скрипт backup.sh выполняет копирование файлов с сервера с NGINX в локальный каталог vhosts-backup, после чего — git push с изменениями обратно в хранилище:

azure_proxy_pipeline_6

#!/usr/bin/env bash

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"

HOST="$1"

USER="username"
RSA_KEY=".ssh/service_id"

if [ -e $RSA_KEY ]; then
    chmod 600 $RSA_KEY
else
    echo -e "\nERROR: can not find $RSA_KEY to connect. Exit.\n"
    exit 1
fi

if [ -z $HOST ]; then
    echo -e "\nERROR: HOST name must be specified as first argument. Exit.\n"
    exit 1
fi

echo -e "\n[$me] NGINX backup started.\n"

vhosts_backup () {
    scp -r -o StrictHostKeyChecking=no -i $RSA_KEY $USER@$1:/etc/nginx/conf.d/* vhosts-backup/
}

if vhosts_backup $HOST; then
    git add .
    git status
    git commit -m "$(date +%Y%m%d) NGINX virtualhosts configs backup" || echo "[$me] Nothing to commit!"
    git push origin master
else
    echo -e "\nERROR: something went wrong during SCP. Exit.\n"
    exit 1
fi

echo -e "\n[$me] NGINX backup finished successfully.\n"

Скрипт nginx_update.sh

Второй скрипт — nginx_update.sh:

  • перемещает все имеющиеся на сервере файлы конфигураций в каталог /tmp/nginx_tmp_prev_confd
  • копирует все файлы конфигурации из локального каталога (репозитория) conf.d на сервер в каталог /etc/nginx/conf.d/
  • проверяет их через nginx -t, и:
    • в случае ошибки — удаляет новые файлы, и откатывает файлы из каталога /tmp/nginx_tmp_prev_confd
    • если статус ОК — выполняет nginx reload

Сам скрипт:

#!/usr/bin/env bash

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"

HOST="$1"

USER="username"
RSA_KEY=".ssh/service_id"

NGINX_INIT="/etc/init.d/nginx"
NGINX_BASEDIR="/etc/nginx"

# remote conf.d location
R_CONFD_DIR="$NGINX_BASEDIR/conf.d"

# local conf.d location in repo
L_CONFD_DIR="conf.d"

# tmp fir for curent vhosts
NGINX_PREV_TMP="/tmp/nginx_tmp_prev_confd"

# tmp fir for new vhosts to be copied then to $R_CONFD_DIR
NGINX_NEW_TMP="/tmp/nginx_tmp_new_confd"

if [ -e $RSA_KEY ]; then
    chmod 600 $RSA_KEY
else
    echo -e "\nERROR: can not find $RSA_KEY to connect. Exit.\n"
    exit 1
fi

if [ -z $HOST ]; then
    echo -e "\nERROR: HOST name must be specified as first argument. Exit.\n"
    exit 1
fi

echo -e "\n[$me] NGINX update started.\n"

# Update process:
#    1. vhosts_clean ():
#       a. Create /tmp/nginx_tmp_prev_confd on the remote
#       b. Move ( < !) all current configs from /etc/nginx/conf.d to /tmp/nginx_tmp_prev_confd so they can be rolled back later if any
#    2. vhosts_copy()
#       a. Create /tmp/nginx_tmp_new_confd
#       b. Copy local conf.d directory content to the remote /tmp/nginx_tmp_new_confd
#       c. Copy /tmp/nginx_tmp_new_confd content to /etc/nginx/conf.d
#    3. nginx -t - validate configs syntax
#    4. nginx reload - load new configs

vhosts_clean () {
    ssh -t -t -o StrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c '

        if [ ! -d $NGINX_PREV_TMP ]; then
            mkdir $NGINX_PREV_TMP
        else
            rm -rfv $NGINX_PREV_TMP && mkdir -v $NGINX_PREV_TMP
        fi

        if [ -d $R_CONFD_DIR ]; then

            if sudo mv -v $R_CONFD_DIR/* $NGINX_PREV_TMP/; then
                echo "$R_CONFD_DIR content moved to $NGINX_PREV_TMP"
                echo ""
            else
                echo "ERROR: can not move files from $R_CONFD_DIR to $NGINX_PREV_TMP. Exit."
                exit 1
            fi

        else
            echo "ERROR: can not find $R_CONFD_DIR. Exit."
            exit 1
        fi
    '"
}

vhosts_copy () {

    ssh -t -t -o StrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c '
        if [ -d $NGINX_NEW_TMP ]; then
            rm -rf $NGINX_NEW_TMP && mkdir $NGINX_NEW_TMP
        else
            mkdir $NGINX_NEW_TMP
        fi
    '"
    echo -e "\n$NGINX_NEW_TMP created.\n"

    scp -r -o StrictHostKeyChecking=no -i $RSA_KEY $L_CONFD_DIR/* $USER@$1:$NGINX_NEW_TMP/

    ssh -t -t -o StrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c '
        if [ -d $NGINX_NEW_TMP -a -d $R_CONFD_DIR ]; then
            sudo cp -rv $NGINX_NEW_TMP/* $R_CONFD_DIR/
            echo ""
        else
            echo "ERROR: can not find $NGINX_NEW_TMP or $R_CONFD_DIR. Exit."
            exit 1
        fi
    '"
}

nginx_rollback () {

    echo -e "\n[$me] NGINX rollback started.\n"

    ssh -t -t -o StrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c '
        if [ -d $NGINX_PREV_TMP -a -d $R_CONFD_DIR ]; then
            sudo rm -rfv $R_CONFD_DIR/*
            sudo mv -v $NGINX_PREV_TMP/* $R_CONFD_DIR
            echo ""
            rm -rfv $NGINX_PREV_TMP
            rm -rfv $NGINX_NEW_TMP
            echo ""
        else
            echo "ERROR: can not find $NGINX_PREV_TMP or $R_CONFD_DIR to run NGINX rollback. Exit."
            exit 1
        fi
    '"
}

nginx_check () {
    ssh -t -t -o StrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c '
        if sudo $NGINX_BIN -t; then
            echo ""
            rm -rfv $NGINX_PREV_TMP
            rm -rfv $NGINX_NEW_TMP
            echo ""
        else
            exit 1
        fi
        '"
}

nginx_reload () {
    ssh -t -t -o StrictHostKeyChecking=no -i "$RSA_KEY" "$USER@$1" "bash -c '
        sudo $NGINX_INIT reload
        echo ""
    '"
}

echo -e "[$me] NGINX cleanup started.\n"
if vhosts_clean $HOST; then
    echo -e "\n[$me] $R_CONFD_DIR cleaned up.\n"
else
    echo -e "\n[$me] ERROR: can not clean $R_CONFD_DIR. Exit.\n"
    exit 1
fi

echo -e "[$me] Copy new config files to $HOST.\n"
if vhosts_copy $HOST; then
    echo -e "\n[$me] New configuration files placed.\n"
else
    echo -e "\n[$me] ERROR: during vhosts_copy(). Exit.\n"
    exit 1
fi

echo -e "[$me] Verifying new configuration.\n"
if nginx_check $HOST; then
    nginx_reload $HOST
else
    echo -e "\nERROR: NGINX can not validate new config files. Running NGINX rollback."
    nginx_rollback $HOST && nginx_check $HOST && nginx_reload $HOST
    echo -e "\nNGINX completed successfully but exiting with 1.\n"
    exit 1
fi

GoCD

Пайплайн в GoCD имеет два шага — NGINXbackup и NGINXupdate:

azure_proxy_pipeline_1

На NGINXbackup выполняется скрипт backup.sh, которому первым аргументом передаётся имя прокси-хоста:

azure_proxy_pipeline_3

На NGINXupdate — обновление конфигурации NGINX:

azure_proxy_pipeline_4

И результат работы NGINXupdate:

azure_proxy_pipeline_5