От 8 часов до 15 минут: автоматизация 40 серверов через Ansible

Задача клиента: веб-студия с ручным управлением серверами

К нам обратилась веб-студия «WebCraft» из Санкт-Петербурга — команда из 15 разработчиков, обслуживающая 40+ серверов клиентов. Клиент столкнулся с серьёзной проблемой: каждый новый проект требовал ручной настройки серверов — установка Nginx, PHP, MariaDB, SSL-сертификатов, настройка безопасности. Один сервер настраивался от 4 до 8 часов. При этом конфигурации «расползались» — на одних серверах PHP 8.1, на других 8.2, где-то забыли обновить сертификат, где-то остались дефолтные настройки SSH.

Ситуация на момент обращения:

  • 40+ серверов с разными конфигурациями — каждый настраивался вручную
  • Настройка нового сервера занимала 4-8 часов рабочего времени девопса
  • Нет стандартизации — разные версии ПО, разные настройки безопасности
  • При увольнении девопса никто не знал точных конфигураций серверов
  • Обновление безопасности на всех серверах — задача на целый день

Клиент хотел получить систему, позволяющую настраивать новый сервер за 15-30 минут, обеспечить единообразие конфигураций и дать возможность любому члену команды выполнять типовые операции.

Наше предложение: Ansible как стандарт автоматизации

Мы провели аудит инфраструктуры студии и предложили внедрить Ansible — инструмент автоматизации от Red Hat. Его главное преимущество — безагентная архитектура: для работы достаточно SSH-доступа к управляемым серверам, никакого дополнительного ПО устанавливать не нужно.

Почему мы выбрали именно Ansible для данного клиента:

  • Безагентность — работает через SSH, не требует демонов на 40+ серверах
  • Декларативный YAML-синтаксис — playbooks читаются как документация, разработчики студии смогут их поддерживать
  • Идемпотентность — повторный запуск не меняет систему, если она уже в нужном состоянии
  • Модульность — тысячи готовых модулей для любых задач
  • Низкий порог входа — продуктивная работа через несколько часов обучения

Архитектура решения

Ansible работает по принципу push-модели: управляющий узел подключается к серверам по SSH и выполняет задачи. Мы спроектировали следующую архитектуру:

  • Control Node — CI/CD-сервер студии (GitLab), на котором установлен Ansible
  • Managed Nodes — 40+ серверов клиентов студии
  • Inventory — список серверов с группировкой по проектам и ролям
  • Playbooks — YAML-файлы для типовых операций (настройка LAMP, деплой, обновление)
  • Roles — переиспользуемые наборы задач для каждого компонента

Весь код Ansible хранится в Git-репозитории студии — любое изменение конфигурации проходит через code review.

Вот наше решение: установка и настройка Ansible

Мы установили Ansible на управляющем узле студии и подготовили структуру проекта для управления всеми серверами.

Установка Ansible на управляющий узел

Ansible устанавливается только на управляющем узле. На серверах клиентов нужен лишь Python 3 и SSH-доступ:

# Debian/Ubuntu
sudo apt update
sudo apt install -y python3-pip python3-venv

# Создаём виртуальное окружение (рекомендуется)
python3 -m venv ~/ansible-env
source ~/ansible-env/bin/activate

# Установка через pip (самая свежая версия)
pip install ansible ansible-lint

# Проверка установки
ansible --version

Настроили SSH-доступ по ключам ко всем серверам:

# Генерация SSH-ключа
ssh-keygen -t ed25519 -C "ansible@control-node"

# Копирование ключа на управляемые хосты
ssh-copy-id user@192.168.1.10
ssh-copy-id user@192.168.1.11
ssh-copy-id user@192.168.1.12

Структура inventory для 40+ серверов

Мы создали чёткую структуру проекта и inventory, отражающую инфраструктуру студии:

mkdir -p ~/ansible-project/{inventories,playbooks,roles,templates}
cd ~/ansible-project

INI-формат inventory:

# inventories/production.ini

[webservers]
web01 ansible_host=192.168.1.10
web02 ansible_host=192.168.1.11

[dbservers]
db01 ansible_host=192.168.1.20
db02 ansible_host=192.168.1.21

[monitoring]
zabbix ansible_host=192.168.1.30

[all:vars]
ansible_user=admin
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_private_key_file=~/.ssh/id_ed25519

[webservers:vars]
http_port=80
max_clients=200

[production:children]
webservers
dbservers
monitoring

YAML-формат для более сложных конфигураций:

