Перейти к основному содержимому

Maintenance-режим в Nginx

·509 слов·3 минут
Работа
Юрий Семеньков
Автор
Юрий Семеньков
DevOps, tech, geek, mentor
Оглавление
This post is also available in English.

Что это такое?
#

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

Сейчас мы умеем раздавать определенную html-страничку вместо стандартной страницы ошибки.

Например вместо дефолтной 504 ошибки мы можем отдавать красивую страницу с логотипом компании и вежливой понятной фразой вроде “Сейчас сервис недоступен, мы уже знаем о проблеме, попробуйте через минутку”.

error_page 500 501 503 502 504 /static/errors/5xx.html

А что если мы знаем, что сегодня с 20 вечера будут проводиться работы, которые повлекут даунтайм сервиса. Включим maintenance-режим с информацией о проводимых работах, сроке завершения.

Вторая ситуация: сервис жестко упал, инженеры решают инцедент, а клиенты в это время видят то 500-ки, то 503, то 504-ки, то таймауты. Включим maintenance-режим и всем будет спокойнее.

Неудачная попытка
#

Первое что нашлось в интернете на эту тему: через if проверяйте наличие файла на сервере (например /etc/nginx/maintenance.flag), если файл есть - отдаем страницу, если нет - идем по стандартному nginx-конфигу. Что-то типа такого:

server {
  	....
  	error_page 503 /maintenance.html;
	
  	location = /maintenance.html {
  	    root /etc/nginx/maintenance/;
  	    internal;
  	}
	
  	location / {
  	  if (-f /etc/nginx/maintenance.flag) {
  	     return 503;
  	  }
  	  proxy_pass http://127.0.0.1:3000;
  	}
}

Это вполне рабочий вариант, но здесь наличие файла проверяется на КАЖДЫЙ запрос. Это может быть ресурсозатратным. На dev-стенде всё прошло хорошо, а на проде начало вызывать тормоза.

Почему return 503?
#

Почему нужно возвращать клиенту 503 код ответа, несмотря на то, что мы отдаем живую работающую html-страницу?

503 код обычно означает, что сервис временно недоступен, там проводятся работы или он перегружен. Подробнее.

503 код ответа не индексируется поисковиками. Представь, если робот гугла в момент даунтайма спарсит страницу твоего проекта и запишет у себя “Under maintenance”.

Так же клиентским браузерам надо запрещать кэшировать такие страницы, чтобы после завершения даунтайма пользователь не ходил на maintenance-страничку из кэша.

Как можно сделать через include конфигурации?
#

Общая логика такая:

  • у нас есть файл maintenance_on.conf в котором одна строка: return 503;
  • по необходимости исклюдим этот файл в нужные locations череш include maintenance_on.conf
  • мягко рестартим Nginx (через reload)

Теперь подробности реализации:

  • Создаем директорию, чтобы не было мусора: mkdir /etc/nginx/maintenance
  • В нее кладем нашу maintenance.html страничку. Навайбкодьте…
  • Создаем конфиг-файл maintenance_on.conf:
return 503;
  • Создаем пустой конфиг-файл maintenance_off.conf
  • Создаем симлинк maintenance_current.conf
ln -sfn /etc/nginx/maintenance/maintenance_off.conf /etc/nginx/maintenance/maintenance_current.conf

Нужно добавить немного строк в nginx-конфиг в блок server:

server {
		...
    error_page 503 /maintenance.html;

    location = /maintenance.html {
        internal;
        root /etc/nginx/maintenance/maintenance.html;
        add_header Cache-Control "no-store" always;
        add_header Retry-After "3600" always;
    }

    location / {
        include /etc/nginx/maintenance/maintenance_current.conf;
        ...
    }
}

Что здесь происходит:

  • Мы говорим, чтобы Nginx редиректил на /maintenance.html при 503 ошибке
  • Настраиваем локейшен /maintenance.html, который отвечает за раздачу нашей сервисной странички. internal нужен, чтобы клиент не мог вообще никак запросить /maintenance_on.conf или любой другой файл.
  • Добавляем заголовки, чтобы клиентский браузер не кэшировал страничку, а также Retry-After.
  • В основной location (или в любой другой) добавляем include нашего симлинка.

Таким образом, чтобы включить maintenance-режим нам нужно только поменять симлинк и мягко перезапустить Nginx:

ln -sfn /etc/nginx/maintenance/maintenance_on.conf /etc/nginx/maintenance/maintenance_current.conf
nginx -t && systemctl reload nginx

Для выключения создаем линк на _off-файл и опять перезапускаем Nginx.

Как автоматизировать - сами придумайте.

Related

Sentry сожрал все место на диске
·770 слов·4 минут
Работа
Как я использую Ansible для управления инфраструктурой?
·1151 слово·6 минут
Работа Ansible
Настройка ansible.cfg. Зачем и как?
·364 слов·2 минут
Работа