Blue-green миграция сайта между Linux-серверами: старый сервер (blue) обслуживает трафик, новый (green) готовится параллельно и получает запросы в момент переключения. Простой сводится к времени распространения DNS-записи: при TTL 60 секунд это 1-2 минуты, при TTL 300 секунд - до 5 минут. Данные не теряются, потому что база на green догоняет blue через потоковую репликацию, а файлы синхронизируются rsync.
Схема работает и для статики, и для приложений с PostgreSQL. Дальше: подготовка окружения, перенос файлов через rsync, синхронизация базы через pg_dump/pg_restore или pg_basebackup с replication slot, выпуск TLS-сертификата до смены DNS, проверки через /etc/hosts и curl --resolve, порядок переключения трафика и план отката. Три обязательные таблицы: чек-лист до миграции, сравнение blue и green по метрикам, проверки после переключения.
Что такое blue-green миграция и когда она оправдана
Blue-green это схема переезда, при которой инфраструктура существует в двух экземплярах. Blue, текущий продакшен, принимает весь трафик. Green, целевой сервер, поднимается рядом, синхронизирует данные и проходит проверки. Переключение выполняется одной сменой DNS A-записи на IP green. Пока резолверы обновляют кэш, оба сервера отвечают пользователям корректно, потому что данные на них совпадают.
Подход оправдан, когда есть контроль над DNS-зоной, доступ к обоим серверам и возможность держать прод на старом сервере до последнего момента. Второй сервер в этот период стоит денег: при аренде VPS с 4 vCPU, 8 ГБ RAM и 160 ГБ NVMe это обычно 2-5 тысяч рублей в месяц, и переплата длится от нескольких дней до двух недель. Эти расходы дешевле, чем час простоя интернет-магазина с оборотом 300 тысяч рублей в сутки.
Ключевые метрики планирования: RPO (сколько данных допустимо потерять) и RTO (сколько времени сервис может быть недоступен). Для статического сайта RPO равен нулю автоматически, потому что файлы синхронизируются rsync. Для приложения с базой RPO 0 достижим только через потоковую репликацию и promote с нулевым lag.
Чем blue-green отличается от обычного переезда с простоем
Обычный переезд: останавливаем nginx и php-fpm, копируем файлы, снимаем дамп базы, разворачиваем на новом сервере, меняем DNS, запускаем. Простой измеряется десятками минут, при базе в 200 ГБ легко уходит в часы. Заказы, созданные в момент остановки, теряются: приложение уже не принимает данные.
Blue-green переносит тяжёлые операции в подготовительную фазу. Полный rsync на 50 ГБ по каналу 1 Гбит/с занимает 8-12 минут, но выполняется заранее, пока сайт работает. Финальный инкрементальный прогон передаёт только изменившиеся файлы: обычно 50-500 МБ, это секунды или единицы минут. Единственное окно, когда запись останавливается, длится столько, сколько нужно на догон WAL и promote базы: от 2 до 30 секунд при нулевом lag.
Откат отличается ещё сильнее. При обычном переезде после смены DNS вернуться к старому серверу сложно: данные разъехались. При blue-green blue остаётся нетронутым 24-48 часов, и откат это обратная смена A-записи.
Два сценария: статический сайт и приложение с изменяемой БД
Статика: лендинг, документация, сайт на Hugo или Jekyll, файлы под nginx. Переносится в два шага, rsync и DNS. Базы нет, вопроса синхронизации тоже нет. Окно простоя равно нулю: старый сервер отдаёт контент до смены записи, новый сразу после.
Приложение с PostgreSQL сложнее. Файлы переносятся так же, но база живёт своей жизнью: пользователи пишут данные постоянно. Здесь нужен один из двух путей: дамп с краткой остановкой записи или потоковая репликация на основе pg_basebackup и replication slot с последующим promote. Второй путь даёт RPO 0 и окно read-only в секунды. Оба разбираются ниже с командами и критериями выбора.
Чек-лист подготовки к миграции: что сделать до первого rsync
Подготовка занимает больше времени, чем сам перенос. Минимум 48 часов уходит только на снижение TTL. Полный план с разбором стратегий и резервных копий собран в руководстве по миграции серверов от планирования до запуска.
Снижение TTL DNS заранее: почему это делают за сутки
TTL кэшируется резолверами на срок, который был указан в записи на момент запроса. Если A-запись имела TTL 86400 и вы снизили его до 300 в день переключения, часть резолверов будет держать старый IP ещё сутки. Правильный порядок: за 24-48 часов до окна миграции изменить TTL на 60-300 секунд, дождаться истечения старых кэшей, и только потом работать с переключением.
dig +ttl +noall +answer example.com A
dig @1.1.1.1 example.com A +short
dig @8.8.8.8 example.com A +noall +answer
Проверяйте несколько публичных резолверов: 1.1.1.1, 8.8.8.8, 9.9.9.9. Значение TTL в ответе должно уменьшаться по мере истечения кэша. Не забывайте про AAAA-запись: если она указывает на старый сервер, а IPv6 на green не настроен, часть клиентов после переключения получит таймаут.
Подготовка целевого сервера: паритет окружения
Классическая причина падения после переключения: на green стоит php-fpm 8.2, на blue 8.1, или PostgreSQL 16 против 15. Приложение, собранное под старую версию, ломается на новой, и отладка съедает всё окно миграции. Сверьте версии до переноса файлов.
nginx -v
php-fpm -v
psql --version
cat /etc/os-release
systemctl list-units --type=service --state=running
Сравните не только версии, но и конфигурацию: /etc/nginx/nginx.conf, sites-available, php.ini, php-fpm pool, юниты systemd, лимиты в /etc/security/limits.conf, права на /var/www, политики SELinux или AppArmor. На Debian и Ubuntu проверьте getenforce и aa-status. Расхождение по правам даёт 403 на green при полностью рабочем blue.
Firewall: откройте 80 и 443 на green до переключения, иначе после смены DNS сайт не откроется. Проверьте nft list ruleset или ufw status. Синхронизация времени через chrony или systemd-timesyncd нужна для TLS и логов: расхождение в 5 минут ломает проверку сертификатов на стороне клиента.
Если green поднимается в облаке, выбирайте машину с нужным числом vCPU и диском NVMe: Timeweb Cloud даёт серверы, VDS/VPS и базы данных с оплатой за фактические ресурсы, что удобно для двухнедельного переезда без покупки железа.
| Пункт | Зачем | Как проверить |
|---|---|---|
| Инвентаризация сервисов и портов | Не забыть про cron, очереди и второстепенные демоны | ss -tulpn, systemctl list-units |
| Фиксация версий ПО | Паритет ОС, nginx, php-fpm, PostgreSQL | nginx -v, psql --version, cat /etc/os-release |
| Бэкап файлов и базы | Точка возврата, если пострадают оба сервера | pg_dump -Fc, копия на отдельный хост или в объектное хранилище |
| SSH-доступ на green | Работа без пароля, автоматизация rsync | ssh -o BatchMode=yes green 'uptime' |
| Порты 80 и 443 в firewall green | Сайт откроется сразу после смены DNS | nft list ruleset, ufw status |
| Синхронизация времени | Валидность TLS и корректные метки в логах | chronyc tracking, timedatectl |
| Мониторинг на оба сервера | Видеть метрики green до и после переключения | Агент node_exporter, проверка графиков в Grafana или Zabbix |
| План отката | Вернуть трафик за минуты при сбое | Записанный порядок шагов, доступ к DNS-панели у дежурного |
| Окно миграции и уведомление | Согласовать с бизнесом и поддержкой | Письмо стейкхолдерам, дежурный на связи |
| Снижение TTL DNS | Переключение за минуты, а не за сутки | dig +ttl example.com A на нескольких резолверах |
Перенос файлов через rsync: первый прогон и инкрементальная синхронизация
Первый прогон выполняется за дни до переключения, когда нагрузка низкая. Он переносит основной объём данных.
rsync -aHAX --delete --numeric-ids --info=progress2 \
-e "ssh -p 22" \
/var/www/ deploy@green:/var/www/
Флаги: -a сохраняет права, время, владельцев и символические ссылки, -H переносит жёсткие ссылки, -A ACL, -X расширенные атрибуты, --delete удаляет на green файлы, которых нет на blue (важно при удалённых плагинах и старых сборках), --numeric-ids переносит UID/GID числами, что критично при разных наборах пользователей. Ключ --info=progress2 показывает общий прогресс, а не список каждого файла.
Полный перенос 50 ГБ по каналу 1 Гбит/с занимает 8-12 минут. Второй прогон перед переключением идёт по тому же набору флагов и передаёт только разницу. Нагрузку на диск старого сервера ограничивают через --bwlimit=50M при узком канале или ionice -c2 -n7 перед командой. Пример регулярной синхронизации с логом и разбор типичных ошибок есть в статье про перенос данных на новый сервер с минимальным даунтаймом.
Что исключать из синхронизации и почему
/var/www/site/var/cache/
/var/www/site/var/log/
/var/www/site/var/tmp/
/var/www/site/node_modules/
/var/www/site/.git/
*.log
*.pid
*.sock
rsync -aHAX --delete --numeric-ids \
--exclude-from=/root/rsync-exclude.txt \
/var/www/ deploy@green:/var/www/
Кэш и логи генерируются заново, их перенос тратит время и приводит к битым файлам состояния. Каталог node_modules собирается на месте: перенос 300 тысяч мелких файлов по SSH идёт дольше, чем npm ci. Исключение из правила: каталог загрузок пользователей (uploads, media, storage/app/public) переносится всегда, потери там недопустимы.
Проверка целостности после rsync
Сухой прогон показывает, что осталось синхронизировать, и ничего не меняет на диске.
rsync -aHAXn --delete --numeric-ids --itemize-changes \
--exclude-from=/root/rsync-exclude.txt \
/var/www/ deploy@green:/var/www/
Пустой вывод означает полное совпадение. Если строки есть, смотрите на первый символ: > значит файл передаётся на green, d значит удаляется. Дополнительно сравните контрольные суммы критичных файлов.
find /var/www/site/config -type f -exec md5sum {} \; | sort -k2 | md5sum
ssh green "find /var/www/site/config -type f -exec md5sum {} \; | sort -k2 | md5sum"
Проверьте владельца и права на ключевых каталогах: ls -la /var/www/site, stat -c '%U:%G %a' /var/www/site/storage. Разница в правах обычно и даёт 500 после переключения.
Синхронизация PostgreSQL: pg_dump/pg_restore или потоковая репликация
Выбор между двумя подходами определяется объёмом базы и допустимым RPO.
- pg_dump + pg_restore: база до 50-100 ГБ, допустимо окно read-only 5-30 минут, простая настройка.
- Потоковая репликация: база от 100 ГБ, RPO близко к нулю, окно остановки записи секунды, нужны настройка standby, WAL streaming и replication slot.
Вариант 1: pg_dump и pg_restore для небольших баз
pg_dump -Fc -Z6 -f /backup/site_$(date +%F).pgc -U postgres site_db
pg_restore -d site_db -j 4 --no-owner --no-privileges /backup/site_2026-09-11.pgc
Флаг -Fc даёт custom format: сжатие, выборочное восстановление таблиц, параллельный разбор через -j. Текстовый дамп восстанавливается одним потоком и на базе в 40 ГБ может идти часами. Перед финальным дампом приложение переводится в режим read-only: настройкой в админке, флагом в конфиге или командой для базы.
ALTER DATABASE site_db SET default_transaction_read_only = on;
-- после восстановления на green
ALTER DATABASE site_db SET default_transaction_read_only = off;
Проверка после восстановления: число строк в ключевых таблицах, значения sequence, внешние ключи.
SELECT relname, n_live_tup FROM pg_stat_user_tables ORDER BY n_live_tup DESC LIMIT 20;
SELECT last_value FROM orders_id_seq;
SELECT conname FROM pg_constraint WHERE contype='f' AND NOT convalidated;
Sequence это классические грабли: дамп переносит текущее значение, но если после снятия дампа на blue были вставки, на green sequence отстанет и приложение получит duplicate key. После переключения выполните:
SELECT setval('orders_id_seq', (SELECT MAX(id) FROM orders));
Вариант 2: потоковая репликация PostgreSQL на новый сервер
Репликация держит green в актуальном состоянии и позволяет переключиться за секунды. На blue создаётся роль репликации и физический слот.
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strong_password';
SELECT * FROM pg_create_physical_replication_slot('green_slot');
В pg_hba.conf на blue разрешаем подключение replicator с IP green.
host replication replicator 10.0.0.12/32 scram-sha-256
На green база разворачивается из базовой копии.
systemctl stop postgresql
rm -rf /var/lib/postgresql/16/main/*
pg_basebackup -h 10.0.0.10 -D /var/lib/postgresql/16/main \
-U replicator -P -R -X stream -S green_slot
systemctl start postgresql
Флаг -R создаёт standby.signal и прописывает primary_conninfo в postgresql.auto.conf. В postgresql.conf на green проверьте hot_standby = on, тогда база принимает read-only запросы. До promote сервер работает только на чтение: любые INSERT завершатся ошибкой cannot execute INSERT in a read-only transaction.
Контроль replication lag и критерий готовности к переключению
-- на blue
SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes
FROM pg_stat_replication;
-- на green
SELECT pg_last_wal_replay_lsn(), pg_is_in_recovery();
lag_bytes = 0 и state = streaming означают, что green применил все изменения. pg_is_in_recovery() возвращает t, пока база в режиме standby. Переключение выполняйте только при нулевом lag и отсутствии ошибок в логах: journalctl -u postgresql -n 100 --no-pager. Слот репликации нельзя удалять до promote, иначе blue удалит WAL, который ещё не доехал до green, и standby отстанет навсегда.
TLS-сертификат на новом сервере: выпуск и проверка до переключения
Если сертификат выпущен только на blue, после смены DNS браузеры покажут предупреждение: имя не совпадает или цепочка неполная. Сертификат на green нужен до переключения.
DNS-01 challenge: выпуск сертификата без переключения DNS
HTTP-01 challenge требует, чтобы домен уже указывал на green. DNS-01 обходит это ограничение: certbot кладёт TXT-запись _acme-challenge.example.com, и валидация проходит, пока трафик ещё идёт на blue.
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d www.example.com \
--preferred-challenges dns-01
Для Route53 применяется плагин --dns-route53, для других провайдеров есть отдельные плагины или ручной режим --manual с --preferred-challenges dns. Проверьте TXT-запись до истечения валидации.
dig +short TXT _acme-challenge.example.com @1.1.1.1
systemctl list-timers | grep certbot
systemctl status certbot.timer
Тестовый прогон обновления выполняйте с флагом --dry-run, чтобы не потратить лимиты Let's Encrypt на повторные выпуски.
Проверка сертификата и цепочки
openssl s_client -connect 10.0.0.12:443 -servername example.com -showcerts /dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
В SAN должны быть оба имени: example.com и www.example.com. Дата notAfter должна покрывать минимум 30 дней после окна миграции. Проверка через HTTP-клиент по IP green без правки DNS:
curl -vI https://example.com/ --resolve example.com:443:10.0.0.12
Ответ должен содержать HTTP/2 200 и строку с TLS 1.3 или 1.2. HSTS включайте только после успешного переключения: заголовок Strict-Transport-Security браузер запоминает на месяцы, и откат на HTTP станет невозможен для уже обученных клиентов.
Тестирование green-сервера через /etc/hosts и curl --resolve
До смены DNS green нужно проверить так, как его увидит пользователь: с настоящим Host-заголовком, TLS и полным стеком приложения. Полная методика с готовыми скриптами описана в материале про тестирование миграции данных.
Способ 1: правка /etc/hosts на рабочей машине.
echo "10.0.0.12 example.com www.example.com" | sudo tee -a /etc/hosts
curl -I https://example.com/
Способ 2: curl --resolve, без изменения системы. Удобен для скриптов и одновременной проверки с нескольких машин.
curl -sS -o /dev/null -w "%{http_code} %{time_total}\n" \
--resolve example.com:443:10.0.0.12 https://example.com/
Способ 3: временный staging-домен stage.example.com с A-записью на green. Он хорош тем, что позволяет прогнать внешние сервисы: платёжные вебхуки, интеграции по API, проверки uptime-мониторинга.
Список smoke-тестов для статики и для приложения с БД
for u in / /about/ /catalog/ /contacts/ /sitemap.xml /robots.txt /nonexistent-page; do
printf "%s -> " "$u"
curl -s -o /dev/null -w "%{http_code}\n" --resolve example.com:443:10.0.0.12 "https://example.com$u"
done
Ожидаемые коды: 200 для страниц, 404 для несуществующей. Для приложения добавьте вход в личный кабинет, оформление тестового заказа, работу форм, ключевые API-эндпоинты, выгрузку отчёта. Проверьте, что статика (css, js, img) отдаётся с нужными заголовками Cache-Control и Content-Encoding: gzip или br.
Логи после тестов: tail -n 200 /var/log/nginx/error.log и лог приложения. Ноль новых ошибок уровня error это критерий допуска к переключению.
Проверка записи в БД на green до переключения
Standby база не принимает запись. Тестировать INSERT до promote нельзя, вы получите ошибку. Варианты: создать отдельную тестовую базу на green и прогнать сценарии там, либо выполнить promote в тестовом окне, проверить запись и поднять репликацию заново. Второй путь рискован, если blue уже начал писать.
BEGIN;
INSERT INTO smoke_test (note, created_at) VALUES ('green check', now());
SELECT * FROM smoke_test WHERE note = 'green check';
ROLLBACK;
После promote повторите этот блок на рабочей базе и сравните план запроса через EXPLAIN (ANALYZE, BUFFERS) с blue: расхождение по времени выполнения больше чем в 2 раза сигнал о проблемах с индексами или статистикой. Обновите статистику командой ANALYZE VERBOSE.
Сравнение старого и нового серверов по измеримым параметрам
Решение о переключении принимается по цифрам. Снимите метрики с обоих серверов в одинаковых условиях: одна нагрузка, один набор URL, одно время суток.
Как снять метрики с обоих серверов
# latency, 10 прогонов по каждому URL
for i in $(seq 10); do
curl -s -o /dev/null -w "%{http_code} %{time_total}\n" --resolve example.com:443:10.0.0.12 https://example.com/
done
# ресурсы
uptime; free -m; df -h /; iostat -x 1 3
# база
psql -c "SELECT pg_database_size('site_db');"
Error rate считайте из логов nginx за одинаковый интервал: awk '$9 ~ /^5/ {c++} END {print c+0}' /var/log/nginx/access.log. Пропускную способность между клиентом и сервером измерьте через iperf3 -c, конфигурацию CPU и RAM зафиксируйте через lscpu | grep -E 'Model name|CPU\(s\)' и dmidecode -t memory | grep -E 'Size|Speed'.
| Параметр | Blue (старый) | Green (новый) | Критерий готовности |
|---|---|---|---|
| ОС и ядро | Ubuntu 22.04, ядро 5.15 | Ubuntu 24.04, ядро 6.8 | Версия не ниже blue, тесты пройдены |
| nginx | 1.18.0 | 1.24.0 | nginx -t проходит, набор модулей совпадает |
| PostgreSQL | 15.6 | 16.3 | Дамп восстановлен, кодировка и collation те же |
| CPU и RAM | 4 vCPU, 8 ГБ | 8 vCPU, 16 ГБ | Не меньше blue по ядрам и памяти |
| Диск | 160 ГБ SATA, свободно 12 ГБ | 160 ГБ NVMe, свободно 90 ГБ | Свободно минимум 20% и не меньше 20 ГБ |
| Latency p95, главная | 240 мс | 190 мс | Не выше blue более чем на 20% |
| Error rate 5xx за час | 0.02% | 0.00% | Не выше значений blue |
| Replication lag | н/д | 0 байт | Строго 0 перед promote |
| TLS и срок сертификата | TLS 1.2/1.3, 60 дней | TLS 1.2/1.3, 85 дней | Действует минимум 30 дней после окна |
| Воркеры php-fpm | pm.max_children = 20 | pm.max_children = 20 | Значения совпадают или выше |
| Пропускная способность канала | 400 Мбит/с | 900 Мбит/с | Не ниже blue |
| NTP-смещение | +0.002 с | +0.004 с | Меньше 0.1 с |
Если хотя бы один параметр хуже blue, устраните расхождение до переключения. Добавить ресурсы green можно в панели облака за минуты, а разбираться с деградацией на живом трафике придётся в спешке.
Переключение трафика: DNS, promote БД и порядок действий
Порядок шагов зависит от того, есть ли на green пишущая база. Общее правило одно: база должна быть готовой принимать запись раньше, чем DNS начнёт указывать на green.
Порядок для статического сайта
- Финальный инкрементальный rsync, проверка сухим прогоном.
- Перезагрузка nginx на green: nginx -t && systemctl reload nginx.
- Smoke-тесты через curl --resolve по всему списку URL.
- Смена A-записи (и AAAA, если IPv6 поддерживается) на IP green в DNS-панели.
- Проверка резолва через dig @1.1.1.1 example.com и открытие сайта в браузере.
- Откат при проблемах: вернуть A-запись на IP blue. При TTL 60 секунд трафик вернётся за 1-2 минуты.
Порядок для приложения с PostgreSQL
- Убедиться, что lag = 0 и state = streaming в pg_stat_replication.
- Остановить запись на blue: приложение в read-only, фоновые задачи (cron, очереди) на паузе.
- Дождаться, пока реплика применит последний WAL: lag_bytes = 0 повторно.
- Promote на green: pg_ctl promote -D /var/lib/postgresql/16/main или SELECT pg_promote();
- Проверить на green: pg_is_in_recovery() возвращает f, база принимает INSERT.
- Переключить DNS на IP green.
- Снять read-only на green, вернуть фоновые задачи.
- Проверить запись из приложения и данные мониторинга.
Окно read-only в этом сценарии длится от 2 до 30 секунд при нулевом lag. Главная ошибка: переключить DNS до promote. Приложение на green получит read-only базу, и пользователи увидят ошибки записи.
Не удаляйте replication slot и не трогайте blue до завершения проверок: слот нужен для разбора расхождений и для отката.
Проверки после переключения и план отката
Первые 30 минут после смены DNS решают, нужен ли откат. Прогоните проверки из таблицы и зафиксируйте результат. Мониторинг должен видеть green: CPU, RAM, диск, 5xx, latency, состояние базы.
| Проверка | Критерий успеха | Действие при ошибке |
|---|---|---|
| DNS резолвится в новый IP | dig на трёх резолверах отдаёт IP green | Проверить TTL и панель DNS, вернуть старую запись при сбое |
| HTTPS без предупреждений | Браузер показывает замок, SAN совпадает | Перевыпустить сертификат, при сбое переключить обратно |
| Ключевые URL | 200 для главной, каталога, контактов | Проверить логи nginx, откатить DNS на blue |
| Авторизация | Тестовый пользователь входит, сессия сохраняется | Проверить права каталогов сессий и ключи приложения |
| Запись в БД | INSERT проходит, данные читаются | Проверить pg_is_in_recovery и права роли, при сбое вернуть blue |
| Replication lag | Не растёт, ошибок в логах нет | Проверить слот и канал, при откате восстановить репликацию |
| Error rate 5xx | Не выше значений blue | Разобрать top-10 ошибок в access.log |
| Latency p95 | В пределах 20% от blue | Проверить воркеры, кэш, индексы базы |
| Мониторинг | Green виден в дашборде, алерты активны | Переустановить агент, обновить цели в Prometheus |
| Фоновые задачи | Cron и очереди выполняются | Запустить юниты на green, выключить их на blue |
Как откатиться за минуты
Откат для статики: смена A-записи на IP blue. Потери нулевые, потому что контент не менялся. Откат для приложения: сначала вернуть DNS на blue, затем разобраться с базой. Если green уже принял записи, их переносят на blue точечно: pg_dump нужных таблиц или логическая репликация обратно. Поэтому окно read-only сокращают до секунд, а проверку записи делают сразу после promote.
Перед откатом зафиксируйте состояние: SELECT pg_current_wal_lsn() на green, список последних записей в критичных таблицах, вывод journalctl по обоим серверам. Эти данные нужны для разбора причин.
Когда можно выключать старый сервер
Blue остаётся в резерве минимум 24-48 часов: TTL у части резолверов и клиентов может быть больше, и остаточный трафик придёт даже после переключения. Проверьте логи blue: если за последние 6 часов нет запросов, кроме health-check мониторинга, трафик перетёк.
tail -n 1000 /var/log/nginx/access.log | awk '{print $1}' | sort -u | wc -l
Перед выключением снимите финальный бэкап базы и файлов на blue, переведите его в режим без записи, и только потом останавливайте юниты. Держите снимок диска или снапшот минимум неделю: откат через сутки после переключения тоже иногда нужен.
Типичные ошибки и как их избежать
Разбор провалов миграции с чек-листом рисков собран в отдельной статье про риски и скрытые сложности миграции. Ниже конкретика по двум самым болезненным участкам.
Ошибки при работе с PostgreSQL
- Нет replication slot: blue переработал WAL, standby отстал навсегда. Слот создаётся до pg_basebackup.
- Promote без проверки lag: потеря последних транзакций. Ждите lag_bytes = 0.
- Дамп в текстовом формате: восстановление базы 40 ГБ идёт часами. Используйте -Fc и pg_restore -j.
- Забыли про sequence: дубли ключей при первой же вставке. Выполните setval после восстановления.
- Read-only на blue не включён, приложение продолжает писать, часть данных теряется при promote.
- Кодировка и collation: база на green создана с другой локалью, индексы по тексту работают иначе. Сверьте SHOW lc_collate; и SHOW server_encoding;
Ошибки при работе с DNS и TLS
- TTL снижен в день переключения: старые кэши живут сутки, часть пользователей идёт на blue, часть на green.
- Забыли AAAA-запись: IPv6-клиенты получают таймаут. Проверьте dig AAAA example.com.
- Сертификат только на blue: после переключения предупреждение в браузере и падение конверсии.
- HSTS включён до переключения: браузеры запомнили правило, откат на HTTP невозможен.
- Кэш и логи не исключены из rsync: битые файлы состояния и лишние гигабайты.
- Мониторинг не переведён на green: сбой замечают пользователи, а не дежурный.
- Blue выключен через час: остаточный трафик от резолверов с длинным TTL теряется.
Критерий go/no-go простой: lag = 0, доля 5xx не выше blue, все smoke-тесты пройдены, сертификат валиден, план отката под рукой, blue не тронут. Если хотя бы один пункт не выполняется, окно миграции переносится, а не растягивается на живом трафике.