Tags: iac terraform hashicorp
Categories: None

За 2015 и 2016-й год в среде DevOps было много сказано про централизованное управление инфраструктурой, про подход Infrastructure as Code и соответствующие тулы. Подход конечно же правильный и эволюционно все так и должно было сложиться. Я например в проектах двухгодичной давности сооружал что-то похожее на декларативное описание инфраструктуры из того, что тогда было под руками. Мой стек выглядел как специальный набор ролей и модулей Ansible + набор bash скриптов и набор указаний для нашей команды в документации.

На данный момент для целостного управления инфраструктурой существуют различные инструменты: Terraform от HashiCorp, CloudFormation от Amazon, Heat от OpenStack и может быть что-то ещё. Кто-то скажет: “а как же системы управления конфигурацией? Как же Chef, Puppter, Ansible, etc?”. Ответ в том, что тулы типа Terraform работают на другом уровне абстракции, на уровне целостной инфраструктуры, которую надо сначала развернуть, а потом поддерживать изменения в ней.

Когда я говорю про большую и целостную инфраструктуру - я имею ввиду тот момент когда ваш сервис начинает пользоваться большим кол-вом подсистем ващего облака. К примеру представим, что для развертывания сервиса в AWS надо создать сеть (или набор сетей), пробить правильно дырки, создать шлюз, создать балансер, создать набор машин в разных датацентарх, настроить CDN, ну и можно продолжать дальше в зависимости от масштабов сервиса. После развертывания необходимо поддерживать изменения в инфраструктуре, а еще и хотелось бы что-бы информация об инфраструктуре шарилась между всеми членами команды. Вот тут и начинают приносить профит системы для управления инфраструктурой и подход IoC (Infrastructure as Code).

Пробуем Terraform?

Какую инфраструктуру будем разворачивать? Так как задача заметки показать подход IoC и Terraform, не будем создавать развесистую инфраструктуру, чтобы не потеряться в дебрях AWS. Накатим простой инстанс с nginx’ом на борту и доступом по ssh.

Немного терминологии

Перед тем как перейти к практической части надо немного разобраться в терминологии Terraform и в том из чего состоит этот инструмент.

Разделим Terraform на 3 логические части:

Первая часть - это консольная утилита

Она читает конфигурацию инфраструктуры из файла с расширением tf. Сам файл буем писать позже.
Основные операции следующие:

  • terraform plan - показывает план выполнения. Это по сути diff из того что было в инфраструктуре и того что станет.
  • terraform apply - применяет план. Тут все просто, тула пойдет и по API начнет дергать все ручки и создавать заданные ресурсы.
  • terraform graph - рисует граф ресурсов, полезная штука для наглядного представления о структуре нашей инфраструктуры.

Вторая часть - это состояния

После каждого применения плана вносятся изменения в файл terraform.tfstate. В нем содержится слепок вашей инфраструктуры на момент времени после применения. Этот файлик можно шарить в команде и его можно версионировать. Профит тут понятный - хронология изменений в инфраструктуре + разрешение коллизий при работе в команде.

Третья часть - это коммерческая платформа от HashiCorp - Atlas

По сути это веб-морда ко всему перечисленному выше. Кейс работы с Atlas’ом следующий: мы можем пушить конфигурацию и state в Atlas, другие разработчики могут пулить; сама веб морда позволяет делать apply конфигурации и отображать хронологию изменений. На самом деле пока не густо, думаю это будет развиваться дальше, появятся визуализация, графические средства конфигурирования и т.д.

Терраформируем

Теперь когда суть более менее ясна, начнем писать конфигурацию vim infrastructure.tf

Для начала скажем, что мы хотим использовать в качестве провайдера AWS:

provider "aws" {
access_key = "ACCESS_KEY"
secret_key = "SECRET_KEY"
region = "us-east-1"
}

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

mkdir ssh && cd ./ssh
ssh-keygen -f user

Теперь опишем необхожимые ресурсы. Это будет сам инстанс и security group для него с описанием дырок:

# Добавляем публичный ключ в AWS
resource "aws_key_pair" "user" {
key_name = "user"
public_key = "${file("ssh/user.pub")}"
}

# Заводим security group для нашего будущего инстанса и разрешаем входящие
# соединения на 22 и 80 портах
resource "aws_security_group" "backend" {
name = "backend"

ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

# Заводим наш инстанс с описанием простого provision'инга (доставляем на инстанс nginx).
# Провиженить можно и другими спомобами, например использовать Chef или Ansible
resource "aws_instance" "backend" {
ami = "ami-0d729a60"
instance_type = "m3.large"
key_name = "user"
security_groups = ["backend"]

provisioner "remote-exec" {
inline = [
"apt-get install nginx"
]
}
}

# На последок опишем ту информацию, которую хотим знать о рабочей инфраструктуре.
# В данном случае - это ip адрес нашего инстанса.
output "backend.ip" {
value = "${aws_instance.backend.public_ip}"
}

Конфигурацию описали, теперь применяем:

terraform apply

После того как команда отработает, можем открыть наш инстанс в браузере и увидеть “Welcome to nginx!”:

google-chrome `terraform output backend.ip`

Или зайти на машину по ssh:

ssh ubuntu@`terraform output backend.ip` -i ssh/user

На последок можем свернуть все то, что понаразворачивали:

terraform destroy

Итого

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

comments powered by Disqus