CentOS 7.2: обновили 60 серверов через Ansible и не зашли ни на один руками
RHEL 7.2 вышел с улучшенной поддержкой контейнеров и atomic host. Обновили парк из 60 хостов на CentOS 7.2 через Ansible - два часа вместо двух дней ручной работы.
Red Hat выпустил RHEL 7.2 с улучшенной поддержкой контейнеров, SELinux и Atomic Host; CentOS 7.2 последовал за ним
На прошлой неделе Red Hat выпустил RHEL 7.2, CentOS-команда подтянулась буквально через пару дней. Для нас это было не просто событие в RSS-ленте - под управлением есть парк серверов клиентов на сопровождении, и вопрос «когда обновлять» сразу превращается в вопрос «как обновлять».
Ответ оказался простым: запустили Ansible-плейбук, выпили кофе, через два часа всё готово. Ни одного ручного входа на сервер.
Что нового в 7.2
RHEL 7.2 - не революция, но заметный шаг. Главные изменения, которые нас интересуют:
Контейнеры и Atomic Host. Red Hat серьёзно вкладывается в тему: улучшена поддержка Docker, появился нормальный atomic CLI для управления образами на Atomic Host, доработан docker-storage-setup. Для тех кто уже смотрит в сторону Docker и Swarm - изменения ощутимые.
SELinux. Добавлены новые политики, улучшена поддержка контейнерных контекстов. На практике это означает что Docker с SELinux в enforcing стал вести себя предсказуемее.
Производительность сети. Несколько патчей в стек TCP/IP и улучшения в NUMA-планировщике. На нагруженных серверах может быть заметно.
Systemd 219. Относительно небольшое обновление, но фиксит несколько неприятных edge case с зависимостями сервисов при загрузке.
Для обычного парка серверов без экзотики - стандартное накопительное обновление. Ничего что требовало бы откладывать.
Как обновляли: плейбук вместо ssh-марафона
Год назад - и даже полгода назад - процедура обновления ОС на клиентском парке выглядела примерно так: список хостов в таблице, инженер садится, по одному заходит на каждый сервер, делает yum update, проверяет сервисы, снимает галочку в таблице. При парке в 60 хостов это два рабочих дня. Нудных, монотонных, с высоким риском пропустить хост или забыть проверить какой-нибудь сервис после перезагрузки.
После того как перестроили провизионинг на Ansible-роли, картина изменилась. У нас уже был плейбук для базового обслуживания хостов. Для 7.2 дописали отдельный update.yml:
- name: CentOS 7.2 update
hosts: centos7
serial: 10
tasks:
- name: обновить все пакеты
yum:
name: "*"
state: latest
register: yum_result
- name: проверить нужна ли перезагрузка
command: needs-restarting -r
register: needs_restart
ignore_errors: yes
changed_when: false
- name: перезагрузить если нужно
command: shutdown -r now
async: 1
poll: 0
when: needs_restart.rc == 1
- name: подождать пока сервер поднимется
wait_for:
host: "{{ inventory_hostname }}"
port: 22
delay: 15
timeout: 300
state: started
delegate_to: localhost
when: needs_restart.rc == 1
- name: убедиться что сервисы запущены
command: "systemctl is-active {{ item }}"
register: svc_check
failed_when: svc_check.rc != 0
with_items: "{{ critical_services }}"
when: critical_services is defined
serial: 10 означает что обновляем по десять серверов за раз - не гоним всё одновременно, но и не ждём пока каждый перезагрузится по очереди. critical_services - список через group_vars, у каждой группы хостов свой: у веб-серверов там nginx и php-fpm, у баз данных - postgresql или mariadb.
Запустили около 11 утра. К часу дня 60 хостов были на 7.2, все критичные сервисы поднялись, ни один хост не завис на перезагрузке.
Где всё-таки пришлось вмешаться
Было два хоста где автоматика встала.
На одном стояло несколько пакетов из стороннего репозитория, несовместимых с новыми зависимостями. Ansible корректно упал с ошибкой, хост остался на 7.1. Зашли руками, разобрались с конфликтом, обновили отдельно. Хорошо что serial изолирует проблему - остальные 58 хостов это не затронуло.
На втором хосте кастомный initrd без поддержки нового формата device-mapper. Снова ошибка, снова ручной вход, снова отдельное решение. Оба случая - не баги в плейбуке, а реальные проблемы на конкретных хостах, которые нужно было решать руками при любом подходе к обновлению. Разница в том что раньше мы бы обнаружили их в середине двухдневного марафона, а сейчас - в первые двадцать минут.
Наблюдение
Автоматизация обновлений - не про то чтобы «освободить руки». Она про то чтобы сделать процесс воспроизводимым и наблюдаемым. Когда 60 хостов обновляет инженер руками, у тебя нет никакой гарантии что каждый из них прошёл через одну и ту же процедуру. Где-то забыл проверить сервис, где-то пропустил хост из списка, где-то сделал yum update пока кто-то там что-то деплоил.
Плейбук делает одно и то же на каждом хосте. Если что-то пошло не так - он останавливается и говорит где именно. Не надо гадать.
При этом плейбук не пишется за один вечер. Наш дошёл до нынешнего состояния через несколько обновлений, через несколько случаев когда что-то шло не так и мы добавляли проверки. Два первых обновления через Ansible были нервными. Это третье - нет.
Как-нибудь распишем детальнее что именно лежит в critical_services и как строим group_vars под разные типы серверов.