# inventories/production.yml
all:
  vars:
    ansible_user: admin
    ansible_python_interpreter: /usr/bin/python3
  children:
    webservers:
      hosts:
        web01:
          ansible_host: 192.168.1.10
          http_port: 80
        web02:
          ansible_host: 192.168.1.11
          http_port: 8080
    dbservers:
      hosts:
        db01:
          ansible_host: 192.168.1.20
        db02:
          ansible_host: 192.168.1.21
      vars:
        db_port: 5432

Проверка inventory:

# Список всех хостов
ansible-inventory -i inventories/production.ini --list

# Граф хостов
ansible-inventory -i inventories/production.ini --graph

Переменные хостов и групп

Мы организовали иерархическую систему переменных для каждого проекта студии:

mkdir -p inventories/{group_vars,host_vars}
# inventories/group_vars/webservers.yml
---
nginx_worker_processes: auto
nginx_worker_connections: 1024
ssl_certificate: /etc/ssl/certs/wildcard.pem
ssl_certificate_key: /etc/ssl/private/wildcard.key
php_version: "8.2"
php_memory_limit: "256M"

# inventories/group_vars/dbservers.yml
---
postgresql_version: 15
postgresql_max_connections: 200
postgresql_shared_buffers: "2GB"
backup_schedule: "0 3 * * *"
# inventories/host_vars/web01.yml
---
nginx_worker_connections: 2048
vhost_domains:
  - example.com
  - www.example.com
  - api.example.com

Ad-hoc команды: быстрые операции на всех серверах

Одна из первых задач, которую мы решили для клиента — возможность выполнять массовые операции на всех серверах одной командой.

Примеры повседневного использования

Мы показали команде студии, как выполнять типовые задачи:

# Проверка доступности всех хостов
ansible all -i inventories/production.ini -m ping

# Получение информации о системе
ansible webservers -i inventories/production.ini -m setup -a "filter=ansible_distribution*"

# Выполнение произвольной команды
ansible all -i inventories/production.ini -m shell -a "uptime"

# Проверка свободного места на дисках
ansible all -i inventories/production.ini -m shell -a "df -h /"

# Установка пакета на все веб-серверы
ansible webservers -i inventories/production.ini -m apt \
  -a "name=nginx state=present" --become

# Перезапуск службы
ansible webservers -i inventories/production.ini -m service \
  -a "name=nginx state=restarted" --become

# Копирование файла
ansible all -i inventories/production.ini -m copy \
  -a "src=/local/file.conf dest=/etc/app/file.conf owner=root mode=0644" --become

# Создание пользователя
ansible all -i inventories/production.ini -m user \
  -a "name=deploy state=present groups=sudo shell=/bin/bash" --become

Сбор фактов о серверах

Модуль setup собирает полную информацию о хосте — facts, доступные как переменные в playbooks:

# Все факты о хосте
ansible web01 -i inventories/production.ini -m setup

# Фильтрация по IP-адресам
ansible web01 -m setup -a "filter=ansible_all_ipv4_addresses"

# Информация о памяти
ansible web01 -m setup -a "filter=ansible_memtotal_mb"

# Информация о дисках
ansible web01 -m setup -a "filter=ansible_mounts"

Полезные факты для playbooks: ansible_distribution, ansible_os_family, ansible_hostname, ansible_default_ipv4.address, ansible_memtotal_mb, ansible_processor_vcpus.

Playbooks: стандартизация настройки серверов

Ключевая часть проекта — создание набора playbooks для всех типовых операций студии. Мы описали желаемое состояние каждого типа сервера в YAML-файлах.

Playbook настройки веб-сервера

Мы создали playbook, который за 15 минут превращает чистый сервер в полностью настроенный веб-хост:

# playbooks/webserver-setup.yml
---
- name: Configure web servers
  hosts: webservers
  become: yes
  gather_facts: yes

  vars:
    packages:
      - nginx
      - php8.2-fpm
      - php8.2-mysql
      - php8.2-curl
      - certbot
      - python3-certbot-nginx

  tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

    - name: Install required packages
      apt:
        name: "{{ packages }}"
        state: present

    - name: Start and enable Nginx
      service:
        name: nginx
        state: started
        enabled: yes

    - name: Create web root directory
      file:
        path: /var/www/{{ item }}
        state: directory
        owner: www-data
        group: www-data
        mode: '0755'
      loop: "{{ vhost_domains | default(['default']) }}"

    - name: Deploy Nginx virtual host config
      template:
        src: templates/nginx-vhost.conf.j2
        dest: "/etc/nginx/sites-available/{{ item }}.conf"
        owner: root
        mode: '0644'
      loop: "{{ vhost_domains | default(['default']) }}"
      notify: Reload Nginx

    - name: Enable virtual hosts
      file:
        src: "/etc/nginx/sites-available/{{ item }}.conf"
        dest: "/etc/nginx/sites-enabled/{{ item }}.conf"
        state: link
      loop: "{{ vhost_domains | default(['default']) }}"
      notify: Reload Nginx

    - name: Configure PHP-FPM pool
      template:
        src: templates/php-fpm-pool.conf.j2
        dest: /etc/php/8.2/fpm/pool.d/www.conf
      notify: Restart PHP-FPM

    - name: Set up firewall rules
      ufw:
        rule: allow
        port: "{{ item }}"
        proto: tcp
      loop:
        - '80'
        - '443'
        - '22'

  handlers:
    - name: Reload Nginx
      service:
        name: nginx
        state: reloaded

    - name: Restart PHP-FPM
      service:
        name: php8.2-fpm
        state: restarted

Запуск playbook:

ansible-playbook -i inventories/production.ini playbooks/webserver-setup.yml

# С ограничением по хостам
ansible-playbook -i inventories/production.ini playbooks/webserver-setup.yml --limit web01

# Пробный запуск (без изменений)
ansible-playbook -i inventories/production.ini playbooks/webserver-setup.yml --check --diff

Условия, циклы и регистрация результатов

Для серверов с разными ОС мы настроили условное выполнение:

---
- name: System configuration with conditions
  hosts: all
  become: yes
  tasks:
    - name: Install packages (Debian)
      apt:
        name:
          - htop
          - iotop
          - vim
        state: present
      when: ansible_os_family == "Debian"

    - name: Install packages (RedHat)
      yum:
        name:
          - htop
          - iotop
          - vim-enhanced
        state: present
      when: ansible_os_family == "RedHat"

    - name: Check if Docker is installed
      command: docker --version
      register: docker_check
      ignore_errors: yes
      changed_when: false

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      when: docker_check.rc != 0

    - name: Create system users
      user:
        name: "{{ item.name }}"
        groups: "{{ item.groups }}"
        shell: "{{ item.shell | default('/bin/bash') }}"
        state: present
      loop:
        - { name: deploy, groups: 'sudo,docker' }
        - { name: monitoring, groups: 'www-data', shell: '/usr/sbin/nologin' }
        - { name: backup, groups: 'backup', shell: '/usr/sbin/nologin' }

    - name: Deploy SSH public keys
      authorized_key:
        user: "{{ item.user }}"
        key: "{{ lookup('file', item.key) }}"
      loop:
        - { user: deploy, key: '~/.ssh/deploy_key.pub' }
        - { user: admin, key: '~/.ssh/admin_key.pub' }

Jinja2-шаблоны для конфигурационных файлов

Мы создали набор шаблонов, автоматически адаптирующихся под ресурсы каждого сервера:

# templates/nginx-vhost.conf.j2
server {
    listen {{ http_port | default(80) }};
    server_name {{ item }}{% if item != 'default' %} www.{{ item }}{% endif %};
    root /var/www/{{ item }};
    index index.php index.html;

    # Managed by Ansible — do not edit manually
    # Last updated: {{ ansible_date_time.iso8601 }}
    # Host: {{ ansible_hostname }}

    access_log /var/log/nginx/{{ item }}_access.log;
    error_log /var/log/nginx/{{ item }}_error.log;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php{{ php_version }}-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

{% if ssl_certificate is defined %}
    listen 443 ssl http2;
    ssl_certificate {{ ssl_certificate }};
    ssl_certificate_key {{ ssl_certificate_key }};
    ssl_protocols TLSv1.2 TLSv1.3;
{% endif %}

    location ~* \.(jpg|jpeg|gif|png|css|js|ico|svg|woff2)$ {
        expires {{ static_cache_days | default(30) }}d;
        add_header Cache-Control "public, immutable";
    }
}

Шаблон PHP-FPM с автоматическим расчётом на основе RAM:

# templates/php-fpm-pool.conf.j2
[www]
user = www-data
group = www-data

listen = /run/php/php{{ php_version }}-fpm.sock
listen.owner = www-data
listen.group = www-data

pm = dynamic
pm.max_children = {{ (ansible_memtotal_mb / 64) | int }}
pm.start_servers = {{ (ansible_memtotal_mb / 256) | int }}
pm.min_spare_servers = {{ (ansible_memtotal_mb / 512) | int }}
pm.max_spare_servers = {{ (ansible_memtotal_mb / 128) | int }}

