Якщо потрібно швидко й безпечно оновити мережеві налаштування на десятках хостів, комбо Netplan + Ansible — саме те. Я покажу, як акуратно підготувати Jinja2-шаблон, протестувати на стейджингу, викотити поетапно і мати чіткий план відкату, щоб ваше SSH підключення не обірвалося в найгірший момент 🛡️

Що будемо робити (огляд)

Ми створимо шаблон Netplan, заведемо змінні для різних ролей/сегментів, налаштуємо playbook з поетапним розгортанням (serial), dry-run, валідацією (netplan generate) та відкатом. Усе це — класична автоматизація задач для стабільного середовища сервер Linux з акуратними мережеві налаштування.

Основний How-to: від шаблону до безпечного застосування

1) Підготуйте інвентар та змінні

# Приклад інвентаря
mkdir -p ansible/{group_vars,templates}
cd ansible
cat > hosts.ini <<'INI'
[netplan]
srv[01:10].dc1.example.com
INI

# Загальні змінні для групи (рендерер, приклад IPv4)
cat > group_vars/netplan.yml <<'YAML'
netplan_renderer: networkd  # або NetworkManager
netplan_config:
  network:
    version: 2
    renderer: "{{ netplan_renderer }}"
    ethernets:
      ens160:
        dhcp4: no
        addresses:
          - 10.10.1.10/24
        gateway4: 10.10.1.1
        nameservers:
          addresses: [1.1.1.1, 8.8.8.8]
YAML

2) Створіть Jinja2-шаблон Netplan

Шаблон рендерить змінні у валідний YAML. Так простіше підтримувати кілька профілів.

cat > templates/99-netplan.yaml.j2 <<'J2'
# This file is managed by Ansible. Do not edit.
{{ netplan_config | to_nice_yaml(indent=2) }}
J2

3) Playbook з валідацією і відкатом

Поетапний rollout, бекапи, перевірка SSH після застосування. Якщо зв'язок ризикує, виконується rollback.

cat > site.yml <<'YAML'
---
- name: Safe Netplan rollout
  hosts: netplan
  become: true
  serial: 1                 # по одному хосту за раз
  any_errors_fatal: true
  vars:
    netplan_target: /etc/netplan/99-ansible.yaml

  pre_tasks:
    - name: Ensure backup dir exists
      ansible.builtin.file:
        path: /root/netplan-backups
        state: directory
        mode: '0700'

    - name: Backup current Netplan directory
      ansible.builtin.command:
        cmd: tar -C /etc -czf /root/netplan-backups/netplan-{{ ansible_date_time.iso8601 }}.tgz netplan

  tasks:
    - name: Deploy templated Netplan config
      ansible.builtin.template:
        src: templates/99-netplan.yaml.j2
        dest: "{{ netplan_target }}"
        owner: root
        group: root
        mode: '0644'
        backup: true
      notify: Validate and apply netplan

  handlers:
    - name: Validate and apply netplan
      block:
        - name: Validate syntax (netplan generate)
          ansible.builtin.command:
            cmd: netplan generate

        - name: Apply new network configuration
          ansible.builtin.command:
            cmd: netplan apply

        - name: Confirm SSH is reachable after apply
          ansible.builtin.wait_for:
            host: "{{ ansible_host | default(inventory_hostname) }}"
            port: 22
            delay: 3
            timeout: 60
            state: started

      rescue:
        - name: Restore previous Netplan from latest backup
          ansible.builtin.shell: |
            set -e
            cp -a /etc/netplan /etc/netplan.failed.$(date +%s) || true
            tar -C / -xzf "$(ls -1t /root/netplan-backups/netplan-*.tgz | head -1)"
            netplan generate
            netplan apply

        - name: Abort rollout on this host
          ansible.builtin.fail:
            msg: "Netplan rollback applied on {{ inventory_hostname }}. Stopping."
YAML

4) Пробний прогін і поетапний деплой

# Dry-run + показ diff
ansible-playbook -i hosts.ini site.yml --check --diff

