Используем Ansible вместе с Terraform

от автора

Недавно я начал применять Terraform для создания облачной лабы для тестов, и это довольно круто. Буквально за несколько дней я поднялся с «никогда не использовал AWS» до «я умею декларативно создавать изолированную инфраструктуру в облаке». Я поставил парочку серверов в выделенной сети в VPC с security group и отдельными ключами SSH, все это заняло у меня несколько сотен строк кода.

Все приятно и прельстиво, но после создания сервера из некоторого базового AMI мне надо его развернуть. Мой типовой инструмент для этого — Ansible, но, к сожалению, у Terraform нет встроенного модуля для Ansible (есть обратный, начиная с Ansible 2.5, прим. переводчика), в отличие от Chef и Salt. Это не похоже на Packer, имеющий ansible (удаленный) и ansible-local, который я использовал для сборки образов Docker.

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

Нужно ли развертывание в облаке?

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

Далее — если делаете свои AMI, вам все равно нужно как-то запускать развертывание, так что опять появляются такие вещи, как Ansible. Ну и опять же, я рекомендую использовать Packer вместе с Ansible.

Получается, что в большинстве случаев развертывание нужно, потому что оно — неизбежно.

Как использовать Ansible вместе с Terraform

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

Встроенный inventory с IP сервера

Наиболее очевидное и хакерское решение — запускать Ansible с помощью local-exec, например так:

provisioner "local-exec" {     command = "ansible-playbook -i '${self.public_ip},' --private-key ${var.ssh_key_private} provision.yml" }

Просто и приятно, но тут сразу же есть нюанс. local-exec запускается без ожидания запуска сервера, так что в большинстве случаев это не сработает, потому что на момент подключения еще некуда подключаться.

В качестве изящного обходного способа вы можете предварительно использовать remote-exec, который будет ожидать соединения с сервером, а затем запускать local-exec.

В результате у меня получилась следующая вещь, запускающая роль «Ansible provisioner»:

provisioner "remote-exec" {     inline = ["sudo dnf -y install python"]      connection {       type        = "ssh"       user        = "fedora"       private_key = "${file(var.ssh_key_private)}"     }   }    provisioner "local-exec" {     command = "ansible-playbook -u fedora -i '${self.public_ip},' --private-key ${var.ssh_key_private} provision.yml"   }

Чтобы ansible-playbook работал, вам надо иметь код для Ansible рядом с кодом для Terraform:

$ ll infra drwxrwxr-x. 3 avd avd 4.0K Mar  5 15:54 roles/ -rw-rw-r--. 1 avd avd  367 Mar  5 15:19 ansible.cfg -rw-rw-r--. 1 avd avd 2.5K Mar  7 18:54 main.tf -rw-rw-r--. 1 avd avd  454 Mar  5 15:27 variables.tf -rw-rw-r--. 1 avd avd   38 Mar  5 15:54 provision.yml

Встроенный inventory будет работать в большинстве случаев, кроме тех, когда необходимо иметь несколько серверов в inventory. Например, если вы устанавливаете агент Consul, вам нужен список серверов для создания файла настроек, это как правило можно найти в обычном репозитории. Но в приведенном выше способе это не сработает, поскольку у нас всего один сервер в inventory.

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

Динамический inventory после работы Terraform

Еще одно простое решение для раскатки инфраструктуры, созданной Terraform — не связывать вместе Terraform и Ansible. Создаем инфраструктуру с помощью Terraform, а затем используем Ansible с динамическим inventory без привязки к тому, как сервера были созданы.

Так что вы сначала создаете инфраструктуру с помощью terraform apply, затем запускаете ansible-playbook -i inventory site.yml, где inventory — каталог, содержащий скрипты динамического inventory.

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

А это то, что я использую в дополнение к предыдущему способу.

Inventory, создаваемая из состояния Terraform

Есть еще одна интересная штука, которая, возможно, будет у вас работать — создание статического inventory из состояния Terraform.

Terraform при работе поддерживает состояние инфраструктуры, содержащее все, включая ваши сервера. При использовании local backend это состояние сохраняется в файле JSON, который можно потом легко разобрать и сконвертировать в inventory для Ansible.

Я нашел два проекта с примерами, так что вы можете их использовать, если будете работать с этим способом.

Первый

[all] 52.51.215.84  [all:vars]  [server] 52.51.215.84  [server.0] 52.51.215.84  [type_aws_instance] 52.51.215.84  [name_c10k server] 52.51.215.84  [%_1] 52.51.215.84

Второй

$ ~/soft/terraform.py --root . --hostfile ## begin hosts generated by terraform.py ## 52.51.215.84        C10K Server ## end hosts generated by terraform.py ##

Дополнение Ansible для Terraform, которое у меня не заработало

Наконец, есть несколько проектов, которые пытаются внедрить поддержку Ansible в Terraform, как это уже, например, сделано для Chef.

Первая попытка сделать дополнение, но, к сожалению, он уже не поддерживается автором и даже больше — не поддерживается актуальной системой дополнений Terraform.

Вторая, более свежая и поддерживаемая, позволяет такой вариант развертывания:

... provisioner "ansible" {     plays {         playbook = "./provision.yml"         hosts = ["${self.public_ip}"]     }     become = "yes"     local = "yes" } ...

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

Заключение

Terraform и Ansible — мощная связка, которую я использую для развертывания облачной инфраструктуры. Для типовых облачных серверов я запускаю Ansible через local-exec, позднее я запускаю Ansible отдельно с динамическим inventory.

Примеры можно найти здесь.

Благодарю за внимание и до новых встреч!

ссылка на оригинал статьи https://habr.com/ru/company/southbridge/blog/525810/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *