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

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 под разные типы серверов.

Контакт

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

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