Ansible копирование нескольких файлов

Обновлено: 07.07.2024

Статья подготовлена на основе уроков из открытой темы "Установка LEMP стека с помощью Ansible" курса по Ansible от Слёрм. Автор – Всеволод Севостьянов, Lead Engineer в Vene.io (Affiliate marketing solution). Первые две темы курса доступны на Youtube.

Материал этого урока будет интересен тем, кто разобрался с установкой Ansible и готов написать свой первый плейбук. Результатом будет плейбук, устанавливающий nginx на удалённой машине.

Hosts

Начнём наше знакомство с Ansible с мануала по командам.

Плох тот админ, который не читает маны – верно?

На что смотрим. Первое – это обязательный аргумент pattern, который указывает, какие хосты мы берем, на каких машинах мы будем выполнять наши команды. Мы будем выполнять на всех – all. Второе, персональная команда – вывести хосты, то есть, команда, которая выведет нашу машину.

All означает – все хосты, которые у нас возможны. Увидим ответ, что список пустой. Почему так происходит? Потому что Ansible по умолчанию берет данные из /etc/ansible/hosts. Посмотрим, что это за файл.

Здесь всё задокументировано

Здесь всё задокументировано

Видим, что мы можем указывать хосты просто через enter и указывать их IP-адреса, либо их доменные имена. Можем их группировать.

Можем даже циклы делать, то есть, говорить, что вот такие хосты у нас существуют в сети и он, соответственно, их развернет просто в список хостов. Нас, естественно, этот файлик не устраивает, и менять мы его не хотим. Мы напишем свой.

Заходим в папочку ansible, в нашем проекте. И создаём файлик, я назову его hosts.ini. Ini – это как раз тот самый формат, когда вы всё перечисляете просто через enter и пишите строку, стандартный формат конфигурации.

Укажем в первой строке IP-адрес нашего второго хоста, то есть, нашего сервера непосредственно. У меня 192.168.50.5 и теперь запускаем команду Ansible ещё раз.

Естественно, он никак не отреагирует, он по-прежнему берет данные из файлика /etc/ansible/hosts.

Для того чтобы он брал данные из нашего файлика – вызовем команду h и увидим в списке команду –i. Ansible называет файлики hosts – эти файлики, где у нас все машины перечислены, inventory. То есть, как по аналогии с каким-то кладовщиком – у него есть инвентарь и в нём указаны все машины, которые нам принадлежат. Мне кажется, это вполне логичным, легко запоминается и указывается через –i.

Мы находимся в корневой папке пользователя и для того, чтобы нам перейти в папку выше – мы указываем ./ansible/hosts.ini.

И давайте разберемся немножко с тем, как запускать команды из Ansible. Попробуем подключиться к удаленному хосту и запустить что-нибудь. В Ansible все команды являются модулями и указываются с помощью ключевого слова m. Запустим стандартный модуль, называемый ping, который ничего не сделает на машине, кроме того, как даст ей команду ping. Это команда, которая физически выполняется Ansible на удаленной машине. Он в неё заходит, загружает модуль Python, вызывает команду ping. И выдаёт ответ.

Нас просят подтвердить, поскольку подключается по SSH, нужно подтверждение сертификата. И мы увидим первую ошибку, что доступ закрыт. Стандартная ошибка, это значит, что нам нужно ввести пароль. На этот случай у Ansible существует команда --ask-pass.

Которая спрашивает с каким паролем мы заходим. Следующая ошибка, с которой мы сталкиваемся: нельзя использовать пароли без установки команды sshpass. Проблема решается просто.

Итак, команда sshpass установлена, и мы, соответственно, вызываем команду ping и задаём ему пароль.

При этом, как мы увидим, команда выполнилась, вывела нам ответ в формате json. Написала, что на удаленной машине у нас Python3, который мы используем для выполнения этого модуля, ничего не изменилось на ней. Команда, не меняющая ничего, и ответ на ping – pong.

Возможно вы заметили, что в примере я не указывал пользователя Ansible, потому что нахожусь под пользователем vagrant и Ansible по умолчанию использует того же пользователя для подсоединения по ssh.

Теперь следующий момент, который мы с вами посмотрим – это как так написать файлик hosts, чтобы больше вот этим всем не заниматься. Потому что если у вас пятьдесят машин и вводить для каждой пароль даже один раз – не очень хороший вариант.

Одним из атрибутов нашего файлика hosts является то, что мы можем присвоить каждой из машин, находящихся в нём какие-то специфичные для неё параметры. И одним из набора специфичных параметров для этой машины являются переменные ansible_user и ansible_password, которые, соответственно, задают пользователя и пароль.

Теперь, если мы запустим Ansible, если мы уберем --ask-pass, то есть, не будем запрашивать пароль, но оставим всё остальное, то, соответственно, все равно нам вернётся success, на этот раз никто у нас никакой пароль не спрашивал.

Таким образом, если у нас будет ещё какая-то другая машина в системе, на которой другой пользователь, мы можем указать всё в файлике hosts и залогиниться на другую машину. Выполнить там точно также команды. Таким образом, мы разделяем сами команды и необходимые параметры, данные для этих машин. У нас всё готово к тому, чтобы писать первый плейбук.

NGINX

Итак, что такое плейбук? Это термин, взятый из футбола. Обозначает книгу тренера, который там что-то записывает и задаёт сценарий игре. Плейбук– это оно и есть, список сценариев для запуска Ansible. То, что мы делали командой Ansible –m, просто запущенная с разными командами, разными аргументами несколько раз. Плейбуки позволяют нам также определить, на каких хостах мы им запускаем и какие задачи мы им задаём. И мы посмотрим, как это работает.

