ADG Оставить заявку
Блог Системное администрирование 4 мин чтения

CentOS 7 вышел: переносим init.d на systemd unit-файлы в боевых условиях

CentOS 7 официально релизнулся в июле 2014. Рассказываем про перенос init.d-скриптов на systemd units и почему часть cron-обёрток пришлось писать заново.

Контекст момента

CentOS 7 выпущен 7 июля 2014 как бесплатный клон RHEL 7 - первый релиз ветки с systemd вместо SysVinit и XFS по умолчанию

CentOS 7 официально вышел 7 июля. Мы ждали его с января и с июня гоняли release candidate на тестовом стенде, так что момент «ну наконец-то» прошёл тихо - большинство сюрпризов уже были известны. Зато после официального релиза началась настоящая работа: переносить скрипты инициализации на systemd нужно было уже без скидки на «это же RC, там всё временное».

Что с RC-периодом

С июня на стенде жили несколько виртуалок с CentOS 7 RC. Цель была простая: прогнать типовые сервисы из нашего арсенала и выявить то, что не заработает без адаптации. Выявили достаточно.

Общая картина совпала с тем, что видели при тестировании RHEL 7 Beta: systemd принимает старые SysVinit-скрипты через слой совместимости, и многие из них даже работают. Ключевое слово - многие. Те, которые не работали, делились на две категории.

Первая - скрипты с нестандартным exit code. SysVinit на exit code особо не смотрел: главное, что сервис запустился. systemd смотрит внимательно. Скрипт, который на status возвращал 0 независимо от реального состояния сервиса, вёл себя на шестёрке нормально, а на семёрке systemd считал сервис всегда запущенным и никогда не пытался его поднять после падения.

Вторая - cron-обёртки. Это отдельная история, о ней ниже.

Как переносили unit-файлы

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

Базовые переносы прошли быстро. Типичный init.d-скрипт для Java-демона - 80 строк с функциями start(), stop(), status(), кучей проверок и PID_FILE в /var/run/. Аналогичный systemd unit:

[Unit]
Description=App Worker
After=network.target

[Service]
Type=forking
User=appuser
ExecStart=/opt/app/bin/start.sh
ExecStop=/opt/app/bin/stop.sh
PIDFile=/var/run/app.pid
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Компактнее, декларативнее. Restart=on-failure отдельно порадовал: раньше это надо было городить через cron или собственный watchdog, теперь входит в описание юнита. Перезапуск при падении - три строки.

Но это простые случаи. Были и сложнее.

Cron-обёртки: пришлось переписывать

Самая болезненная часть - скрипты, которые запускались через cron и при этом управляли сервисом: проверяли, жив ли процесс, перезапускали если нет, писали в лог. Такой подход накопился исторически - когда нет нормального мониторинга перезапуска на уровне init, люди пишут в cron.

С переходом на systemd такие обёртки нужно не переносить, а выбрасывать. Логику «проверь и перезапусти» берёт на себя systemd - через Restart= и RestartSec=. Если оставить cron-скрипт, который делает /etc/init.d/service restart (или уже systemctl restart), получается два слоя управления процессом, которые иногда конфликтуют.

У одного клиента был такой сценарий: cron каждые 5 минут проверял процесс, systemd при падении перезапускал его быстрее. Cron приходил, видел что процесс жив, уходил. Иногда совпадало: cron дёргал restart в тот момент, когда systemd сам как раз начинал перезапуск после краша - и получали двойной старт. Потратили час, пока разобрались что происходит.

Решение - убрать cron-скрипт, настроить Restart=on-failure в unit-файле, поставить правильный RestartSec и добавить алерт в Zabbix на состояние юнита через systemctl is-active. Мониторинг и рестарт - разные вещи, не надо смешивать в одном cron-скрипте.

XFS и разметка дисков

На новых серверах под CentOS 7 XFS по умолчанию. С этим разобрались ещё на RC: планировать разметку надо сразу правильно, уменьшить XFS-раздел потом нельзя. На виртуалках это терпимо - расширяем через LVM. На физических серверах если ошиблись с размером раздела под данные - больно.

Один момент, на который наступили в RC и запомнили: dump с XFS не работает. Скрипты резервного копирования, которые использовали dump на ext4-разделах, пришлось переводить на xfsdump или rsync. Небольшое изменение, но его легко пропустить при миграции.

Что в итоге

CentOS 7 RC на стенде с мая дал хороший задел - к официальному релизу уже не было паники и неизвестности. Типовые переносы на systemd заняли от получаса до пары часов на сервис, в зависимости от сложности исходного скрипта.

Cron-обёртки для управления сервисами - это технический долг, который при переходе на systemd стал видимым. Хорошо, что стал: убрали несколько конструкций, которые работали «как-то» и никто особо не трогал. Теперь логика рестарта живёт в unit-файле, а мониторинг - в Zabbix, и не пересекаются.

Новые установки под клиентов теперь идут сразу на CentOS 7. Существующие серверы на CentOS 6 трогать не торопимся - до конца поддержки далеко, а мигрировать живой продакшн ради самой миграции смысла нет. Но план перехода для каждого клиентского сервера уже составляем.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.