На управляющей машине устанавливаем ansible:
# apt-get install ansible
В домашнем каталоге создаём каталог, в котором будем хранить все файлы для настройки удалённых компьютеров. Если нужно работать над проектом совместно с другими системными администраторами и отслеживать изменения, сделанные ими, то лучше сразу же создать в этом каталоге git-репозиторий:
$ mkdir playbooks $ git init
Создадим файл конфигурации ansible.cfg и пропишем в него следующие настройки:
[defaults] inventory = hosts remote_user = ansible private_key_file = .ssh/id_rsa
Сразу же сгенерируем ssh-ключ, который будем устанавливать на удалённые системы для их настройки при помощи ansible:
$ mkdir .ssh $ ssh-keygen -f .ssh/id_rsa $ chmod go= -R .ssh
Каталог .ssh помещать в git-репозиторий не стоит.
Создадим файл hosts, в котором будем отмечать узлы, управляемые при помощи ansible. Например, файл с одним-единственным узлом с именем mon может выглядеть следующим образом:
mon ansible_host=169.254.252.2
На управляемой машине после настройки сети и установки OpenSSH-сервера необходимо установить несколько пакетов, которые будут использоваться ansible:
# apt-get install python2.7-minimal python2.7-stdlib python-minimal
Также установим sudo, чтобы при удалённой настройке можно было выполнять действия от имени пользователя root:
# apt-get install sudo
Добавим учётную запись специально для удалённой настройки:
# useradd -c 'Ansible account' -m ansible
Сразу же дадим возможность этой учётной записи использовать sudo для работы с правами пользователя root:
# visudo
Добавляем строчки:
Defaults:ansible !requiretty ansible ALL=(root:ALL) NOPASSWD:ALL
Скопируем на удалённую машину SSH-ключ:
$ ssh-copy-id -i .ssh/id_rsa.pub ansible@169.254.252.2
Для первого сценария возьмём простейшую задачу - настройки файла /etc/resolv.conf на удалённом компьютере.
Создадим на управляющей машине в каталоге проекта файл сценария resolvconf.yml со следующим содержимым:
--- - name: Configure resolv.conf hosts: mon become: True tasks: - name: copy /etc/resolv.conf template: src: templates/resolv.conf dest: /etc/resolv.conf owner: root group: root mode: 0644
Создадим каталог templates для шаблонов файлов конфигурации:
$ mkdir templates
Создадим шаблон конфигурации templates/resolv.conf для файла /etc/resolv.conf управляемого компьютера:
{% if resolvconf.domain %} domain {{ resolvconf.domain }} {% endif %} {% for ip in resolvconf.nameservers %} nameserver {{ ip }} {% endfor %}
Значения переменных хранятся в так называемом реестре ansible. Он представляет собой файл в формате YML и может находиться либо в каталоге host_vars, либо в каталоге group_vars. В каталоге host_vars хранятся настройки, специфичные для каждого отдельного управляемого узла. Внутри этого каталога создаётся фай, имя которого совпадает с указанным в файле hosts. В каталоге group_vars хранятся настройки, общие для определённой группы узлов. Внутри этого каталога создаётся файл, имя которого совпадает с именем группы, указанным в файле hosts.
Создадим каталог host_vars с переменными узлов:
$ mkdir host_vars
И внутри каталога создадим файл mon со следующим содержимым:
resolvconf: domain: stupin.su nameservers: - 169.254.252.1
Осталось выполнить наш первый простейший сценарий. Для этого воспользуемся командой ansible-playbook:
$ ansible-playbook resolvconf.yml
В прошлом сценарии имелась опция, которая заставляла выполнять действия от имени пользователя root:
become: True
В случае, если нужно выполнять действия от имени другого, непривилегированного пользователя, можно столкнуться с проблемами. Например, администратором баз данных PostgresSQL является системный пользователь postgres. Создать нового пользователя или базу данных можно только от его имени. Поэтому, задача такого вида:
- name: createuser -P <login> postgresql_user: name: "{{ item.login }}" password: "{{ item.password }}" with_items: "{{ postgresql_databases }}" when: postgresql_databases
Завершится такой ошибкой:
unable to connect to database: ВАЖНО: пользователь "postgres" не прошёл проверку подлинности (Peer)
Однако и простого указания опций переключения на пользователя postgres оказывается недостаточно:
- name: createuser -P <login> become: True become_user: postgres postgresql_user: name: "{{ item.login }}" password: "{{ item.password }}" with_items: "{{ postgresql_databases }}" when: postgresql_databases
В этом случае попытка выполнить задачу завершается следующей ошибкой (отформатировано для наглядности):
Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: chown: изменение владельца '/tmp/ansible-tmp-1549203485.91-25063771984034/': Операция не позволена chown: изменение владельца '/tmp/ansible-tmp-1549203485.91-25063771984034/postgresql_user.py': Операция не позволена ). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user
После доработки в соответствии с материалами по ссылке, указанной в тексте ошибки, задача приобретает следующий вид:
- name: createuser -P <login> become: yes become_user: postgres vars: ansible_ssh_pipelining: true postgresql_user: name: "{{ item.login }}" password: "{{ item.password }}" with_items: "{{ postgresql_databases }}" when: postgresql_databases
Но и этого оказывается недостаточно, т.к. возникает следующая ошибка:
failed: [mon] (item={u'login': u'zabbix', u'password': u'xxxxxxxxxxxxxxxx', u'name': u'zabbix'}) => { "failed": true, "item": { "login": "zabbix", "name": "zabbix", "password": "xxxxxxxxxxxxxxxx" }, "module_stderr": "sudo: a password is required\n", "module_stdout": "" } MSG: MODULE FAILURE
Как видно, ansible пытается переключиться на указанного пользователя при помощи sudo. Но, когда я настраивал sudo для ansible, то указал разрешение переключаться без указания пароля только на пользователя root:
ansible ALL=(root:ALL) NOPASSWD:ALL
Чтобы разрешить пользователю ansible переключаться ещё и на пользователя postgres, нужно добавить через команду visudo ещё одно разрешение:
ansible ALL=(postgres:ALL) NOPASSWD:ALL
После этого задача выполняется успешно.
Иногда отложенный перезапуск сервиса может таить в себе проблемы. Например, если в конфигурации сервиса изменился прослушиваемый им порт, новые настройки не вступят в силу, пока не будет достигнут конец сценария. В то же время, действия, выполняемые до вызова отложенного перезапуска сервиса, могут использовать новый порт для подключения к сервису, не зная, что сервис ещё не был перезапущен и его новые настройки ещё не вступили в силу.
Именно так получилось у меня при подготовке роли, настраивающей сервис PostgreSQL. После изменения номера порта может потребоваться создать новые базы данных или пользователей, но пока сервис не был перезапущен, подключиться к нему по новому порту не получится, а старый может быть не известен. В таком случае можно запомнить результаты выполненных действий в переменных при помощи выражения register:
- name: vim /etc/postgresql/9.6/main/pg_hba.conf template: src: etc/postgresql/9.6/main/pg_hba.conf dest: /etc/postgresql/9.6/main/pg_hba.conf owner: postgres group: postgres mode: 0640 register: pg_hba - name: vim /etc/postgresql/9.6/main/postgresql.conf template: src: etc/postgresql/9.6/main/postgresql.conf dest: /etc/postgresql/9.6/main/postgresql.conf owner: postgres group: postgres mode: 0644 register: postgresql
И затем проверить результаты этих действий и немедленно перезапустить сервис, если его конфигурация была изменена:
- name: systemctl restart postgresql service: name: postgresql state: restarted when: (pg_hba.changed or postgresql.changed)
Для более-менее полноценного использования Ansible рекомендую изучить роли. Роль представляет собой совокупность сценария, настроек по умолчанию и используемых файлов и шаблонов. В сценарии можно будет указать список ролей, которые нужно применить к узлам, указанным в сценарии. Благодаря ролям становится возможным собирать сценарии из крупных строительных блоков - ролей.