Минимальный Playbook для обновления серверов (Ansible, Ubuntu 24.04+)
Короткая «заметка» для BookStack: готовые playbook’и и команды. Работает как с ansible-core из APT, так и с полным ansible из pipx/PPA. Предполагается, что у тебя уже есть проект с ansible.cfg и инвентори inventories/inventory.ini (из прошлой заметки).
Предпосылки
-
В проекте уже есть
ansible.cfgиinventories/inventory.ini. -
На целевых хостах установлен Python 3.
-
Для Arch нужен модуль
community.general.pacman:ansible-galaxy collection install community.general -
Файл инвентори используйте реальный (частая ошибка — неверный путь).
Быстрая проверка окружения
ansible --version
ansible all -i inventories/inventory.ini --list-hosts
1) Простой плейбук (Debian/Ubuntu)
Файл: playbooks/simple-update.yml
---
- name: Simple update for Debian/Ubuntu
hosts: all
become: yes
gather_facts: yes
tasks:
- name: Update cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Upgrade packages
ansible.builtin.apt:
upgrade: dist
autoremove: yes
autoclean: yes
when: ansible_os_family == "Debian"
- name: Check if reboot is required
ansible.builtin.stat:
path: /run/reboot-required
register: reboot_required
when: ansible_os_family == "Debian"
- name: Reboot if required
ansible.builtin.reboot:
msg: "Rebooting due to system updates"
reboot_timeout: 600
pre_reboot_delay: 60 # меньше 60 на Linux ≈ 0
when: ansible_os_family == "Debian" and reboot_required.stat.exists
- name: Wait for host after reboot (optional)
ansible.builtin.wait_for_connection:
timeout: 600
delay: 20
when: ansible_os_family == "Debian" and reboot_required.stat.exists
Запуск:
ansible-playbook -i inventories/inventory.ini playbooks/simple-update.yml
2) Универсальный плейбук (Debian/Ubuntu, RHEL/CentOS/Alma/Rocky/Fedora, Arch)
Файл: playbooks/update-all-systems.yml
---
- name: Update all Linux servers (multi-distro)
hosts: all
become: yes
gather_facts: yes
serial: 1 # безопасно для прод-сред
tasks:
# --- Debian/Ubuntu ---
- name: Update cache (Debian/Ubuntu)
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Upgrade packages (Debian/Ubuntu)
ansible.builtin.apt:
upgrade: dist
autoremove: yes
autoclean: yes
when: ansible_os_family == "Debian"
- name: Check if reboot required (Debian/Ubuntu)
ansible.builtin.stat:
path: /run/reboot-required
register: debian_reboot_required
when: ansible_os_family == "Debian"
# --- RHEL/CentOS/Fedora ---
- name: Ensure needs-restarting is available (RHEL-like)
ansible.builtin.package:
name:
- yum-utils # RHEL 7+/CentOS
- dnf-plugins-core # Fedora/новые DNF
state: present
when: ansible_os_family == "RedHat"
ignore_errors: yes
- name: Update cache and upgrade (RHEL-like)
ansible.builtin.yum:
name: "*"
state: latest
update_cache: yes
when: ansible_os_family == "RedHat"
- name: Check if reboot required (RHEL-like)
ansible.builtin.command: needs-restarting -r
register: rhel_reboot_required
failed_when: false
changed_when: false
when: ansible_os_family == "RedHat"
# --- Arch Linux ---
- name: Update packages (Arch)
community.general.pacman:
update_cache: yes
upgrade: yes
when: ansible_os_family == "Archlinux"
# --- Unified reboot logic ---
- name: Reboot if required (Debian/Ubuntu)
ansible.builtin.reboot:
msg: "Rebooting due to system updates"
reboot_timeout: 900
pre_reboot_delay: 60
when: ansible_os_family == "Debian" and debian_reboot_required.stat.exists
- name: Reboot if required (RHEL-like)
ansible.builtin.reboot:
msg: "Rebooting due to system updates"
reboot_timeout: 900
pre_reboot_delay: 60
when: ansible_os_family == "RedHat" and rhel_reboot_required.rc == 1
- name: Wait for host after reboot (when reboot happened)
ansible.builtin.wait_for_connection:
timeout: 900
delay: 20
when: >
(ansible_os_family == "Debian" and debian_reboot_required.stat.exists) or
(ansible_os_family == "RedHat" and rhel_reboot_required.rc == 1)
Запуск:
ansible-playbook -i inventories/inventory.ini playbooks/update-all-systems.yml
3) «Безопасное» обновление с пред-чеками и «бэкапом» списка пакетов
Файл: playbooks/secure-update.yml
---
- name: Secure update with pre-checks
hosts: all
become: yes
gather_facts: yes
vars:
max_load_1min: 4.0
min_free_space_mb: 512
backup_before_update: true
backup_dir: "/var/backups/preupdate-{{ ansible_date_time.date }}"
tasks:
- name: Fail if 1min load too high
ansible.builtin.assert:
that:
- (ansible_loadavg['1'] | float) <= max_load_1min
fail_msg: "System load too high: {{ ansible_loadavg['1'] }}"
- name: Fail if any mount has too little free space
ansible.builtin.fail:
msg: "Low space on {{ item.mount }}: {{ (item.size_available // 1024 // 1024) }} MB"
loop: "{{ ansible_mounts }}"
loop_control:
label: "{{ item.mount }}"
when: (item.size_available // 1024 // 1024) < min_free_space_mb
- name: Create backup directory
ansible.builtin.file:
path: "{{ backup_dir }}"
state: directory
mode: '0755'
when: backup_before_update
- name: Save package list (Debian/Ubuntu)
ansible.builtin.shell: dpkg --get-selections > "{{ backup_dir }}/packages.txt"
args: { warn: false }
when: ansible_os_family == "Debian" and backup_before_update
- name: Save package list (RHEL-like)
ansible.builtin.shell: rpm -qa > "{{ backup_dir }}/packages.txt"
args: { warn: false }
when: ansible_os_family == "RedHat" and backup_before_update
- name: Update cache / packages (Debian/Ubuntu)
block:
- ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
- ansible.builtin.apt:
upgrade: dist
autoremove: yes
autoclean: yes
when: ansible_os_family == "Debian"
- name: Update cache / packages (RHEL-like)
ansible.builtin.yum:
name: "*"
state: latest
update_cache: yes
when: ansible_os_family == "RedHat"
- name: Check if reboot required (Debian/Ubuntu)
ansible.builtin.stat:
path: /run/reboot-required
register: reboot_required
when: ansible_os_family == "Debian"
- name: Check if reboot required (RHEL-like)
ansible.builtin.command: needs-restarting -r
register: rhel_reboot_required
failed_when: false
changed_when: false
when: ansible_os_family == "RedHat"
- name: Reboot if required
ansible.builtin.reboot:
msg: "Rebooting due to system updates"
reboot_timeout: 900
pre_reboot_delay: 60
when: >
(ansible_os_family == "Debian" and reboot_required.stat.exists) or
(ansible_os_family == "RedHat" and rhel_reboot_required.rc == 1)
- name: Wait for host after reboot
ansible.builtin.wait_for_connection:
timeout: 900
delay: 20
when: >
(ansible_os_family == "Debian" and reboot_required.stat.exists) or
(ansible_os_family == "RedHat" and rhel_reboot_required.rc == 1)
Запуск (пример без «бэкапа»):
ansible-playbook -i inventories/inventory.ini playbooks/secure-update.yml -e "backup_before_update=false"
4) Обновление с простым логированием
Файл: playbooks/update-with-logging.yml
---
- name: Update with simple logging (cross-distro)
hosts: all
become: yes
gather_facts: yes
vars:
log_file: "/var/log/ansible-updates.log"
tasks:
- name: Start log
ansible.builtin.lineinfile:
path: "{{ log_file }}"
line: "{{ ansible_date_time.iso8601 }} - Start update on {{ inventory_hostname }}"
create: yes
# Debian/Ubuntu
- name: Update & upgrade (Debian/Ubuntu)
block:
- ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
- ansible.builtin.apt:
upgrade: dist
autoremove: yes
autoclean: yes
when: ansible_os_family == "Debian"
# RHEL/CentOS/Fedora
- name: Update & upgrade (RHEL-like)
ansible.builtin.yum:
name: "*"
state: latest
update_cache: yes
when: ansible_os_family == "RedHat"
# Arch
- name: Update & upgrade (Arch)
community.general.pacman:
update_cache: yes
upgrade: yes
when: ansible_os_family == "Archlinux"
- name: Log completion
ansible.builtin.lineinfile:
path: "{{ log_file }}"
line: "{{ ansible_date_time.iso8601 }} - Update completed on {{ inventory_hostname }}"
- name: Check reboot flag (Debian/Ubuntu)
ansible.builtin.stat:
path: /run/reboot-required
register: debian_reboot_required
when: ansible_os_family == "Debian"
- name: Check reboot flag (RHEL-like)
ansible.builtin.command: needs-restarting -r
register: rhel_reboot_required
failed_when: false
changed_when: false
when: ansible_os_family == "RedHat"
- name: Log reboot requirement
ansible.builtin.lineinfile:
path: "{{ log_file }}"
line: "{{ ansible_date_time.iso8601 }} - Reboot required on {{ inventory_hostname }}"
when: >
(ansible_os_family == "Debian" and debian_reboot_required.stat.exists) or
(ansible_os_family == "RedHat" and rhel_reboot_required.rc == 1)
Полезные варианты запуска
# Простой запуск
ansible-playbook -i inventories/inventory.ini playbooks/update-all-systems.yml
# Dry-run (ничего не меняет, показывает план)
ansible-playbook -i inventories/inventory.ini playbooks/update-all-systems.yml --check --diff
# Только определённая группа или хост
ansible-playbook -i inventories/inventory.ini playbooks/update-all-systems.yml --limit webservers
ansible-playbook -i inventories/inventory.ini playbooks/update-all-systems.yml --limit n-1-dsw
# Подробный вывод
ansible-playbook -i inventories/inventory.ini playbooks/update-all-systems.yml -vvv
Ручной «план Б» (без Ansible)
Debian/Ubuntu
sudo apt-get update
sudo apt-get dist-upgrade -y
sudo apt-get autoremove -y
sudo apt-get autoclean -y
test -f /run/reboot-required && sudo reboot
RHEL/CentOS/Alma/Rocky/Fedora
sudo dnf -y install dnf-plugins-core || sudo yum -y install yum-utils
sudo dnf -y upgrade || sudo yum -y update
sudo needs-restarting -r; [ "$?" -eq 1 ] && sudo reboot
Arch
sudo pacman -Syu
# ребут — по вашей политике (например, после обновления ядра)
Мини-шпаргалка по структуре проекта
~/ansible-projects/
├─ ansible.cfg
├─ inventories/
│ └─ inventory.ini
├─ playbooks/
│ ├─ simple-update.yml
│ ├─ update-all-systems.yml
│ ├─ secure-update.yml
│ └─ update-with-logging.yml
└─ roles/
Готово. Эти четыре плейбука закрывают быстрые апдейты, мульти-дистрибутив, «безопасный» режим и логирование; остальное (уведомления, расписание) можно добавить отдельно.