php_admin_value[memory_limit] = {{ php_memory_limit | default('256M') }}
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M

Роли: модульная организация для студии

Мы организовали все playbooks студии в роли — переиспользуемые компоненты со стандартной структурой.

Роль безопасной настройки сервера (hardening)

Создали роль, стандартизирующую безопасность на всех 40+ серверах:

ansible-galaxy role init roles/webserver

# Структура роли
tree roles/webserver/
roles/webserver/
├── defaults/
│   └── main.yml
├── files/
├── handlers/
│   └── main.yml
├── meta/
│   └── main.yml
├── tasks/
│   └── main.yml
├── templates/
└── vars/
    └── main.yml
# roles/hardening/defaults/main.yml
---
ssh_port: 22
ssh_permit_root_login: "no"
ssh_password_authentication: "no"
ssh_max_auth_tries: 3
fail2ban_bantime: 3600
fail2ban_maxretry: 5
auto_updates: true
allowed_ssh_users:
  - admin
  - deploy
# roles/hardening/tasks/main.yml
---
- name: Update all packages
  apt:
    upgrade: safe
    update_cache: yes
  tags: packages

- name: Install security packages
  apt:
    name:
      - fail2ban
      - ufw
      - unattended-upgrades
      - aide
      - rkhunter
    state: present
  tags: packages

- name: Configure SSH
  template:
    src: sshd_config.j2
    dest: /etc/ssh/sshd_config
    owner: root
    mode: '0600'
    validate: 'sshd -t -f %s'
  notify: Restart SSH
  tags: ssh

- name: Configure fail2ban
  template:
    src: jail.local.j2
    dest: /etc/fail2ban/jail.local
  notify: Restart fail2ban
  tags: fail2ban

- name: Set up UFW defaults
  ufw:
    state: enabled
    policy: deny
    direction: incoming
  tags: firewall

- name: Allow SSH through UFW
  ufw:
    rule: allow
    port: "{{ ssh_port }}"
    proto: tcp
  tags: firewall

- name: Configure automatic security updates
  template:
    src: 20auto-upgrades.j2
    dest: /etc/apt/apt.conf.d/20auto-upgrades
  when: auto_updates
  tags: updates

- name: Set permissions on sensitive files
  file:
    path: "{{ item }}"
    mode: '0600'
  loop:
    - /etc/shadow
    - /etc/gshadow
    - /etc/ssh/sshd_config
  tags: permissions
# roles/hardening/handlers/main.yml
---
- name: Restart SSH
  service:
    name: sshd
    state: restarted

- name: Restart fail2ban
  service:
    name: fail2ban
    state: restarted

Использование готовых ролей из Ansible Galaxy

Для стандартных компонентов мы использовали проверенные роли из Galaxy:

# Установка ролей
ansible-galaxy install geerlingguy.nginx
ansible-galaxy install geerlingguy.postgresql
ansible-galaxy install geerlingguy.certbot

# Файл зависимостей
cat requirements.yml
---
roles:
  - name: geerlingguy.nginx
    version: "3.1.0"
  - name: geerlingguy.postgresql
    version: "3.4.0"
  - name: geerlingguy.certbot
    version: "5.1.0"

ansible-galaxy install -r requirements.yml

Использование в playbook:

# playbooks/site.yml
---
- name: Configure all servers
  hosts: all
  become: yes
  roles:
    - role: hardening
      tags: security

- name: Configure web servers
  hosts: webservers
  become: yes
  roles:
    - role: geerlingguy.nginx
      vars:
        nginx_remove_default_vhost: true
      tags: nginx
    - role: geerlingguy.certbot
      vars:
        certbot_auto_renew: true
      tags: ssl

- name: Configure database servers
  hosts: dbservers
  become: yes
  roles:
    - role: geerlingguy.postgresql
      vars:
        postgresql_version: "15"
      tags: database

Ansible Vault: безопасное хранение паролей клиентов

У веб-студии десятки паролей от баз данных, API-ключей и сертификатов для разных проектов. Мы настроили безопасное хранение через Ansible Vault.

Шифрование секретов

Мы организовали хранение секретов с шифрованием AES-256:

# Создание зашифрованного файла
ansible-vault create inventories/group_vars/all/vault.yml

