Привет, Хабр! Сегодня поговорим про инфраструктуру как код. Почему Terraform уже не единственный игрок в мире IaC, а Pulumi становится всё более актуальным. Я расскажу, как эти инструменты работают, чем отличаются, и почему стоит присмотреться к Pulumi, особенно, если вы хотите гибкости и мощи в управлении облаками.

Почему IaC — это важно

В наше время автоматизация инфраструктуры — это не просто модный тренд, а необходимость. Вспомните старые времена: ручная настройка серверов, бесконечные конфиги, куча времени на развёртывание. Сейчас это как копать яму лопатой, стоя на ступени экскаватора. Мир ускорился до предела: бизнес требует гибкости, быстрого масштабирования и развёртывания новых фич. Если будем настраивать каждый сервер вручную, просто не успеем за рынком. IaC решает эту проблему. Мы просто описываем инфраструктуру кодом, а машина всё делает сама. И на этом пути уже есть свои классики.

Terraform даёт понятный декларативный язык HCL, с которым легко стартовать, особенно небольшим командам и стартапам. Всё просто: описал ресурсы, запустил — и инфраструктура создаётся. Удобно, надёжно и предсказуемо.

Но есть и минус — Terraform довольно консервативен. Когда хочется сделать что-то нестандартное, приходится туго. Его шаблоны ограничивают, гибкости мало.

Знакомьтесь, Pulumi — IaC нового поколения

Но законы рынка работают везде. Если есть спрос — будут и предложения. С появлением Pulumi — IaC стал проще. Вместо собственного языка Terraform появились привычные нам языки программирования, такие как JavaScript, Python, Go, .NET. Значит, мы можем писать инфраструктуру так, как пишем приложения — с циклами, условными операторами, функциями. Хотим динамическую инфраструктуру, которая меняется в зависимости от нагрузки —  пожалуйста! Нужно интегрировать вызовы API, запускать AWS Lambda прямо из кода инфраструктуры — без проблем.

Pulumi поддерживает динамические провайдеры — это огромный плюс, потому что облачные API постоянно меняются, а ждать обновления провайдера от Terraform бывает довольно долго. С Pulumi намного быстрее адаптироваться. Достаточно написать свой провайдер и сразу использовать новые возможности облака.

Как Pulumi меняет правила игры на примере Netbox

Netbox — популярный инструмент для учёта ресурсов. У него есть Terraform-провайдер, но он довольно жёсткий и не даёт быстро добавлять свою логику, например, для кастомных плагинов. С Pulumi можно написать простой Python-код, который создаст полноценного провайдера для Netbox, и управлять виртуальными машинами, интерфейсами и IP-адресами. Без громоздких бинарных провайдеров, без долгого ожидания обновлений. Это даёт свободу быстро менять и расширять инфраструктуру под свои нужды.

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

import pulumi
import os
from pulumi.dynamic import ResourceProvider, CreateResult, UpdateResult, Resource, DiffResult
import pynetbox
import json

api_url = os.getenv('NETBOX_URL')
api_token = os.getenv('NETBOX_TOKEN')

class NetboxVMProvider(ResourceProvider):
    def __init__(self, api_url, token):
        self.nb = pynetbox.api(api_url, token=token)

    def create(self, props):
        vm = self.nb.virtualization.virtual_machines.create(
            name=props["name"],
            disk=props.get("disk"),
            vcpus=props.get("vcpus"),
            memory=props.get("memory"),
            site=props.get("site"),
            tenant=props.get("tenant"),
            platform=props.get("platform"),
            status='active',
            custom_fields={
                'Environments': f'{props.get("Environments")}', 
                "ResourceID": f'{props.get("ResourceID")}'
            }
        )

        netbox_interface = self.nb.virtualization.interfaces.create(
            virtual_machine=vm.id,
            name="eth0"
        )

        netbox_ip_address = self.nb.ipam.ip_addresses.create(
            address=props.get("address"),
            assigned_object_type='virtualization.vminterface',
            assigned_object_id=netbox_interface.id,
            dns_name=props.get("dns_name"),
            status='active'
        )

        vm.update({
            'primary_ip4': netbox_ip_address.id
        })

        vm_id = vm.id
        return CreateResult(id_=str(vm_id), outs={**props, "vm_id": vm_id})

    def update(self, id, olds, news):
        vm = self.nb.virtualization.virtual_machines.get(id)
        for key, value in news.items():
            setattr(vm, key, value)
        vm.save()
        return UpdateResult(outs={**news, "vm_id": id})

    def delete(self, id, props):
        vm = self.nb.virtualization.virtual_machines.get(id)
        vm.delete()

