Ansible - удаленная настройка конфигураций
Представим, что у вас есть 10 серверов под разные или похожие задачи. Каждую машину нужно периодически обновлять, изменять ее конфигурацию. Часто необходимо поднять и настроить сразу несколько серверов в короткие сроки. Конечно, можно подключаться к каждому по SSH и вручную вносить необходимые изменения, но это очень долго и увеличивает возможность совершения ошибок из-за человеческого фактора.
Для эффективного решения подобных задач DevOps-специалисты используют систему удаленного управления конфигурацией Ansible. Ansible автоматизирует поставку ПО, управляет конфигурацией и развёртыванием приложений. В облачной среде, Ansible может использоваться для автоматизации конфигурирования и управления облачными инфраструктурами. Например, для развертывания и управления виртуальными машинами, контейнерами, сетевыми объектами и облачными сервисами.
Главные преимущества Ansible:
1) Работа по SSH. На управляемые серверы не нужно устанавливать дополнительный софт, Ansible должен быть установлен лишь на управляющем сервере.
2) Простота. Код написан на Python, поэтому написание дополнительных модулей под ваши задачи не составит труда. Конфигурационные файлы Ansible создаются в формате YAML - формат сериализованных данных (т.е. перевод структуры данных в битовую последовательность), намного проще и читабельнее, чем JSON и XML.
3) Декларативность. Разработчику нужно писать не действия программы, а результат, которого она должна достичь. Ansible сам спланирует как именно он будет достигнут. Это значительно сокращает время настройки.
4) Push и Pull. Ansible может работать в обоих режимах: главный сервер может "вытягивать" информацию из управляемых, или наоборот, "проталкивать" ее в зависимые сервера.
Недостатки:
1) Проблемы с Windows. С версии 1.7 Ansible поддерживает Windows, но работать приходится с оболочкой PowerShell, необходимо установить Linux-модуль.
2) Контроль состояния. В Ansible нет постоянного мониторинга зависимых серверов, он лишь выполняет задачи и наблюдает за состоянием хоста. В других системах управления есть более широкие возможности для контроля состояния серверов.
Структура Ansible
Модули
Это программы, выполняющие работу на сервере. Например, вместо запуска команды на машине:
$ apt install nginx
Мы можем использовать модуль apt и установить nginx :
- name: Install htop apt: name=htop
Хосты
Чтобы предоставить перечень хостов, нам нужно обозначить список, находящийся в файле инвентаризации.
Playbooks
Playbooks — основа работы Ansible. Это способ отправки команд на удалённые компьютеры с помощью скриптов в формате YAML. Вместо того, чтобы индивидуально использовать команды для удалённой настройки компьютеров из командной строки, вы можете настраивать целые сложные среды, передавая скрипт одной или нескольким серверам.
Vars
Файл содержит набор переменных, например имя пользователя и пароль базы данных.
Роли
Это способ сгруппировать несколько задач в один контейнер, чтобы эффективно автоматизировать работу с помощью понятной структуры каталогов.
Файлы конфигураций Ansible делятся на блоки, начинающиеся с “- name”. Сначала указывается название операции, а потом модуль, который нужен для ее выполнения. После этого нужно указать переменные модуля.
На первый взгляд это может показаться сложным, но структура Ansible очень проста, а модули быстро запоминаются или находятся в интернете. Существует полная документация, помимо этого, вы можете найти огромное количество самописные модулей под самые разные задачи.
Использование Ansible на практике
Рассмотрим удобство Ansible на конкретном примере - с помощью Ansible мы установим сервисы на машины и отредактируем их конфигурации:
- Ubuntu22, 192.168.1.2 – MariaDB
- Ubuntu23, 192.168.1.3 – MySQL
- Debian12, 172.16.1.4 – стек LAMP + WordPress
ВНИМАНИЕ! В конфигурациях мы используем шаблонные пароли для наглядности, обязательно измените их.
Установка
На управляемых узлах должен быть установлен Python версии 2.4 и выше, по умолчанию он вшит в большинство дистрибутивов Linux-систем. На сервер ansible-controller необходимо установить Ansible, рассмотрим пример для Ubuntu:
$ sudo apt update $ sudo apt install ansible
При установке будет создан каталог /etc/ansible с конфигурационными файлами: hosts и ansible.cfg - файл с настройками Ansible.
В простейшем виде файл hosts может содержать одну строку (адрес управляемого сервера): 192.168.1.2
Вы можете указать только ip-адреса серверов, но будет удобнее сразу записать номера портов ssh, пользователей, пароли и т.д. Укажем информацию о хостах:
$ nano hosts all: hosts: server-1: ansible_host: 192.168.1.2 ansible_connection: ssh ansible_user: root ansible_password: b1Ge62qUzIZhmtrH server-2: ansible_host: 192.168.1.3 ansible_connection: ssh ansible_user: root ansible_password: h1FF8LQUmapS5uj0 server-3: ansible_host: 172.16.1.4 ansible_connection: ssh ansible_user: root ansible_password: Byu0M1E7vJyxQ2m6
Теперь мы можем проверить доступность серверов:
root@ubuntu:/etc/ansible# ansible all -i hosts -m ping server-1 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" } server-3 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" } server-2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" }
Отлично, Ansible-controller имеет доступ ко всем необходимым серверам.
Начнем с MariaDB, для этого создадим новую конфигурацию Ansible:
$ nano mariadb-management.yml
Разберем из чего состоит этот файл конфигурации:
Сначала мы указываем информацию об управляемых серверах и переменные.
---
- name: MariaDB Management using Ansible
hosts: server-1
gather_facts: true become: true vars:
mysql_root_password: "StrongRootPassword!"
python_mysql: "{{ 'python3-mysqldb' if ansible_distribution|lower in ['debian', 'ubuntu'] else 'python3-PyMySQL' }}"
Устанавливаем и включаем сервисы:
tasks: - name: Installing MariaDB Server package: name: mariadb-server state: latest update_cache: yes - name: Installing python_mysql package: name: "{{ python_mysql }}" state: present update_cache: yes - name: start and enable mariadb server service: name: mariadb enabled: true state: started
Обновляем пароль СУБД:
- name: update mysql root password for all root accounts mysql_user: name: root host: "{{ item }}" password: "{{ mysql_root_password }}" login_user: root login_password: "{{ mysql_root_password }}" check_implicit_admin: yes priv: "*.*:ALL,GRANT" with_items: - "{{ ansible_hostname }}" - 127.0.0.1 - ::1 - localhost
Создаем новую БД и пользователя с полными привилегиями:
- name: Create a new database with name 'testdb' mysql_db: name: testdb state: present login_user: root login_password: "{{ mysql_root_password }}" - name: Create database user & grant all privileges on the testdb mysql_user: name: testuser1 password: Passw0rd! priv: 'testdb.*:ALL' host: '%' state: present login_user: root login_password: "{{ mysql_root_password }}"
Это все, что нужно для установки и настройки MariaDB на нашем сервере, пора запустить Ansible:
По выводу программы понятно, что все необходимые сервисы установлены и настроены.
Теперь поднимем MySQL-сервер, добавим необходимую базу данных и пользователя с привилегиями:
Создадим конфигурацию Ansible для MySQL:
$ nano mysql-management.yml --- - name: MySQL Server Management Using Ansible become: yes hosts: server-2 vars: mysql_root_password: "StrongRootPassword!" service_name: "{{ 'mysql' if ansible_distribution|lower in ['debian', 'ubuntu'] else 'mysqld' }}" python_mysql: "{{ 'python3-mysqldb' if ansible_distribution|lower in ['debian', 'ubuntu'] else 'python3-PyMySQL' }}" tasks: - name: Determine package manager ansible.builtin.set_fact: package_manager: "{{ 'apt' if ansible_distribution|lower in ['debian', 'ubuntu'] else 'yum' }}" - name: Installing MySQL and Required dependencies package: name: "{{ item }}" state: present update_cache: yes loop: - mysql-server - name: Installing python_mysql package: name: "{{ python_mysql }}" state: present update_cache: yes - name: Start and enable mysql service service: name: "{{ service_name }}" state: started enabled: yes - name: update mysql root password for all root accounts mysql_user: name: root host: "{{ item }}" password: "{{ mysql_root_password }}" login_user: root login_password: "{{ mysql_root_password }}" check_implicit_admin: yes priv: "*.*:ALL,GRANT" with_items: - "{{ ansible_hostname }}" - 127.0.0.1 - ::1 - localhost - name: Create a new database with name 'testdb' mysql_db: name: testdb state: present login_user: root login_password: "{{ mysql_root_password }}" - name: Create database user & grant all privileges on the testdb mysql_user: name: testuser1 password: Passw0rd! priv: 'testdb.*:ALL' host: '%' state: present login_user: root login_password: "{{ mysql_root_password }}"
Запускаем!
И теперь можно понять, что все сработало. Теперь у нас есть конфигурации, которые позволяют создавать СУБД с необходимыми параметрами за 5 минут сразу на нескольких машинах.
Наконец, попробуем что-то более серьезное: стек LAMP и WordPress с готовыми конфигурациями сервисов.
Так будет выглядеть структура нашего проекта:
- playbook.yml – конфигурация Ansible, в которой будет описано, какой результат нам необходим;
- hosts – список хостов;
- apache.conf.j2 и wp-config.php.j2 – конфигурации сервисов LAMP+WP;
- default.yml – здесь буду указаны пароли и пользователи СУБД, хост и порт веб-сервера.
$ nano playbook.yml --- - hosts: server-3 become: true vars_files: - vars/default.yml tasks: - name: Install prerequisites apt: name=aptitude update_cache=yes state=latest force_apt_get=yes tags: [ system ] - name: Install LAMP Packages apt: name={{ item }} update_cache=yes state=latest loop: [ 'apache2', 'mariadb-server', 'python3-pymysql', 'php', 'php-mysql', 'libapache2-mod-php' ] tags: [ system ] - name: Install PHP Extensions apt: name={{ item }} update_cache=yes state=latest loop: "{{ php_modules }}" tags: [ system ] # Apache Configuration - name: Create document root file: path: "/var/www/{{ http_host }}" state: directory owner: "www-data" group: "www-data" mode: '0755' tags: [ apache ] - name: Set up Apache VirtualHost template: src: "files/apache.conf.j2" dest: "/etc/apache2/sites-available/{{ http_conf }}" notify: Reload Apache tags: [ apache ] - name: Enable rewrite module shell: /usr/sbin/a2enmod rewrite notify: Reload Apache tags: [ apache ] - name: Enable new site shell: /usr/sbin/a2ensite {{ http_conf }} notify: Reload Apache tags: [ apache ] - name: Disable default Apache site shell: /usr/sbin/a2dissite 000-default.conf notify: Restart Apache tags: [ apache ] # MySQL Configuration - name: Set the root password mysql_user: name: root password: "{{ mysql_root_password }}" login_unix_socket: /var/run/mysqld/mysqld.sock tags: [ mysql, mysql-root ] - name: Remove all anonymous user accounts mysql_user: name: '' host_all: yes state: absent login_user: root login_password: "{{ mysql_root_password }}" tags: [ mysql ] - name: Remove the MySQL test database mysql_db: name: test state: absent login_user: root login_password: "{{ mysql_root_password }}" tags: [ mysql ] - name: Creates database for WordPress mysql_db: name: "{{ mysql_db }}" state: present login_user: root login_password: "{{ mysql_root_password }}" tags: [ mysql ] - name: Create MySQL user for WordPress mysql_user: name: "{{ mysql_user }}" password: "{{ mysql_password }}" priv: "{{ mysql_db }}.*:ALL" state: present login_user: root login_password: "{{ mysql_root_password }}" tags: [ mysql ] # UFW Configuration - name: "UFW - Allow HTTP on port {{ http_port }}" ufw: rule: allow port: "{{ http_port }}" proto: tcp tags: [ system ] # WordPress Configuration - name: Download and unpack latest WordPress unarchive: src: https://wordpress.org/latest.tar.gz dest: "/var/www/{{ http_host }}" remote_src: yes creates: "/var/www/{{ http_host }}/wordpress" tags: [ wordpress ] - name: Set ownership file: path: "/var/www/{{ http_host }}" state: directory recurse: yes owner: www-data group: www-data tags: [ wordpress ] - name: Set permissions for directories shell: "/usr/bin/find /var/www/{{ http_host }}/wordpress/ -type d -exec chmod 750 {} \\;" tags: [ wordpress ] - name: Set permissions for files shell: "/usr/bin/find /var/www/{{ http_host }}/wordpress/ -type f -exec chmod 640 {} \\;" tags: [ wordpress ] - name: Set up wp-config template: src: "files/wp-config.php.j2" dest: "/var/www/{{ http_host }}/wordpress/wp-config.php" tags: [ wordpress ] handlers: - name: Reload Apache service: name: apache2 state: reloaded - name: Restart Apache service: name: apache2 state: restarted
----
$ mkdir vars $ nano vars/default.yml
----
#System Settings php_modules: [ 'php-curl', 'php-gd', 'php-mbstring', 'php-xml', 'php-xmlrpc', 'php-soap', 'php-intl', 'php-zip' ] #MySQL Settings mysql_root_password: "mysql_root_password" mysql_db: "wordpress" mysql_user: "sammy" mysql_password: "mysql_password" #HTTP Settings http_host: "my_site.com" http_conf: "my_site.conf" http_port: "80"
----
$ mkdir files $ nano files/apache.conf.j2
----
<VirtualHost *:{{ http_port }}> ServerAdmin webmaster@localhost ServerName {{ http_host }} ServerAlias www.{{ http_host }} DocumentRoot /var/www/{{ http_host }}/wordpress ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined <Directory /var/www/{{ http_host }}> Options -Indexes AllowOverride All </Directory> <IfModule mod_dir.c> DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm </IfModule> </VirtualHost>
----
$ nano files/wp-config.php.j2 <?php define( 'DB_NAME', '{{ mysql_db }}' ); define( 'DB_USER', '{{ mysql_user }}' ); define( 'DB_PASSWORD', '{{ mysql_password }}' ); define( 'DB_HOST', 'localhost' ); define( 'DB_CHARSET', 'utf8' ); define( 'DB_COLLATE', '' ); define('FS_METHOD', 'direct'); define( 'AUTH_KEY', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); define( 'SECURE_AUTH_KEY', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); define( 'LOGGED_IN_KEY', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); define( 'NONCE_KEY', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); define( 'AUTH_SALT', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); define( 'SECURE_AUTH_SALT', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); define( 'LOGGED_IN_SALT', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); define( 'NONCE_SALT', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}' ); $table_prefix = 'wp_'; define( 'WP_DEBUG', false ); if ( ! defined( 'ABSPATH' ) ) { define( 'ABSPATH', dirname( __FILE__ ) . '/' ); }
require_once( ABSPATH . 'wp-settings.php' );
Все файлы созданы, можно запускать ansible-playbook:
Все установлено, проверяем:
Отлично, наш сервер работает. Теперь вы можете использовать эту конфигурацию Ansible, чтобы быстро устанавливать и настраивать свои веб-серверы.
Подведем итоги:
Для работы с Ansible не нужны агенты на управляемых серверах. Он использует Python и Yaml, простые и удобные языки для новичка. Так же, программа предоставляет набор надежных функций и встроенных модулей, которые облегчают написание сценариев автоматизации.
Это эффективный и расширяемый Open Source инструмент, который позволяет управлять конфигурациями удаленных серверов и сохранять их состояние. Мы лишь поверхностно прошлись по его возможностям, показали как пишутся сценарии для решения различных задач.
Все варианты использования Ansible в рамках одной статьи охватить невозможно и не нужно, а для желающих узнать больше мы подготовили несколько ссылок:
- Официальный аккаунт на github c исходным кодом проекта и хорошим набором примеров проектов.
- Документация Ansible.
- Готовые конфигурации Ansible под разные задачи.
- Управление Windows-сервером.
Виртуализация — неизбежная и незаменимая часть современной ИТ-инфраструктуры любого бизнеса. Что это такое и как она работает, рассмотрим в этой статье.
01 октября, 2024Как мы используем продукты VMware для виртуальных серверовМы строим облачную инфраструктуру на основе архитектуры этого бренда: используем VMware vSphere для создания виртуальных серверов и управления ими, панель VMware vCloud Director для управления облаком. В статье рассказываем, почему выбираем именно эти решения.
28 сентября, 2024Частные, публичные и гибридные облака: разные виды облачных сервисовРассказываем, что представляет собой гибридное облако, как оно работает, какие особенности имеет и кому подойдет
20 августа, 2024