# Содержимое:
---
vault_db_password: "SuperSecretP@ss123"
vault_api_key: "sk-1234567890abcdef"
vault_ssl_passphrase: "CertPassphrase"
vault_smtp_password: "MailP@ssword"
# Управление зашифрованными файлами
ansible-vault edit inventories/group_vars/all/vault.yml
ansible-vault view inventories/group_vars/all/vault.yml
ansible-vault encrypt secrets.yml
ansible-vault decrypt secrets.yml
ansible-vault rekey secrets.yml

Использование в playbooks:

# inventories/group_vars/dbservers.yml
---
db_name: myapp
db_user: appuser
db_password: "{{ vault_db_password }}"
# Запуск с vault
ansible-playbook site.yml --ask-vault-pass

# Через файл с паролем (для CI/CD)
echo 'VaultPassword123' > ~/.vault_pass
chmod 600 ~/.vault_pass
ansible-playbook site.yml --vault-password-file ~/.vault_pass

В ansible.cfg указали файл пароля по умолчанию:

# ansible.cfg
[defaults]
vault_password_file = ~/.vault_pass
inventory = inventories/production.ini
roles_path = roles
retry_files_enabled = false

[privilege_escalation]
become = true
become_method = sudo

Лучшие практики для студии

Мы внедрили правила работы с секретами:

  • Разделение обычных и зашифрованных переменных — отдельные файлы
  • Префикс vault_ для зашифрованных переменных
  • .vault_pass в .gitignore
  • В CI/CD пароль через ANSIBLE_VAULT_PASSWORD_FILE
# .gitignore
*.retry
.vault_pass
*.pyc
__pycache__/

Для разных окружений (production, staging) — разные vault-id:

ansible-vault create --vault-id prod@~/.vault_pass_prod group_vars/all/vault.yml
ansible-vault create --vault-id staging@~/.vault_pass_staging group_vars/all/vault_staging.yml

ansible-playbook site.yml --vault-id prod@~/.vault_pass_prod --vault-id staging@~/.vault_pass_staging

Практический пример: полный деплой LAMP-стека за 15 минут

Мы применили все наработки для создания мастер-playbook, который поднимает полный LAMP-стек с нуля.

Полный playbook развёртывания

# playbooks/lamp-deploy.yml
---
- name: Deploy LAMP Stack
  hosts: webservers
  become: yes
  gather_facts: yes

  vars_files:
    - ../inventories/group_vars/all/vault.yml

  vars:
    mysql_root_password: "{{ vault_db_password }}"
    app_db_name: myapp
    app_db_user: appuser
    app_db_password: "{{ vault_db_password }}"
    php_version: "8.2"
    app_domain: example.com
    app_root: /var/www/{{ app_domain }}

  pre_tasks:
    - name: Update apt cache
      apt:
        update_cache: yes
        cache_valid_time: 3600

  tasks:
    - name: Install Nginx
      apt:
        name: nginx
        state: present
      tags: nginx

    - name: Deploy Nginx config
      template:
        src: templates/nginx-app.conf.j2
        dest: /etc/nginx/sites-available/{{ app_domain }}.conf
      notify: Reload Nginx
      tags: nginx

    - name: Install PHP and extensions
      apt:
        name:
          - php{{ php_version }}-fpm
          - php{{ php_version }}-mysql
          - php{{ php_version }}-curl
          - php{{ php_version }}-gd
          - php{{ php_version }}-mbstring
          - php{{ php_version }}-xml
          - php{{ php_version }}-zip
          - php{{ php_version }}-intl
          - php{{ php_version }}-bcmath
        state: present
      tags: php

    - name: Install MariaDB
      apt:
        name:
          - mariadb-server
          - python3-pymysql
        state: present
      tags: database

    - name: Create application database
      mysql_db:
        name: "{{ app_db_name }}"
        state: present
        login_unix_socket: /var/run/mysqld/mysqld.sock
      tags: database

    - name: Deploy application files
      synchronize:
        src: ../files/app/
        dest: "{{ app_root }}/"
        delete: yes
      notify: Clear PHP cache
      tags: app

  handlers:
    - name: Reload Nginx
      service:
        name: nginx
        state: reloaded

    - name: Restart PHP-FPM
      service:
        name: "php{{ php_version }}-fpm"
        state: restarted

    - name: Clear PHP cache
      command: php{{ php_version }} -r "opcache_reset();"
      ignore_errors: yes

Запуск:

# Полное развёртывание
ansible-playbook -i inventories/production.ini playbooks/lamp-deploy.yml --ask-vault-pass