class NetboxVM(Resource, module="NetBox", name="VirtualMachine"):
    def __init__(self, name, props, opts=None):
        super().__init__(NetboxVMProvider(api_url, api_token), name, props, opts)

Таким вот нехитрым образом у нас получается полноценный провайдер без больших бинарников провайдера от Terraform. Причем мы можем менять его прямо на ходу! В этом нам помогают:

from pulumi.dynamic import ResourceProvider, CreateResult, UpdateResult, Resource, DiffResult

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

vm = NetboxVM(
    f"netboxvm-{config.name}",
    {
        "name": config.name,
        "api_url": NETBOX_URL,
        "tenant": netbox_tenant.id,
        "platform": netbox_platform.id,
        "vcpus": cpu_core_count,
        "site": netbox_site.id,
        "memory": memory_size,
        "disk": config.system_disk_size,
        "dns_name": config.name,
        "address": network.ip4_addr,
        "Environments": SYS_ENV,
        "ResourceID": instance.id
    },
    opts=pulumi.ResourceOptions(
        parent=instance,
        depends_on=instance,
        ignore_changes=["__provider"]
    )
)

И готово!

Инфраструктура как часть приложения

Ещё один важный момент: с Pulumi IaC становится частью приложения. Можно создавать инфраструктуру, которая сама подстраивается под нагрузку, автоматически разворачивает тестовые окружения, оптимизирует затраты. Например, можно настроить автоматическую отправку уведомлений сотрудникам с безопасной передачей паролей через зашифрованные ссылки — всё это прямо в коде инфраструктуры. В Terraform такие сценарии требуют сложных обходных путей и внешних скриптов. С Pulumi всё намного проще. Вы можете брать свой любимый язык, а я для примера снова воспользуюсь Python.

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

Terraform не позволит выполнить произвольный код, если у него нет подходящего провайдера, а Pulumi создан для такого. Берём и пишем простой код:

def send_email(msg_to: str, msg_from: str, subject: str, body: str) -> None:
    msg = EmailMessage()
    msg.set_content(body)
    msg['Subject'] = subject
    msg['From'] = msg_from
    msg['To'] = msg_to

    s = smtplib.SMTP("SOME_SERVER")
    s.send_message(msg)
    s.quit()


def send_secret_email(msg_to: str, url: str) -> None:
    api_url = PULUMI_CONFIG.require("secrets_url")
    api_puburl = PULUMI_CONFIG.require("secrets_puburl")
    url = url.replace(api_url, api_puburl)
    
    body = (
        "Здравствуйте!\r\n\r\n"
        f"Ваш пароль от консоли Вы можете получить по ссылке {url}.\r\n\r\n"
        "Ссылка действительна в течении недели.\r\n"
        "для авторизации нажмите на IAM User Login и введите Account name: 123123"
    )
    subject = "Your password"
    msg_from = "no-reply-pulumi@example.com"

    send_email(msg_to, msg_from, subject, body)

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

Конечно, мы можем взять Terraform, покрыть его большой кучей внешних скриптов bash или Python и получить почти то же самое, но… Через Pulumi мы всё получаем из коробки. Прямо как джинн, но не из бутылки, а из коробки. И желаний не три, а сколько хочешь.

Импорт и миграция из других инструментов

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

Так как у нас в распоряжении множество языков программирования, ничего не мешает дополнять наш IaC любыми функциями:

  • взаимодействие с собственными API;

  • вызов и взаимодействие с любыми внешними приложениями посредством SDK;

  • использование Lambda в любом моменте выполнения IaC.

И это далеко не весь список преимуществ, которые мы получаем. По факту он ограничен только нашей фантазией и…

Есть нюанс — нужен опыт

Pulumi не панацея, если вы вдруг подумали, что я работаю на Pulumi Corporation и продвигаю этот проект. Во-первых, это Open Source. Во-вторых, минусы тоже есть.

Pulumi — это не про «нажать кнопку и получить». Здесь нужна команда с хорошими навыками программирования. Если в Terraform можно взять готовый шаблон и чуть подправить, то для Pulumi, как это ни прискорбно, нужно уметь писать код, проектировать архитектуру и рефакторить. Это вызов, особенно для команд, где DevOps не программисты. Но если освоить Pulumi, вы получите безграничные возможности для автоматизации и управления. Это отличная альтернатива, особенно для крупных компаний, где идеи рождаются очень быстро, а архитектура «меняется каждую минуту».

Итоги. Когда что выбрать

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

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

В итоге, не стоит смотреть на Terraform и Pulumi как на конкурентов. Они отлично дополняют друг друга. Можно использовать Terraform для стабильных базовых задач, а Pulumi — для сложных сценариев и кастомизации. Главное понимать, что IaC — это не просто код, а инструмент, который должен работать на вас и вашу команду.