В папке ansible создадим файл playbook.yml. Плейбуки пишутся в формате yaml. Мы будем знакомиться с этим форматом в процессе написания плейбуков. На данный момент, что нас интересует? Плейбуки начинаются с трёх дэшей или с трёх чёрточек и закачиваются тремя точками.

Этот формат необязательный. Я, например, не использую три точки, но начинаю с чёрточек, потому что это достаточно удобно. Плейбуки позволяют нам делать комментарии, поэтому я здесь сразу и напишу.

Соответственно, в плейбуке нужно обязательно ставить какие-то play. Play задаются с помощью массива, то есть в yaml следующая запись обозначает массив.

И здесь мы можем написать, например, разные переменные. Наш плейбук в себе будет содержать play, и каждый play в себе обязан содержать hosts – это также как мы писали в консоли Ansible – all. Здесь то же самое. Это базовая вещь, базовый play, и мы можем запустить плейбук.

Если мы хотим создать второй play – мы создаём второй элемент массива, ему определяем какой-то второй параметр и для yaml это значит, что это массив с двумя переменными. Сейчас нам это не нужно.

Переходим в консоль Ansible. Командой ls увидим, что у нас есть файлы hosts.ini и playbook.yml. И для того, чтоб запустись плейбук, у Ansible существует консольная команда: ansible-playbook. Она очень похожа на команду Ansible, за исключением того, что вместо передачи аргументов хостов, мы передаём аргумент плейбук, то есть путь к файлику playbook.yml. Укажем hosts.ini, как файлик инвентаря, то есть, это две базовые вещи, которые нужно ansible-playbook для того, чтобы работать. Какие хосты и что мы делаем.

Теперь он запускает PLAY [all] – это play, который нам говорит для всех хостов. И первый TASK [Gathering Facts], который мы даже не указывали – это собирание фактов, первый модуль, который загрузится – это модуль Ansible, который загружается на машину и собирает все факты с этой машины. На данном моменте нам достаточно знать, что каждый play в плейбуке собирает факты о машине – это может быть операционная система, версия Python, которая там стоит, IP-адреса, порты и так далее.

После сбора фактов Ansible возвращает нам команду ok и возвращает статистику. Какие задачи были ok, какие что-то изменили в системе, какие не смогли достичь удалённой системы, задачи провалившиеся при настройке, пропущенные, восстановленные, и какие задачи были проигнорированы системой.

Каждый хост, каждый play в плейбуке характеризуется целью, на какие хосты мы его применяем и набором задач, так называемыми task-ами. Task-и – это тоже массив, потому что task на play может быть много, соответственно, как play в плейбуке, здесь всё логично. И каждый task, как минимум, содержит в себе имя. Имя, также как и hosts, — это строка. Строки в yaml задаются любо через кавычки, либо без них. Я рекомендую кавычки, потому что в таком случае yaml не будет теряться при попытке скастовать что-то, то есть, если у вас там строка — это строка, если у вас число – это число и к тому же, это очень хорошо видно в IDE. И первая task-а для нас – это будет установка самого nginx на удалённой машине. Давайте, так её и назовём. Install nginx via apt. И поехали делать task.

После указания имени task, нам нужно указать модуль, который будет его выполнять. Как вот мы указывали -m ping, здесь надо сделать тоже самое. Поскольку nginx у нас установится через систему APT, мы можем посмотреть, как же она называется в Ansible.

То есть, Ansible позволяет выполнять консольные команды, как мы посмотрим в дальнейшем, но всегда рекомендую использовать модули, потому что модули обеспечивают одно важное качество Ansible.

Существует модуль ansible.builtin.apt, который как раз позволяет устанавливать нам софт через apt-packages. И здесь все его параметры и достаточно интересная документация с примерами. Я смотрю на примеры, как человек со стажем, как правило, они более актуальны, чем документация. В данном случае они совпадают. И смотрим, что для apt нужно указать имя и state.

Смотрим. Для начала: разница как раз между Ansible 2.9, 2.10 и 2.11 в том, что Ansible будет форсить, будет заставлять людей использовать полные имена модулей. Потому что, если кто-то еще напишет модуль apt, и он у вас будет установлен в системе, Ansible может потеряться. Он может не понять, какой apt ему запускать. Поэтому надо всегда указывать полный путь. И так мы и будем поступать. Соответственно, здесь указывается полный путь к модулю. И дальше указываются параметры модуля.

Важно понимать, что это все словари. Имя — это ключ словаря и строка "Install nginx via apt" — это значение. Ansible.builtin.apt – это тоже ключ, а значение у него это список аргументов и они в yaml идут через 2 пробела. Это важно, потому что если у вас не будет нужного количества пробелов, yaml будет ругаться на то, что он не может ничего сконфигурировать. И поэтому я и рекомендую использовать какую-нибудь IDE, а не писать просто это все в блокноте и следить там руками за пробелами. Это неудобно.

Поэтому, указываем первый параметр — это имя пакета. Имя пакета у нас просто nginx.