# Тест лише на двох серверах
ansible-playbook -i hosts.ini site.yml --limit 'netplan[0:1]'

# Повний поетапний запуск
ansible-playbook -i hosts.ini site.yml

Альтернативні способи

  • NetworkManager через Ansible: модуль community.general.nmcli для систем із NM-рендерером. Зручно, якщо потрібні профілі Wi‑Fi/VLAN/Bridge, а не статичні Netplan-файли.
  • Ролі та Molecule-тестування: винесіть завдання в роль, перевіряйте під LXD/Docker (наприклад, гарна практика для стейджу перед продом 🧪).
  • Валідація маршрутизації: після netplan apply перевіряйте наявність шлюзу/маршрутів командою ip route у тасці й падайте з помилкою, якщо щось не так.

GUI-спосіб (точкова перевірка)

Для візуальної перевірки одного вузла можна швидко накатити Cockpit і глянути інтерфейси. Це не масовий метод, але іноді корисний.

sudo apt update && sudo apt install -y cockpit
sudo systemctl enable --now cockpit.socket
# Відкрийте https://<IP-сервера>:9090 та зайдіть у Networking

Пам'ятайте: для масових змін краще Ansible. Cockpit — тільки для разової діагностики або термінових правок на одному сервер Linux.

FAQ

Чому після застосування зникає доступ по SSH?

Найчастіше — через неправильний шлюз або помилку в YAML. Використовуйте поетапний serial: 1, валідацію netplan generate, і плейбук з блоком rescue для відкату. Також перевіряйте, що ви міняєте інтерфейс, яким здійснюється SSH підключення.

NetworkManager чи systemd-networkd?

Вибір визначає renderer. На серверних Ubuntu зазвичай networkd. На десктопах і деяких хмарах — NetworkManager. Узгодьте це у змінній netplan_renderer і тримайте окремі профілі.

Як перевірити YAML перед деплоєм?

Локально: yamllint. На хості через Ansible: netplan generate у тасці. Якщо є індетнація або синтаксис зламані — команда впаде до застосування змін.

Що з IPv6 або кількома адресами?

Додавайте до addresses кілька CIDR, а для IPv6 використовуйте gateway6 та DNSv6. Наприклад: addresses: [10.10.1.10/24, 2001:db8::10/64].

У мене різні назви інтерфейсів на хостах. Як бути?

Зберіть факти ansible_facts і згенеруйте ethernets динамічно (наприклад, для інтерфейсу, що має адресу з потрібної підмережі). Або заведіть мапу хост->інтерфейс у host_vars.

Чи можна робити "netplan try" для авто-відкату?

netplan try очікує підтвердження в TTY. У безінтерактивному середовищі краще покладатися на поетапний деплой + rescue блок відкату й зовнішні бекапи. Якщо дуже треба — можна викручуватись через псевдо-TTY, але це крихкий підхід.

Як перевірити, що маршрут за замовчуванням залишився?

Додайте таск після netplan apply з перевіркою ip route | grep -q 'default via'. Якщо немає — запускати rollback.

Порада від Kernelka

Спочатку зробіть лабораторію: LXD/Multipass/VM із кількома віртуальними NIC. Готуйте профілі під різні підмережі, тримайте позасмуговий канал доступу (IPMI/iDRAC/Console), а rollout крутите невеликими порціями. Тримайте пінг до кожного хоста в окремій вкладці tmux — це дає впевненість під час змін 🚀

Підсумок

  • Готуйте Jinja2-шаблон Netplan і централізуйте змінні.
  • Робіть бекапи і валідовуйте netplan generate перед застосуванням.
  • Деплойте поетапно (serial), перевіряйте SSH та маршрути.
  • Передбачайте rollback через rescue і архіви з /etc/netplan.
  • На стейджі тестуйте роль під Molecule; у прод — маленькими хвилями.

Так ви отримаєте керовані та передбачувані мережеві налаштування на кожному сервері без зайвого ризику і простої.