Если хотите выйти за рамки шаблонов и сделать инфраструктуру живой и адаптивной — выберите Pulumi. Если нужна простота и проверенность — Terraform остаётся отличным вариантом. Решение за вами, просто расширяйте свои возможности новыми инструментами.

https://www.pulumi.com/ - Pulumi
https://www.terraform.io/ - Terraform
https://t.me/pulumi_ru - Русскоговорящие сообщество Pulumi
https://t.me/masikmos - Автор статьи

Комментарии (8)


  1. Andy_U
    14.05.2025 10:12

    У вас все отступы в коде пропали...


    1. masikm Автор
      14.05.2025 10:12

      Спасибо. Поправил


  1. gred
    14.05.2025 10:12

    ну, как бы... нормальных пакетов (.deb, .rpm) - нету. поддержки *BSD в качестве run platform - нету. поставить через go install на не поддерживаемой платформе - нету. от вашего покорного слуги есть issue по данному поводу. от разрабов реакции - 0


    1. masikm Автор
      14.05.2025 10:12

      deb и rpm нету потому что другая логика доставки https://www.pulumi.com/docs/iac/download-install/versions/ и https://github.com/pulumi/pulumi/releases просто качаете архив с бинарниками и используете

      под *BSD даже не знал что нету, давно не использовал unix

      видимо логика у разрабов такая что или сам клади в go и сам собирай deb, rpm и под unix тоже. Как я говорил pulumi не панацея и статья не нацелена на то что бы сказать что terraform плохо. Тут вопрос гибкости, иногда без pulumi просто не обойтись а terraform что называется не вывозит.


  1. PetyaUmniy
    14.05.2025 10:12

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

    Концеп Pulumi вообще не понимаю.
    Помоему это тулза не нового поколения, это шаг назад в 70-80e к шелл портянам с размазаным по всему файлу контекстом выполнения и императивщиной в полный рост.

    А вот это заявление:

    появились привычные нам языки программирования... Go, .NET.
    

    вызывает у меня опасения за тех кто это придумал, за их ментальное здоровье. Почему бы не пойти дальше? Где C, Fortran, Cobol... и asm разумеется?

    Такое чувство что люди совершенно оторвались от реальности. Зачем вам интеграция инфраструктурной тулзы в ваш язык программирования, а особенно компилируемые? Вам что нужно запускать её раз в 100мкс? Точно нужно, да? А зачем? Ведь в противном случае задача решается самым прямым образом: запускайте самые обычные инструменты через exec. Это не настолько плохо как люди об этом думают, особенно если вы делаете это реже чем раз в секунды. Или если вы делаете не mvp колхоз, лишь бы заработало, и вам нужна изоляция, границы модулей - вот это все, то дергаете их по API (например ansible можно дергать через AWX или Semaphore, terraform тоже чем-то, вроде тоже через последний). Зачем миксовать в коде приложения принципильно разные сущности? Не понимаю.

    А еще к вопросу безопасности, вы забиваете в свой код credentials позволяющие, допустим, управлять инстансами VM... Угадайте что произойдет если это сервис сломают? На каком количестве инстансов вылезет злоумышленик? Конечно, можно сделать и безопасно. Но это как будто бы вариант тем кому "нужны шашечки", в другом случае (обычная тулза по api) у тех кому "ехать" сразу работает достаточно безопасно.

    Тезис про собственные языки ansible и terraform на мой взгляд ошибочен. Их нельзя сравнивать с обычными языками программирования - это dsl поверх стандартного формата сериализации. В ансибле точно можно юзать для сериализаци json вместо yml, в terraform вроде тоже можно json вместо hcl. Таким образом остается только ознакомиться с самим dsl, который очень простой, потому что ограниченный. Это близко нельзя сравнить с изучением языка программирования. Разные порядки сложности.
    Вобщем очередной раз не убедили.


    1. masikm Автор
      14.05.2025 10:12

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

      Все что вы написали 7 лет назад я читал про Kubernetes. Делайте выводы


    1. cadmi
      14.05.2025 10:12

      А еще к вопросу безопасности, вы забиваете в свой код credentials позволяющие, допустим, управлять инстансами VM... Угадайте что произойдет если это сервис сломают?

      Ну вот с этого места всё понятно - автор комментария не то что не использовал, а даже документацию не читал. Но осуждает.

      Этот бы возмущенный комментарий да в производительное русло.


  1. masikm Автор
    14.05.2025 10:12

    Ой, сплю уже, комvентарий удалил случайно про отсутствие dry run\plan

    как же отсутствует - ну pulumi preview же