Разработка программного обеспечения давно уже стала серьезным промышленным направлением, по сложности зачастую превосходящим некоторые технологические производства. Это в прежние времена и архитектурой, и разработкой и тестированием приложения могли заниматься только программисты, которые сами писали код. Сейчас в разработке участвует множество различных специалистов: архитекторов, разработчиков, дизайнеров, тестировщиков и многих других. Все эти специалисты отвечают за то, чтобы продукт вышел в продакшен. После чего за дальнейшее исправное функционирование решения отвечают уже другие специалисты – техническая поддержка, специалисты по эксплуатации. Однако и это не исчерпывающий список участников процесса обеспечения жизненного цикла приложения. Любое сетевое приложение сейчас может стать целью для хакеров. Поэтому и разработка, и эксплуатация приложений должны вестись с учетом актуальных практик по информационной безопасности.
Так что картинка из идеального мира представляет собой взаимодействие между разработчиками, эксплуатационщиками и безопасниками на всех этапах жизненного цикла приложения, от проектирования и разработки до ввода в эксплуатацию и поддержки.
Суровая реальность
А вот в реальном мире все совсем по-другому. Разработка часто варится в собственном соку. Приложение разрабатывается с учетом требований бизнеса (и соответственно сроков, которые всегда поджимают),но без привлечения специалистов ИБ. При передаче приложения в продакшен тоже зачастую нет должного взаимодействия между разработкой и специалистами по эксплуатации. Ну и внедрение осуществляется без учета требований ИБ. В результате потом к уже развернутому приложению приходится прикручивать средства защиты, которые будут тратить ресурсы защищаемых серверов, занимать часть полосы пропускания каналов связи и вообще «мешать» пользователям работать. Эксплуатационщики тоже потом вынуждены изучать продут на лету, придумывая различные костыли для снятия нужных метрик и сбора логов. Отдельной болью для всех является установка обновлений.
Культура CI/CD
Но многих из этих проблем можно избежать, если внедрить технологию непрерывной доставки ПО (Continuous delivery или CD, или CDE). Это подход к разработке ПО, при котором программное обеспечение выпускается короткими итерациями. При этом гарантируется, что ПО является стабильным и может быть передано в эксплуатацию в любое время, а передача его не происходит вручную. Целью является сборка, тестирование и релиз программного обеспечения с большей скоростью и частотой. В дополнение к непрерывной доставке существует также Непрерывная интеграция (Continuous Integration, CI)– набор практик по автоматизации непрерывному внесению изменений и дополнений в приложения. Поскольку большинство современных приложений разрабатываются с использованием различных платформ и инструментов, то появляется необходимость в механизме интеграции и тестировании вносимых изменений.
Непрерывная интеграция обеспечивает последовательный, автоматизированный способ сборки, упаковки и тестирования приложений. Если процесс интеграции налажен должным уровнем, разработчики будут делать коммиты чаще, что в свою очередь поможет улучшить качество выпускаемого программного обеспечения. Важно понимать, что непрерывная поставка начинается там, где заканчивается непрерывная интеграция. То есть, CD позволяет автоматизировать процесс развертывания приложений в различных окружениях: в тестовой среде, когда разработчики пишут и отлаживают код и в продакшене, когда прошел все проверки и может быть размещен в продуктивной среде.
Объединение Continuous Integration и Continuous Delivery - CI/CD представляют собой культуру, набор принципов и практик, которые позволяют разработчикам чаще и надежнее развертывать изменения программного обеспечения.
Процесс CI/CD по своей сути является циклическим постоянно повторяющимся действием и в одной из публикаций на эту тему даже предлагалось назвать его CI/CD/CD (Continuous Deployment), где после непрерывной доставки также идет непрерывное развертывание.
По сути, процесс CI/CD представляет собой конвейер, в котором непрерывно идет процесс развертывания и обновления программного обеспечения. Немного поговорим о том, какие преимущества дает конвейерное производство.
Спасибо, Генри или о преимуществах конвейера
В начале ХХ века за сборку всего автомобиля могла отвечать одна бригада рабочих. То есть и за сборку ходовой, и за установку двигателя, и за покраску кузова отвечают одни и те же люди. Какие недостатки были у такого подхода: сборка одной машины занимала много времени, рабочие могли ошибиться и забыть установить какую-либо деталь, от рабочих требовалось высокая квалификация. Однако, когда Генри Форд внедрил на своих заводах конвейерное производство ситуация резко изменилась. Теперь за каждую специализацию отвечает отдельная бригада рабочих: одни только ставят двигатель, другие только устанавливают шасси, третьи только собирают кузов и так далее. В результате каждая бригада отвечает только за свою часть работ, снижается процент ошибок при сборке, снижаются затраты времени на выпуск одной машины. К недостаткам такого подхода можно отнести необходимость нанимать большее число рабочих. Однако, сейчас именно такой подход используется на всех производствах.
Конвейеры в разработке работают аналогичным образом, только вместо рабочих мы можем часть задач по созданию проекта, его сборке и тестированию поручить различным программным компонентам: скриптам, сервисам и т.д. При этом и разработчики и тестировщики в таком конвейере находятся в тесном взаимодействии. Ежедневные коммиты позволяют всем командам находиться в постоянном взаимодействии и результатом работы такого конвейера является достаточно качественный программный продукт, готовый к использованию в продакшене. На рисунке ниже представлен типичный конвейер CI/CD.
Рассмотрим каждый из представленных компонентов подробнее. Среда разработки – это песочница, в которой разработчики создают код. Затем код коммитится и передается в хранилище. Компонент CI забирает этот код из хранилища и тестирует его на наличие различных багов. Компонент QA это собственно тестировщики качества кода, отвечающие за качество выпускаемого кода. Но в серьезных компаниях тестировщики тоже используют свои конвейеры для автоматизации тестирования. И конвейеры QA это отдельная большая тема, выходящая за рамки данной статьи. Staging это тестовая среда, которая по своей конфигурации и архитектуре максимально приближена к продуктовой среде. На ней проходит приемочное тестирование перед передачей решения в продакшен. Важно, чтобы методы развертывания в стейджинге и в продакшене полностью совпадали, иначе можно попасть в неприятную ситуацию, когда какой-нибудь контейнер тестировали в одной системе контейнеризации, а в продакшене оказалась другая и в результате мы получили проблемы, о которых никто даже не задумывался.
Кстати, схожей должна быть и инфраструктура, то есть дисковая подсистема, балансировщик и каналы связи, иначе также можно получить неожиданные тормоза при работе.
На этапе Production абсолютно большинство багов уже должно быть отловлено, однако вполне возможны ситуации, когда какие-то ошибки и странности в поведении приложения все же имеются. Для своевременного выявления таких проблем необходимо вести мониторинг работы приложения на регулярной основе. И здесь важную роль играет взаимодействие специалистов из разработки и из эксплуатации, потому что те, кто обслуживает и внедряет могут сказать какие метрик и события им нужны, а разработчики могут дописать в приложении необходимый код для сбора этих метрик и событий.
Итак, какие требования мы должны предъявлять к нашему конвейеру. Прежде всего, это автоматизация процессов сборки и деплоя в инфраструктуру. В отличие от примера со сборкой машин, где для конвейерной сборки нам требовалось больше рабочих, здесь мы можем максимально автоматизировать процесс, что позволит нам по максимуму передать все рутинные задачи скриптам. По сути, сегодня даже часть кода генерируется скриптами с помощью заданных шаблонов.
Проблемы конвейеров
Стандартизация подходов к управлению окружениями на разных этапах процесса CI/CD. Как мы видели на схеме ранее, процесс состоит из разных этапов и на каждом из них есть своя мини (а иногда и совсем не мини) инфраструктура, состоящая из серверов и сетевого оборудования, которые тоже нуждаются в периодическом обновлении и конфигурировании. И подходы к этим действиям у разных команд могут быть различными. В результате разработчики вносят изменения в свою инфраструктуру быстрее, чем специалисты, обслуживающие стейджинг и продакшен. В результате возможна ситуация, когда разработчики уже обновили свои серверы, и пишут и отлаживают код в новой среде, в то время, как QA еще используют старый набор компонентов, из-за чего результаты тестов могут начать существенно различаться. Так что, очень важно, чтобы обновления и изменения конфигурации согласовывались, между всеми участниками CI/CD. По этим же причинам важно повышение прозрачности процессов.
Важно понимать, что и разработка, и тестирование нуждаются в независимых окружениях. Это очевидно по многим причинам. Прежде всего, окружение, которое используют разработчики содержит больше различных компонентов, необходимых для разработки. Среда, в которой работают тестировщики уже не содержит такого многообразия компонентов и обычно содержит только те библиотеки, которые необходимы для работы приложения. Зато у тестировщиков крутится множество различных скриптов, тестирующих приложение. С точки зрения безопасности, среда, в которой работают разработчики содержит меньше ограничений, чем тестовая, а тестовая в свою очередь менее ограничена чем стейджинг и продакшен.
В результате у нас в CI/CD присутствует несколько окружений и возникает ряд проблем. Так как окружений несколько, то не всегда понятно, кто за что отвечает и как следствие состояние окружений не синхронизировано. Множество компонент и множество окружений существенно усложняют инфраструктуру. И еще один очевидный недостаток - нехватка ресурсов. Чем сложнее инфраструктура, тем больше ресурсов требуется для ее функционирования.
Решения для автоматизации
Пожалуй, наиболее известным инструментом CI/CD является Open Source фреймворк Jenkins. Данный проект, написанный на Java, содержит множество сторонних расширений, однако как и положено подобным решениям, требует настройки перед началом работы. Основным узлом является контроллер (Master), который является управляющим центром, отвечающим за планирование задач. Задачи запускаются согласно расписанию на подчиненных серверах (Slave), которые необходимо прикрепить к мастеру. В Jenkins важную роль играют журналы - логи выполнения задач. Так как вся история фреймворка хранится только на Мастере, необходимо корректно настроить хранение и ротацию логов, чтобы не оказаться вдруг в ситуации, когда вы хотите узнать кто закоммитил код пару недель назад, а журналов уже нет.
Результаты выполнения задач подчиненные серверы, которые также иногда называют агентами, возвращают Мастеру. Для взаимодействия между Мастером и слейвами можно использовать различные протоколы.
Проект с открытым исходным кодом Nexus Sonatype — это репозиторий поддерживающий множество форматов артефактов, таких как Docker, Java и другие. С помощью Nexus можно собирать и управлять зависимостями и распространением программного обеспечения. Это единый источник всех компонентов, двоичных файлов и артефактов сборки. На рисунке ниже представлен один из вариантов взаимодействия между Jenkins и Nexus в процессе CI/CD.
RunDeck
И еще один это open source проект – Rundeck. С помощью этого инструмента автоматизации можно развернуть сервер сценариев, который позволит автоматизировать рутинные и шаблонные работы. Например, можно практически на любом количестве узлов выполнить скрипты и проконтролировать их выполнение. Rundeck объединяет все уже используемые инструменты и позволяет организовать прозрачное взаимодействие между ними.
Rundeck представляет собой сервер, работающий на Java. С этого сервера осуществляется подключение к управляемым узлам и получение результатов. Все результаты работы хранятся в выделенной БД. Инструмент поддерживает Windows, Linux и Mac OS.
Заключение
В этой статье мы рассмотрели культуру CI/CD, какие преимущества дает использование конвейерной разработки ПО и с какими проблемами можно столкнутся в процессе интеграции различных подразделений в общий процесс CI/CD. Также в статье были кратко рассмотрены основные инструменты, позволяющие выстроить процесс CI/CD.
Также хочу порекомендовать всем бесплатный урок курса DevOps практики и инструменты от OTUS, где мои коллеги расскажут про 3 основных принципа безопасности инфраструктуры. В уроке будет демо, где эксперты OTUS разберут одну проблему на инфраструктуре - очень интересный протокол Диффи-Хеллмана на примере больших чисел с отсылкой на эллиптические кривые и криптографию.Преподаватель на пальцах покажет как работает алгоритм и как исправить проблему связанную с ним в nginx.