Найти тему

Ansible - удаленная настройка конфигураций

Оглавление

Представим, что у вас есть 10 серверов под разные или похожие задачи. Каждую машину нужно периодически обновлять, изменять ее конфигурацию. Часто необходимо поднять и настроить сразу несколько серверов в короткие сроки. Конечно, можно подключаться к каждому по SSH и вручную вносить необходимые изменения, но это очень долго и увеличивает возможность совершения ошибок из-за человеческого фактора.

Для эффективного решения подобных задач DevOps-специалисты используют систему удаленного управления конфигурацией - 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 мы установим сервисы на машины и отредактируем их конфигурации:

1) Ubuntu22, 192.168.1.2 – MariaDB

2) Ubuntu23, 192.168.1.3 – MySQL

3) Debian12, 172.16.1.4 – стек LAMP + WordPress

С помощью Ansible мы установим сервисы на машины и отредактируем их конфигурации.

ВНИМАНИЕ! В конфигурациях мы используем шаблонные пароли для наглядности, обязательно измените их.

Установка

На управляемых узлах должен быть установлен 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 с готовыми конфигурациями сервисов.

Так будет выглядеть структура нашего проекта:

1) playbook.yml – конфигурация Ansible, в которой будет описано, какой результат нам необходим;

2) hosts – список хостов;

3) apache.conf.j2 и wp-config.php.j2 – конфигурации сервисов LAMP+WP;

4) 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 в рамках одной статьи охватить невозможно и не нужно, а для желающих узнать больше мы подготовили несколько ссылок:

1) https://github.com/ansible/ — официальный аккаунт на github c исходным кодом проекта и хорошим набором примеров проектов

2) https://docs.ansible.com/ - документация Ansible

3) https://github.com/do-community/ansible-playbooks - готовые конфигурации Ansible под разные задачи

4) https://medium.com/the-sysadmin/managing-windows-machines-with-ansible-60395445069f - управление Windows-сервером

Ставьте лайк, если было полезно! Присоединяйтесь в нашему Телеграм-каналу, пишем про облако, мануалы и кейсы работы.