И второй параметр — это state. Соответственно, что такое state? State, как написано в документации — это в каком состоянии мы хотим найти пакет. Ansible, он сам по себе декларативный, то есть, вы не указываете в плейбуке, что ему нужно сделать, вы указываете, что вы хотите видеть. И state – это как раз очень хороший пример. То есть вы не говорите, что я хочу установить такой-то nginx, вы говорите: я хочу видеть пакет nginx в apt в таком-то state-е. По умолчанию state – present. Это значит, что если у вас уже есть какой-то пакет в Ansible, то state у него, соответственно, будет неизменным. И есть state – latest. В таком случае, если apt найдет какую-то более свежую версию пакета, то он попробует ее обновить.

Последняя команда, которую я хотел бы задать здесь, это update_cache. Это тоже самое, что вы запускаете каждый раз перед запуском любой команды apt, соответственно sudo apt. Update, которая просто обновит cache всех библиотек, которые у вас лежат в архиве.

Запускаем Плейбук в консоли Ansible второй раз.

Первая команда Gathering Facts. Вторая команда Install nginx via apt. И она провалилась. То есть написано "Failed to lock apt for exclusive operation". Это не очень подробное описание, но оно нам позволяет понять, что не получилось у apt получить какой-то lock.

Почему? Потому что существует в Ansible политика выполнения команд от того пользователя, которым вы залогинились. То есть в данном случае пользователь vagrant пытается установить что-то через apt. И не может, потому что apt пишет в системные файлы, которым нужен root.

Для того, чтобы Ansible стал root, мы используем команду в play become true, которая будет выполнятся для всех task в этом play. Можем ее использовать внутри task, можем ее использовать внутри play. В данном случае я хочу, чтобы все, что мы делали, делалось через sudo под root. И поэтому ставлю ее в непосредственно play.

Теперь команда будет запущенна от root. Можно видеть, что true в данном случае не строка, а булево. То есть истина или ложь. Точно также, как и update_cache. Это еще один тип переменных в формате yaml.

Запускаем Плейбук в консоли Ansible третий раз.

И мы видим, что nginx успешно установился. Также видим новый статус – changed. Это значит, что nginx что-то изменил в системе – установил пакет.

Здесь самое время сказать, что Ansible является идемпотентным, то есть, он задуман, как идемпотентная система. Что это значит? При запуске одного и того же плейбука 2 раза на одной и той же системе, у вас в этой системе ничего не изменится. Второй раз apt даже пытаться не будет, он проверит список пакетов, он увидит nginx и не будет ничего дальше делать. То есть статус ok — это значит, что система соответствует тому статусу, который вы от неё ожидаете.

Теперь чтобы проверить, что nginx действительно настроен, возьмём любой шаблон лендига и запустим.

Создаём task. Удаляем папку по умолчанию var/www/html. Для того, чтобы скопировать нашу папку с нашим лендингом для заглушки на веб-сайт. Воспользуемся другой командой Ansible – ansible.builtin.file. Указываем путь – path. И дальше помним про идемпотентность – указываю state – absent. Просто указываю state. То есть, как там всё будет происходить, как эти файлы будут удалятся. Ansible написан в таком духе, что мы описываем состояние системы.

Ну, и последнее, что мы делаем, копируем наш лендинг в папку var/www/html. У меня сейчас лендинг в папке files в директории Ansible. Пишем последнее имя task "Copy our lending to /var/www/html folder". Будем пользоваться командой ansible.builtin.copy, которая будет копировать файлы с нашей локальной машины на удаленную машину.

Указываем путь. Пути поддерживаются абсолютные и относительные. На нашей машине, скорее всего, мы не знаем, откуда мы будем запускать Ansible, поэтому пишем относительные пути – scr: "files/html" И в dest мы указываем "/var/www/". В чем смысл? Когда мы копируем через vagrant upload. Vagrant upload нам копирует содержимое папки внутрь. В данном случае Ansible будет копировать всю папку. И, поэтому, если мы хотим скопировать что-то в var/www/html, нам нужно назвать папку соответствующим образом и скопировать ее корневую директорию.

Далее мы указываем owner и group. Это просто пользователь и группа. И указываем mode – режим. Если не указать пользователя, группу и режим, то Ansible будет пытаться скопировать это все под пользователем, под которым он запущен. И с become true это, скорее всего, будет root.

Запускаем наш Playbook ещё раз. Он идемпотентный, то есть второй раз nginx у нас не установится. Наш объект будет удален и копируется наш новый лендинг в var/www/html.

Осталось проверить, как это работает. Открываем IP-адрес нашего сервиса. Всё, поздравляю, nginx настроен. Буквально 3 команды в плейбуке.

Инструкция представляет из себя шпаргалку по работе с Ansible. У автора не стоит задачи подробного пояснения всех операций — только описание задачи и пример того, как ее можно решить с помощью ansible. Для более подробного описания я постараюсь указать ссылки на официальную документацию. Также в данную шпаргалку не войдут все возможные действия, которые можно выполнить с помощью данной системы — только популярные и те, с которыми приходилось сталкиваться самому автору. По мере возможности, их список будет пополняться.

Для удобства, мы попробуем разбить примеры на операции, которые логически можно объединить в одну группу.

Получение информации

Сюда войдут примеры, которые позволят собирать информацию, выводить ее на экран, помогать в отладке и всякое такое.

1. Показать информацию об удаленной системе, на которой запускается ansible.

Выполняется с помощью модуля debug, который должен показать содержимое ansible_facts:

- name: Print all available facts
ansible.builtin.debug:
var: ansible_facts

* ansible_facts содержит массив данных с информацией о системе. Однако, функция сборки информации может быть отключена (так как на ее работу тратится, относительно, много времени) в настройках плейбука с помощью опции gather_facts: false — в этом случае, значение нужно изменить на true.

