Краткий мастер-класс по разработке инфраструктурного кода


image


В октябре этого года я выступил с докладом на конференции HashiConf 2018, где рассказал о 5 ключевых уроках, которые я и мои коллеги из Gruntwork усвоили в процессе создания и поддержки библиотеки из более чем 300 000 строк инфраструктурного кода, используемой в производственных системах сотнями компаний. В этой публикации я поделюсь видео и слайдами с выступления, а также сокращенной текстовой версией описания 5 основных уроков.


Видео и слайды



Вступление: DevOps сейчас — в «каменном веке»


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


Лично мне DevOps больше больше напоминает вот что:


image


image


image


image


Создавать инфраструктуру производственного уровня сложно. Это настоящий стресс. И кушает много времени. Очень много времени.


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


image


Урок 1. Чеклист для инфраструктуры производственного уровня


Проекты DevOps всегда занимают больше времени, чем вы ожидаете. Всегда. Почему так?
Первая причина — это "стрижка яка". Ниже — яркая иллюстрация этого феномена, (это отрывок из сериала “Малкольм в центре внимания”)



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



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


Урок 2. Набор инструментов


Перечислим основные инструменты, которые мы в Gruntwork используем для создания и управления инфраструктурой (по состоянию на 2018 год):


image


  • Terraform. Мы используем Terraform для развертывания всей базовой инфраструктуры, включая сеть, подсистемы балансировки нагрузки, базы данных, средства управления пользователями и разрешениями, а также все наши серверы.
  • Packer. Мы используем Packer для настройки и создания образов виртуальных машин, которые запускаем на наших серверах.
  • Docker. Некоторые из наших серверов образуют кластеры, где мы запускаем приложения как контейнеры Docker. Для кластеров Docker мы применяем в основном следующие инструменты: Kubernetes, ECS и Fargate.

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


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


Урок 3. Большие модули — это зло


Новички в деле применения «инфраструктуры как кода» часто определяют всю свою инфраструктуру для всех своих сред (среда разработки, промежуточная среда, производственная среда и т. д.) в одном файле или наборе файлов, которые развертываются как единое целое. Зря.


Вот лишь некоторые из недостатков такого подхода:


  • Низкая скорость. Если вся инфраструктура определена в одном месте, то выполнение любой команды займет много времени. Мы сталкивались с ситуациями в компаниях, когда выполнение команды terraform plan занимало 5–6 минут!
  • Низкая безопасность. Если всей инфраструктурой вы управляете совместно, то для изменения чего-либо вам нужны разрешения на доступ ко всему. То есть почти каждый пользователь должен быть администратором, а это тоже очень неудобно.
  • Высокие риски. Если вы складываете все яйца в одну корзину, то создаете ситуацию, когда одна локальная ошибка может нарушить работу всей инфраструктуры. Например, когда вносите незначительные изменения во внешнее приложение в среде разработки, одна опечатка или неправильная команда могут привести к удалению производственной базы данных.
  • Сложно понять. Чем больше кода размещено в одном месте, тем сложнее одному человеку понять все это. И когда все это связано, непонятные части сыграют с вами злую шутку.
  • Сложно тестировать. Тестировать код инфраструктуры сложно; тестировать большие объемы инфраструктурного кода практически невозможно. Вернемся к этому позже.
  • Сложно анализировать. Вывод таких команд, как terraform plan становится бесполезным, так как никто не утруждает себя просмотром тысяч строк. Более того, анализ кода становится бесполезным.

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


«Делайте что-то одно и делайте это хорошо» — философия Unix.
«Первое правило функций гласит, что они должны быть маленькими. Второе правило гласит, что функции должны быть еще меньше». — «Чистый код»

Урок 4. Инфраструктурный код без автоматических тестов неисправен


Если ваш инфраструктурный код не имеет автоматических тестов, он работает неправильно. Вы просто еще не знаете об этом. Но тестировать инфраструктурный код сложно. У вас нет ни «локального хоста» (например, вы не можете развернуть виртуальное частное облако AWS VPC у себя на ноутбуке), ни реальных «модульных тестов» (например, вы не можете изолировать код Terraform от «внешнего» мира, поскольку он как раз и предназначен для общения с внешним миром).


Поэтому чтобы правильно протестировать инфраструктурный код, обычно приходится развертывать его в реальной среде, запускать реальную инфраструктуру, проверять работоспособность кода, а затем разбивать его (описание этого стиля тестирования: см. Terratest, это библиотека с открытым исходным кодом, включающая инструменты для тестирования кода Terraform, Packer и Docker, работы с API-интерфейсами AWS, GCP и Kubernetes, выполнения команд оболочки локально и на удаленных серверах через SSH, а также многие другие возможности). Таким образом, тестируя инфраструктуру, надо слегка переопределить условия:


image


Модульные тесты развертывают и тестируют один или несколько тесно связанных модулей инфраструктуры одного типа (например, модули для одной базы данных).


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


Сквозные тесты (e2e) развертывают и тестируют всю архитектуру.
Обратите внимание на то, что диаграмма представляет собой пирамиду: у нас много модульных тестов, поменьше интеграционных тестов и совсем мало e2e-тестов. Почему? Это зависит от длительности выполнения каждого типа тестов:


image


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


  1. Создать небольшие и простые автономные модули (см. Урок 3) и написать много модульных тестов для них — удостовериться, что они работают правильно.
  2. Объединить эти небольшие, простые и апробированные блоки, чтобы создать более сложную инфраструктуру, которую вы тестируете с помощью меньшего количества интеграционных и E2E-тестов.

Урок 5. Процесс релиза


Подытожим все вышесказанное. Вот как вы теперь будете создавать инфраструктуру и управлять ею:


  • Сверьтесь с чеклистом для инфраструктуры производственного уровня и убедитесь, что работаете в правильном направлении.
  • Определите свою «инфраструктуру как код» с помощью таких инструментов, как Terraform, Packer и Docker. Убедитесь, что у вашей команды достаточно времени на освоение этих инструментов (см. Ресурсы DevOps).
  • Создавайте код из небольших и автономных составных модулей (или используйте стандартные модули из библиотеки Infrastructure as Code Library).
  • Подготовьте автоматические тесты для ваших модулей с помощью Terratest.
  • Выполните запрос на включение внесенных изменений для рецензирования вашего кода.
  • Выпустите новую версию кода.
  • Скопируйте новую версию кода из одной среды в другую.

image

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


  1. Tiendil
    29.12.2018 16:21

    Краткое содержание: если вы что-то программируете, то на ваш код распространяются те же правила, что и на код программистов. Даже если вы не программист, а, например, devops, тестировщик, менеджер, доктор, школьный учитель или депутат)