# Только обновление приложения
ansible-playbook -i inventories/production.ini playbooks/lamp-deploy.yml --tags app

# Пробный запуск
ansible-playbook -i inventories/production.ini playbooks/lamp-deploy.yml --check --diff

Управление пользователями и SSH-ключами

Мы автоматизировали управление доступами для всей команды студии:

# playbooks/manage-users.yml
---
- name: Manage system users and SSH access
  hosts: all
  become: yes

  vars:
    admin_users:
      - name: ivanov
        full_name: "Иванов Пётр"
        ssh_key: "ssh-ed25519 AAAA... ivanov@company"
        groups: sudo,docker
        state: present
      - name: petrov
        full_name: "Петров Сергей"
        ssh_key: "ssh-ed25519 AAAA... petrov@company"
        groups: sudo
        state: present
      - name: sidorov
        full_name: "Сидоров (уволен)"
        state: absent

  tasks:
    - name: Create/remove admin users
      user:
        name: "{{ item.name }}"
        comment: "{{ item.full_name | default('') }}"
        groups: "{{ item.groups | default('') }}"
        shell: /bin/bash
        state: "{{ item.state | default('present') }}"
        remove: "{{ 'yes' if item.state | default('present') == 'absent' else 'no' }}"
      loop: "{{ admin_users }}"

    - name: Deploy SSH keys for admin users
      authorized_key:
        user: "{{ item.name }}"
        key: "{{ item.ssh_key }}"
        exclusive: yes
      loop: "{{ admin_users }}"
      when: item.state | default('present') == 'present' and item.ssh_key is defined

    - name: Configure sudoers
      lineinfile:
        path: /etc/sudoers.d/{{ item.name }}
        line: "{{ item.name }} ALL=(ALL) NOPASSWD:ALL"
        create: yes
        mode: '0440'
        validate: 'visudo -cf %s'
      loop: "{{ admin_users }}"
      when: item.state | default('present') == 'present'

При увольнении сотрудника достаточно изменить state: absent — его доступ удалится на всех 40+ серверах.

Результаты внедрения

Проект занял 3 недели — от аудита до полного перехода студии на Ansible. Вот измеримые результаты:

  • Настройка нового сервера сократилась с 4-8 часов до 15-20 минут (один запуск playbook)
  • Стандартизация — все 40+ серверов приведены к единой конфигурации безопасности
  • Обновление безопасности — одна команда вместо дня ручной работы
  • Управление доступами — добавление/удаление сотрудника на всех серверах за 2 минуты
  • Документация — playbooks стали живой документацией инфраструктуры
  • Экономия времени — около 40 человеко-часов в месяц на типовых операциях
  • Безопасность — все секреты зашифрованы через Vault, хранятся в Git

Часто задаваемые вопросы

Нет, это главное преимущество Ansible — безагентная архитектура. Ansible устанавливается только на управляющем узле. На управляемых серверах нужен лишь Python 3 и SSH-доступ, которые есть на любом современном Linux-сервере по умолчанию.

Ключевые отличия: Ansible безагентный (Puppet и Chef требуют установки агента), использует декларативный YAML вместо Ruby-DSL, работает по push-модели (а не pull), не требует выделенного сервера для управления. Ansible проще в освоении, но Puppet может быть эффективнее для очень больших инфраструктур (10 000+ узлов).

Используйте Ansible Vault — встроенный механизм шифрования файлов и переменных алгоритмом AES-256. Создайте зашифрованный файл через ansible-vault create vault.yml, поместите туда секреты и ссылайтесь на них из обычных переменных. В CI/CD передавайте пароль vault через переменную окружения ANSIBLE_VAULT_PASSWORD_FILE.

Да, Ansible поддерживает управление Windows-серверами через WinRM. Установите модуль pywinrm на управляющем узле, включите WinRM на Windows-серверах и используйте специальные модули: win_package, win_service, win_feature, win_file и другие.

Используйте несколько уровней тестирования: 1) --check --diff для пробного запуска без изменений; 2) ansible-lint для проверки синтаксиса; 3) Molecule — фреймворк для тестирования ролей в Docker; 4) staging-окружение. Всегда запускайте с --limit на одном хосте перед массовым применением.

Нужна помощь с настройкой?

Специалисты АйТи Фреш помогут с внедрением и настройкой — 15+ лет опыта, обслуживание от 15 000 ₽/мес

📞 Связаться с нами
#ansible для начинающих#автоматизация серверов#ansible playbook#ansible роли#ansible inventory#ansible vault#ansible galaxy#jinja2 шаблоны