Как организовать автоматическое обновление серверов с помощью скриптов?

«Как организовать автоматическое обновление серверов с помощью скриптов?» — вопрос из категории Скриптинг и автоматизация, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Автоматическое обновление серверов — ключевая практика DevOps для поддержания безопасности и стабильности. Вот основные подходы:

1. Базовый скриптинг (Cron + пакетный менеджер): Простое решение для небольшого числа серверов. Создаем скрипт и добавляем его в cron.

#!/bin/bash
# /usr/local/bin/auto-update.sh
set -euo pipefail
LOG_FILE="/var/log/auto-update.log"

# Для Debian/Ubuntu
echo "$(date): Starting update" >> "$LOG_FILE"
apt-get update && apt-get upgrade -y >> "$LOG_FILE" 2>&1

# Для RHEL/CentOS/AlmaLinux
# dnf check-update -y && dnf upgrade -y >> "$LOG_FILE" 2>&1

# При необходимости перезагрузка (если обновилось ядро)
if [ -f /var/run/reboot-required ]; then
    echo "$(date): Reboot required, scheduling in 5 min" >> "$LOG_FILE"
    shutdown -r +5 "Kernel updated via auto-update script"
fi
echo "$(date): Update completed" >> "$LOG_FILE"

Добавляем в crontab -e: 0 3 * * sun /usr/local/bin/auto-update.sh

2. Управление конфигурацией (Ansible): Идеально для флота серверов. Создаем плейбук для безопасного обновления с контролем.

# update-playbook.yml
- name: Apply security updates to all servers
  hosts: all
  become: yes
  serial: "30%" # Обновляем по частям, а не все сразу
  tasks:
    - name: Update apt cache (Debian/Ubuntu)
      apt:
        update_cache: yes
        cache_valid_time: 3600
      when: ansible_os_family == "Debian"

    - name: Apply security updates only (Debian/Ubuntu)
      apt:
        upgrade: dist
        autoremove: yes
        autoclean: yes
        default_release: "{{ ansible_distribution_release }}-security"
      when: ansible_os_family == "Debian"

    - name: Apply updates (RHEL family)
      yum:
        name: '*'
        state: latest
        security: yes # Только обновления безопасности
        exclude: kernel* # Исключаем ядро, если нужна отдельная процедура
      when: ansible_os_family == "RedHat"

    - name: Reboot if required and kernel was updated
      reboot:
        msg: "Reboot triggered by Ansible for kernel update"
        pre_reboot_delay: 60
        post_reboot_delay: 30
        reboot_timeout: 300
      when: ansible_os_family == "RedHat" and ansible_kernel is changed

Запуск: ansible-playbook -i inventory.ini update-playbook.yml

3. Immutable Infrastructure (Terraform + Packer): Современный подход: не обновляем сервера, а заменяем их новыми образами.

  • Packer: Создает новый AMI/образ с уже примененными всеми обновлениями.
  • Terraform: Планирует замену старых инстансов (например, в Auto Scaling Group) на новые с обновленным образом.

Ключевые практики:

  • Сначала Stage: Всегда тестируйте обновления на staging-окружении.
  • Мониторинг и откат: Настройте алерты на сбои после обновления. Имейте план быстрого отката (например, к предыдущему AMI).
  • Окна обслуживания: Планируйте обновления на время наименьшей нагрузки.
  • Логирование и уведомления: Все этапы должны логироваться, а ключевые события (начало, завершение, перезагрузка) — отправляться в чат (Slack/Telegram) или систему мониторинга.