Недавно я начал применять 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 infradrwxrwxr-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.
Примеры можно найти здесь.
Благодарю за внимание и до новых встреч!