Также мы можем обратиться к конкретному элементу массива ansible_facts, получив информацию о конкретной настройке или опции:

* например, имя компьютера.

2. Отображение на экран переменной.

Выше мы уже использовали debug для отображения переменной — принцип тот же:

* при выполнении задачи на экране мы увидим значение переменной variable. Обратите внимание, что запись ansible.builtin.debug и debug — это одно и то же, то есть, ansible.builtin можно не писать.

3. Сохранение результата в переменную.

Выполняется с помощью register:

- name: Run a shell command and register its output as a variable
shell: command
register: command_result

* в данном примере мы запишем в переменную command_result все то, что мы получили с помощью команды command.

Вывести на экран содержимое можно с помощью debug:

- name: Show Value of Variable
debug:
var: command_result.stdout

* обратите внимание, что мы выводим не все содержимое, а только stdout, то есть то, что должна была вывести в консоль команда.

4. Получить список сервисов.

Для этого существует service_facts:

- name: Populate service facts
ansible.builtin.service_facts:

- name: Print all available facts
ansible.builtin.debug:
var: ansible_facts.services

* цель достигается двумя задачами. В первой мы собираем информацию о сервисах с помощью service_facts, второй — выводим на экран содержимое.

Проверки и условия

В данную группу войдут действия, которые помогут нам ограничить выполнение задач.

1. Проверка на пустую папку.

Задачи сводится к двум операциям:

  • получении списка файлов в целевом каталоге (например, с помощью команды ls) и регистрации полученного значения в переменную с помощью register.
  • проверка содержимого переменной, которую мы получили на шаге 1 с помощью when.

Пример будет таким:

- name: Register Contents of PGDATA Folder
shell: ls /var/lib/postgresql/11/main
register: pg_contents

- name: Init PostgreSQL DB
shell: /opt/pgpro/std-11/bin/pg-setup initdb
environment:
PGDATA: "/var/lib/postgresql/11/main"
when: pg_contents["stdout_lines"] | length == 0

2. Проверить, определена ли переменная.

Для этого используется опция is defined (определена) или is not defined (не определена):

when: pgpro is defined

when: pgpro is not defined

* в данном примере мы проверим наличие переменной pgpro. На практике такая проверка имеет значение, так как если мы попробуем выполнить действия с несуществующей переменной, Ansible нам вернет ошибку.

В официальной документации про это сказано в статье о when (ссылка выше).

3. Выполнение команды, если сервис в рабочем состоянии.

Нам необходимо получить информацию о службах с помощью service_facts, после чего можно уже делать проверку с помощью when:

- name: Populate service facts
ansible.builtin.service_facts:

- name: Stop Service If Running One
shell: systemctl stop apache2
when: ansible_facts.services["apache2.service"] is defined and ansible_facts.services["apache2.service"].state == "running"

* в данном примере мы проверим, есть ли служба apache2 и запущена ли она. Если это так, то мы ее останавливаем.

Подробнее о service_facts можно прочитать в документации (ссылка выше в разделе 4. Получить список сервисов).

Установки пакетов, модулей и расширений

В данном разделе мы коснемся всего, что приводит к установке чего бы то ни было. А именно:

  • Установки пакетов в систему.
  • Загрузки исходников.
  • Установке дополнительных модулей.
  • Распаковке архивов.

Рассмотрим это подробнее.

1. Установка модуля в nodejs.

Установка модулей в nodejs выполняется с помощью npm. Для него в ansible есть отдельная функция:

- name: Install nodejs modules.
npm:
name: newman
global: yes

* в данном примере будет выполнена установка newman, которая будет доступна всем проектам (опция global).

2. Загрузка из GIT.

Выполняется с помощью модуля git:

* в данном примере мы сделаем клон репозитория в каталог /tmp/docker-compose.

3. Распаковка архива.

Выполняется с помощью unarchive:

* в данном примере мы распакуем исходник для nginx в каталог /tmp. Обратите внимание на две вещи:

  • Мы используем переменную nginx_ver. Данная переменная должна быть определена при запуске плейбука, или в инвентарном файле, или в var, или в default.
  • Опция creates позволит не выполнять операцию, если существует файл /tmp/nginx->.tar.gz.

Настройка системы

В данном разделе мы рассмотрим процессы, которые больше подходят для категории настройки системы.

1. Добавить задание в cron.

Выполняется с помощью модуля cron:

* в данном примере мы создадим задание для запуска команды /scripts/command.sh каждый день, каждые 6 часов.

2. Добавить публичный ключ хоста в known_hosts.

Делается с помощью known_hosts. Пример из официальной документации:

3. Создание новых SSH-ключей для сервера.

Создание ключей реализуется с помощью модуля openssh_keypair:

* в данном примере мы создадим 4 ключа разных типов: dsa, ecdsa, ed25519, rsa. Так как у каждого из них свои требования к размеру, перечень представлен в виде двумерного массива. Ключи будут созданы в каталоге /etc/ssh/.

4. Создание системной учетной записи.

Для этого есть модуль user. У него много опций, но для создания системной учетной записи нам достаточно:

- name: Create User Consul
user:
name: consul
system: yes
comment: "Consul Agent"

* в данном примере будет создана учетная запись consul.

5. Работа с systemd.

Для данной настройки есть одноименный модуль systemd. Рассмотрим варианты его использования.

а) перечитать конфигурацию (необходимо делать каждый раз, когда мы меняем настройки юнита):

- name: systemd reload
systemd:
daemon_reload: yes

б) разрешить сервис (автозапуск):

- name: mysql enable
systemd:
name: mysql
enabled: yes

* для сервиса mysql.

в) перезапустить сервис:

- name: mysql reload
systemd:
name: mysql
state: restarted

* для сервиса mysql.

6. Настройка брандмауэра.

Выполняется разными модулями в зависимости от используемой системы управления netfilter:

Рассмотрим небольшие примеры.

- name: Block specific IP
iptables:
chain: INPUT
source: 8.8.8.8
jump: DROP

Добавить 80 порт:

Добавить порты с циклом:

Работа с папками и файлами

Рассмотрим задачи, которые помогут нам создавать, копировать и работать с файлами.

1. Создание каталогов и файлов.

Создание файлов и каталогов выполняется с помощью модуля file.

а) для каталога в качестве state указываем directory:

б) для создания файла указываем убираем опцию state (или даем ей значение file):

- name: Create File
file:
path: "/var/www/site1/index.php"
owner: www-data
group: www-data
mode: 0644

* в данном примере мы созданим файл index.php в каталоге /var/www/site1.

2. Копирование файлов из каталога.

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

- name: Copy Cert File If Different
copy:
src: ">"
dest: /etc/ssl/dmosk
remote_src: no
mode: 0644
owner: root
group: root
with_fileglob:
- files/*

* в данном примере мы прочитаем все содержимое каталога files на компьютере с ansible, и скопируем его в каталог /etc/ssl/dmosk на целевом компьютере.

3. Используем шаблон.

Копирование из шаблона отличается от копирования из файла тем, что в шаблоне могут использоваться переменные, которые будет заменяться их значениями в момент копирования. Для самого процесса копирования из шаблона используется модуль template:

- name: Create Config for Consul Agent
template:
src: templates/consul/config.json.j2
dest: /etc/consul.d/config.json

* в данном примере мы возьмом шаблон templates/consul/config.json.j2 на компьютере ansible и разместим его в по пути /etc/consul.d/config.json на целевом компьютере.

4. Удалить последние 30 файлов.

Задача решается в два этапа:

  • ищем содержимое целевого каталога.
  • сотритуем список найденных по времени изменения файлов и удаляем все, что идут после определенного числа объектов.

Поиск выполняем с помощью модуля find, удаление — file:

- name: "Get list of backup files"
find:
paths: "/backup"
file_type: file
register: founds

* в данном примере мы ищем файлы в каталоге /backup, после чего сортируем найденное и удаляем по списку все файлы, которые идут после 30-го.

Для этого используется модуль uri. Простой пример:

* в данном примере мы скачаем файл с ресурса, где требуется аутентификация по токену, который передается в заголовке. Заголовки мы передаем с помощью параметра headers. Также мы задаем права на загруженный файл и делаем в качестве владельца пользователя и группу dmosk.

Виртуализация VMware

Работа с виртуальными машинами на платформе VMware выполняется с помощью модуля vmware_guest.

Мы рассмотрим несколько примеров.

1. Базовое подключение.

Для выполнения действий над виртуальными машинами мы должны подключиться к хосту VMware. Для этого используем данные строки:

* параметр validate_certs, выставленный в no, позволит избежать ошибки, если у нас на хосте используется самоподписанный сертификат (как правило, так и есть).

2. Переименовать виртуальную машину.

Для выполнения действия нам нужно знать идентификатор виртуальной машины:

* где uuid — идентификатор виртуальной машины; name — новое имя виртуальной машины.

3. Конвертировать виртуальную машину в шаблон.

Для этого нужно просто задать признак is_template:

Разное

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

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

С помощью ansible-vault мы можем шифровать файлы и папки. Это позволит нам хранить секреты не в открытом виде. Данные расшифровываются в момент выполнения задач.

Данной командой мы получаем шифрованную строку:

Система запросит ввести дважды пароль и предложит ввести строку, которую нужно зашифровать. После мы должны нажать 2 раза Ctrl + D — мы получим строку, которая начинается с !Vault и различные символы.

Для того, чтобы в момент выполнения задачи ansible расшифровал данные, при запуске плейбука мы должны указать ключ --ask-vault-pass:

2. Игнорировать ошибки.

Если ansible столкнется с ошибкой при выполнении задачи, работа плейбука будет завершена. Иногда, нужно пропустить ошибку при выполнении определенной задачи, чтобы выполнение было продолжено. Для этого существует опция ignore.

а) чтобы пропустить ошибки выполнения, в настройка задачи используем:

- name: Bad Task
.
ignore_errors: yes

б чтобы игнорировать ошибки при подключении к хосту:

- name: Bad Task
.
ignore_unreachable: yes

3. Начинать выполнение с определенной задачи.

При выполнении отладки, полезно запустить плейбук, но начать выполнение с определенной задачи. Остальные пропустить.

Это можно сделать с помощью опции --start-at-task:

ansible-playbook . --start-at-task="Start Job"

* в данном примере плейбук начнет выполнять задания с задачи Start Job.

4. Завершить выполнение плейбука после определенной задачи.

С помощью данной конструкции:

5. Зависимые роли.

С помощью файла meta/main.yml в роли мы можем определить пред-роль, от которой зависит выполнение текущей роли. Для этого настраивается опция dependencies:

dependencies:
- role: pred

6. Вставка роли и ее задач.

Позволяет в процессе выполнения задачи подключить роль. Делается при помощи include_role:

- name: "Include Other Role"
include_role:
name: other_role

А это пример, как подключить роль и сделать так, чтобы все ее задачи выполнились на определенном хосте:

7. Замены в строке.

Замены выполняются с помощью модуля replace:

* в данном примере мы добавляем комментарий к строке server.address=127.0.0.1.

8. Повторы при выполнении задачи.

Мы можем управлять цикличностью выполнения задач с помощью retries (количиство повторов), delay (задержка в секундах).

Рассмотрим пример повтора выполнения задачи при возникновении ошибки:

- name: Run anything command
command: /foo/bar/cmd
register: result
retries: 3
delay: 60
until: result is not failed

* в данном примере мы будем выполнять команду /foo/bar/cmd пока ее выполнение не закончится без ошибок. Количество повторов будет равен 3 с интервалом в 60 секунд.

Что-то не смог понять из примеров в документации - как же скопировать файл с удалённого сервера на локальный и наоборот? Вот есть модули copy и fetch, например. Вот я пишу в плейбуке:

Как указать ansible, с какого хоста я хочу скопировать файл? Ну и соответственно, при копировании на удалённый хост, где указывать этот удалённый хост?

P.S. Немного разобрался: Чтобы скопировать файл с удалённого хоста на локальный:

Файл test.txt будет лежать в каталоге ./backup/localhost/>

Скопировать с локального на удалённый:

Подозреваю, что, если указать в начале - hosts: > вместо localhost, то delegate_to использовать не нужно.

Ну зачем же так сложно? ))

Все эти задачи решаются и без мороки с Delegation и Local Actions, вам же самим потом сложнее будет разбираться в собственных плейбуках или читать чужие, написанные по-простому.

В каждом плейбуке вы указываете на каких хостах запускать задачи - пишете hosts: '>' (если хотите из командной строки управлять списком через --extra-vars "target=10.0.100.123") или hosts: dbservers (если фиксировать плейбук на группу хостов):

Эти хосты - "удалённый" сервер, ну а "локальный" - это само собой хост, на котором находится ваш плейбук.

  • Для копирования файла с локального сервера на удалённый -- используете модуль copy
  • Для копирования файла с удалённого сервера на локальный -- используете модуль fetch

И в copy и в fetch src - это откуда брать файл, а dest - это куда положить файл. Для copy src=local а dest=remote, для fetch -- наоборот src=remote, а dest=local.

Вот и всё. Вам кстати именно об этом говорили в комментарии к вашему последнему вопросу: "В целом Ansible подразумевает то, что ты уже на удаленном хосте", не надо нарезать лишние петли вокруг локалхоста.

PS Если нужно копировать с произвольного хоста на произвольный хост - то смотрите в сторону модуля syncronyze на основе rsync. Но вообще в 90% случаев вам понадобится копирование с локального хоста на удалённый и будете использовать copy или template.

Я пытаюсь скопировать содержимое каталога dist в каталог nginx.

но когда я выполняю playbook, он выдает ошибку:

у него есть ошибка копирования каталога? Как скопировать содержимое каталога, которое находится внутри другого каталога и файла?

можно использовать синхронизация модуль. Пример из документации:

Это имеет дополнительное преимущество, что он будет более эффективен для больших/много файлов.

решен ответить: Чтобы скопировать содержимое каталога в другой каталог я использую следующий:

он копирует в другой каталог. В частности, одним из элементов является каталогом, а другой-нет. Он отлично работает.

Ansible Copy модуль по умолчанию копирует файлы/директории с управлением машины на удаленную машину. Если вы хотите скопировать файлы/директории на удаленной машине и если у вас есть Ansible 2.0, set remote_src to yes

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

карта @surfer190последующий вопрос:

Хммм, что если вы хотите скопировать все содержимое? Я заметил, что * не работает-surfer190 Jul 23 ' 16 в 7: 29

Ansible remote_src не поддерживает рекурсивное копирование.См.описание remote_src в Ansible copy docs

чтобы рекурсивно скопировать содержимое папки и убедиться, что задача остается идемпотентной, я обычно делаю это так:

недостатком является то, что команда find по-прежнему отображается как "изменено"

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

Я тоже был вовлечен целый день! и, наконец, нашел решение в вместо копия: или : как показано ниже:

строго уведомление: 1. src_path и des_path конец / символ 2. в командной оболочке src_path заканчивается . которая показывает все содержимое каталога 3. Я использовал мой имя удаленного сервера оба в hosts: и выполнить оболочку раздел Дженкинса, вместо remote_src: описатель в план.

Я думаю, что это хороший совет, чтобы запустить ниже команду в разделе Execute Shell в Дженкинсе:

ниже работал для меня,

Это я нашел идеальное решение для копирования файла с сервера Ansible на удаленный.

Ansible – это современный инструмент управления конфигурацией, который упрощает настройку и обслуживание удаленных серверов. Минималистичный дизайн позволяет быстро включиться в работу, с его помощью можно централизованно управлять сотнями систем – это делается через плейбуки или через специальные команды.

Плейбуки – это файлы, состоящие из наборов задач, которые можно использовать повторно. А специальные команды – это задачи, которые выполняются не так часто (это, например, перезапуск сервиса или извлечение информации об удаленных системах, которыми управляет Ansible).

В этом мануале вы узнаете, как использовать специальные команды Ansible для выполнения типичных задач, таких как установка пакетов, копирование файлов и перезапуск сервисов на одном или нескольких удаленных серверах с управляющей ноды Ansible.

Требования

  • Главная (управляющая) нода Ansible. В этом мануале предполагается, что в этом качестве вы используете компьютер Ubuntu 20.04 с установкой Ansible, который подключается к хостам Ansible с помощью ключей SSH. Также на главной ноде нужен обычный пользователь sudo и включенный брандмауэр, как описано в этом мануале. Чтобы установить Ansible, следуйте этому руководству.
  • Два хоста Ansible (можно больше). Хост Ansible – это любой компьютер, настройками которого может управлять главная нода Ansible. В этом мануале предполагается, что в качестве хостов Ansible вы используете удаленные серверы Ubuntu 20.04. Убедитесь, что на каждом хосте Ansible есть открытый SSH ключ главной ноды Ansible (его нужно добавить в authorized_keys системного пользователя). Для этого можно использовать либо аккаунт root, либо обычного пользователя sudo. За инструкциями обратитесь к разделу 2 этого мануала.
  • Файл инвентаря на главной ноде Ansible, содержащий все хосты Ansible. Чтобы настроить такой файл, обратитесь к мануалу Создание файла инвентаря Ansible. Предварительно протестируйте подключение между главной нодой и хостами

Тестирование подключения хостов Ansible

Следующая команда проверит соединение между главной нодой и всеми хостами Ansible. Эта команда использует текущего системного пользователя и соответствующий ему SSH-ключ в для удаленного входа в систему и включает параметр -m, который сообщает Ansible о необходимости запустить модуль ping. Она также содержит флаг -i, с помощью которого Ansible будет пинговать хосты, перечисленные в указанном файле инвентаря.

Если вы впервые подключаетесь к этим серверам через SSH, вам будет предложено подтвердить подлинность хостов. При появлении запроса введите yes и нажмите Enter.

Вы должны получить примерно такой результат:

server1 | SUCCESS => "changed": false,
"ping": "pong"
>
server2 | SUCCESS => "changed": false,
"ping": "pong"
>

Если вы получили от хоста ответ «pong», это означает, что соединение установлено, и вы можете выполнять команды Ansible на этом сервере.

Настройка параметров подключения

По умолчанию Ansible пытается подключиться к хостам через удаленного пользователя с тем же именем, что и у вашего текущего системного пользователя, используя соответствующую ему пару ключей SSH.

Чтобы подключиться как другой удаленный пользователь, добавьте команду с флагом –u, после которого укажите имя нужного пользователя:

ansible all -i inventory -m ping -u 8host

ansible all -i inventory -m ping --private-key=

После того как вы подключитесь, используя соответствующие параметры, вы сможете настроить файл инвентаря. В нем можно установить другого удаленного пользователя и закрытый ключ, если они не соответствуют значениям Ansible по умолчанию. Тогда вам не нужно будет указывать эти параметры в командной строке.

В следующем примере файла инвентаря переменная ansible_user настроена только для сервера server1:

server1 ansible_host=203.0.113.111 ansible_user=8host
server2 ansible_host=203.0.113.112

Теперь Ansible будет использовать аккаунт 8host в качестве удаленного пользователя по умолчанию при подключении к серверу server1.

Чтобы настроить пользовательский ключ SSH, включите переменную ansible_ssh_private_key_file:

server1 ansible_host=203.0.113.111 ansible_ssh_private_key_file=/home/8host/.ssh/custom_id
server2 ansible_host=203.0.113.112

В обоих случаях мы установили собственные значения только для server1. Если вы хотите использовать одни и те же настройки для нескольких серверов сразу, используйте для этого дочернюю группу:

[group_a] 203.0.113.111
203.0.113.112
[group_b] 203.0.113.113
[group_a:vars] ansible_user=8host
ansible_ssh_private_key_file=/home/8host/.ssh/custom_id

В этом примере пользовательские конфигурации (другой аккаунт и ключ SSH) будут применяться только для подключения к серверам группы group_a.

Определение целей для выполнения команд

При выполнении специальных команд Ansible вы можете настроить целевые хосты, а также любую комбинацию групп, хостов и подгрупп. Например, вот как можно проверить подключение каждого хоста в группе servers:

ansible servers -i inventory -m ping

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

ansible server1:server2:dbservers -i inventory -m ping

Чтобы добавить в шаблон исключение, используйте восклицательный знак, поставив перед ним escape-символ \, как показано ниже. Эта команда будет запущена на всех серверах из группы group1, кроме server2:

ansible group1:\!server2 -i inventory -m ping

Если вам нужно запустить команду только на серверах, которые входят и в group1, и group2, вам следует использовать символ &. Не забудьте поставить перед ним обратный слеш:

ansible group1:\&group2 -i inventory -m ping

За дополнительной информацией о том, как использовать шаблоны при определении целей для команд, обратитесь к разделу 5 мануала Создание файла инвентаря Ansible.

Запуск модулей Ansible

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

Чтобы выполнить модуль с аргументами, добавьте в команду флаг -a, а затем соответствующие параметры в двойных кавычках:

ansible target -i inventory -m module -a "module options"

В качестве примера мы используем модуль apt для установки пакета tree на server1:

ansible server1 -i inventory -m apt -a "name=tree"

Запуск команд Bash

Если модуль не указан с помощью опции -m, для выполнения указанной команды на удаленном сервере по умолчанию используется модуль command.

Это позволяет выполнить практически любую команду, которую обычно можно запустить через терминал SSH (при условии, что подключающийся пользователь имеет достаточные права, а команда не использует интерактивные запросы).

В этом примере команда uptime выполняется на всех серверах из указанного инвентаря:

ansible all -i inventory -a "uptime"
server1 | CHANGED | rc=0 >>
14:12:18 up 55 days, 2:15, 1 user, load average: 0.03, 0.01, 0.00
server2 | CHANGED | rc=0 >>
14:12:19 up 10 days, 6:38, 1 user, load average: 0.01, 0.02, 0.00

Повышение привилегий для выполнения команд с помощью sudo

ansible server1 -i inventory -a "tail /var/log/nginx/error.log" --become

Это эквивалентно запуску команды sudo tail /var/log/nginx/error.log на удаленном хосте с помощью текущего пользователя локальной системы или удаленного пользователя, указанного в инвентаре.

ansible server1 -i inventory -a "tail /var/log/nginx/error.log" --become -K

Установка и удаление пакетов

В следующем примере модуль apt используется для установки пакета nginx на все хосты из текущего инвентаря:

ansible all -i inventory -m apt -a "name=nginx" --become -K

Чтобы удалить пакет, включите в команду аргумент state и присвойте ему значение absent.

ansible all -i inventory -m apt -a "name=nginx state=absent" --become -K

Копирование файлов

С помощью модуля file вы можете копировать файлы между главной нодой и управляемыми хостами в любом направлении. Следующая команда копирует локальный текстовый файл на все удаленные хосты:

ansible all -i inventory -m copy -a "src=./file.txt dest=

Чтобы скопировать файл с удаленного сервера на главную ноду, включите опцию remote_src:

ansible all -i inventory -m copy -a "src=

/myfile.txt remote_src=yes dest=./file.txt"

Изменение прав доступа к файлу

Чтобы изменить права доступа к файлам и каталогам на удаленных нодах, вы можете использовать модуль file.

Следующая команда настроит права для файла file.txt, расположенного в /var/www на удаленном хосте. Она установит umask файла на 600, вследствие чего чтение и запись будут доступны только текущему владельцу файла. Кроме того, команда установит право собственности на этот файл для пользователя и группы по имени 8host:

ansible all -i inventory -m file -a "dest=/var/www/file.txt mode=600 owner=8host group=8host" --become -K

Перезапуск сервисов

Чтобы перезапустить сервис nginx на всех хостах в группе webservers, запустите такую команду:

ansible webservers -i inventory -m service -a "name=nginx state=restarted" --become -K

Перезагрузка серверов

В Ansible нет специального модуля для перезагрузки серверов, но вы можете выполнить команду bash, которая вызывает команду /sbin/reboot на удаленном хосте.

Важно! Следующая команда полностью перезапустит сервер или серверы, которыми управляет Ansible. Это может вызвать временный сбой в работе всех приложений, использующих эти серверы.

Например, чтобы перезапустить все серверы в группе webservers, запустите такую команду:

ansible webservers -i inventory -a "/sbin/reboot" --become -K

Сбор информации об удаленных нодах

Модуль setup возвращает подробную информацию (системные данные) об удаленных системах под управлением Ansible.

Чтобы получить системные данные server1, введите:

ansible server1 -i inventory -m setup

ansible server1 -i inventory -m setup -a "gather_subset=min"

Чтобы вывести только определенные элементы JSON, вы можете использовать аргумент filter. Он принимает подстановочный шаблон для сравнения строк и поиска совпадений, аналогично fnmatch. Например, чтобы получить информацию о сетевых интерфейсах ipv4 и ipv6, вы можете использовать *ipv* в качестве фильтра:

ansible server1 -i inventory -m setup -a "filter=*ipv*"
server1 | SUCCESS => "ansible_facts": "ansible_all_ipv4_addresses": [
"203.0.113.111",
"10.0.0.1"
],
"ansible_all_ipv6_addresses": [
"fe80::a4f5:16ff:fe75:e758"
],
"ansible_default_ipv4": "address": "203.0.113.111",
"alias": "eth0",
"broadcast": "203.0.113.111",
"gateway": "203.0.113.1",
"interface": "eth0",
"macaddress": "a6:f5:16:75:e7:58",
"mtu": 1500,
"netmask": "255.255.240.0",
"network": "203.0.113.0",
"type": "ether"
>,
"ansible_default_ipv6": <>
>,
"changed": false
>

Если вы хотите проверить использование диска, вы можете запустить команду Bash, вызывающую утилиту df:

ansible all -i inventory -a "df -h"
server1 | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
udev 3.9G 0 3.9G 0% /dev
tmpfs 798M 624K 798M 1% /run
/dev/vda1 155G 2.3G 153G 2% /
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/vda15 105M 3.6M 101M 4% /boot/efi
tmpfs 798M 0 798M 0% /run/user/0
server2 | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
udev 2.0G 0 2.0G 0% /dev
tmpfs 395M 608K 394M 1% /run
/dev/vda1 78G 2.2G 76G 3% /
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/vda15 105M 3.6M 101M 4% /boot/efi
tmpfs 395M 0 395M 0% /run/user/0

Заключение

В этом мануале вы узнали, как использовать специальные команды Ansible для управления удаленными серверами: как выполнять общие задачи, перезапускать сервисы, копировать файлы с главной ноды на удаленные хосты Ansible, собирать информацию с удаленных хостов, использовать разные параметры и фильтры.

За дополнительной информацией обращайтесь к официальной документации Ansible по специальным командам.

Читайте также: