0
Обложка: Деплой монолита на .NET Framework 4.8 и Oracle с помощью Ansible

Деплой монолита на .NET Framework 4.8 и Oracle с помощью Ansible

Павел Кузнецов
Павел Кузнецов
​​

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

  1. Почему Ansible, а не PowerShell
  2. Как настроить деплой приложения
  3. Как деплоить базу данных Oracle
  4. Деплой бэкенда и фронтенда приложения
  5. И пара лайфхаков

Почему Ansible, а не PowerShell

  • Один подход написания плейбуков для Windows и Linux-серверов. То есть у нас есть единая среда автоматизации. И если ты умеешь писать под Linux, то сможешь и под Windows.
  • Достаточно декларативный язык. Мы указываем, что хотим получить на выходе, и Ansible своим движком выдаёт результат.
  • Ansible позволяет хранить всю инвентаризацию серверов и стендов (а только в нашей системе их порядка десяти, плюс различные настройки приложения для разных стендов).
  • Огромное количество модулей для работы с различными фреймворками, программным обеспечением и железом.
  • Есть полная поддержка Redhat.

Тем, у кого планируется большой объём автоматизации на Ansible или других скриптах и требуется комплексное управление всем этим процессом, стоит посмотреть в сторону opensource проектов AWX или Rundeck.

Как настроить деплой приложения

Подготовить серверы

Сперва открываем сетевые проходы от Linux-агентов в TeamCity до управляемых серверов. Это порты 5985/tcp, 5986/tcp для Windows и 23/tcp в Linux для SSH.

Затем добавляем учётную запись, под которой мы будем подключаться и управлять конечными серверами в локальную группу Администраторы. Включаем службу WinRM — настройки по умолчанию будет достаточно — и аутентификацию CredSSP (другие виды аутентификации либо сложно настроить в компании, либо вовсе нельзя).

winrm quickconfig
Enable-WSManCredSSP -Role Server -Force
Add-LocalGroupMember -Group Administrators -Member "ваша учетка для управления"

После остаётся только подготовить инструменты для работы с самим Ansible. Я использую Git, VS Code и набор плагинов: GitLens, Redhat Ansible, Redhat XML и Prettier — Code formatter.

Создать репозиторий для деплоя

В Bitbucket создаём отдельный репозиторий, где будем хранить всё, что связано с деплоем на Ansible. Это нужно, чтобы отделить скрипты деплоя от репозитория проекта системы, тем самым ограничив права доступа к ним. Доступ должен быть только у DevOps-инженеров и прикладных администраторов. Мало ли кто случайно поправит конфиг-файл для продуктивного сервера — и после деплоя получим неработающее приложение.

Подготовить билд конфигурации в TeamCity для запуска Ansible

Сначала готовим отдельную build configuration (далее — билд), которая собирает Ansible плейбуки для конкретной задачи. Этот билд подключается в build chain общего процесса деплоя, после того как все артефакты прошли проверки ИБ и загружены в хранилище Nexus.

Это позволяет параллельно использовать билд Ansible для разных веток проекта.

Допустим, в проекте требуется создать новый Windows-сервис. Разработчики создают отдельную ветку для этой задачи и разрабатывают сервис. Но нам надо уже готовить деплой для будущего сервиса: установить сервис, настроить файлы конфигурации. Чтобы ничего не ломать в текущем деплое, в Ansible-проекте создаём ветку с аналогичным названием под разработку этой новой фичи и тестируем их параллельно.

После того как сервис будет готов и протестирован вместе с нашим изменённым деплоем, делаем Pull Request в master-ветку Ansible. И получаем master-деплой, уже скорректированный под новый сервис.

Иллюстрация: деплой приложения

Build chain

Как деплоить базу данных Oracle

  1. Разработчики готовят изменения в БД в виде SQL-запросов и помещают в changeset Liquibase, которые применяются в процессе обновления.
  2. Liquibase артефакты проходят проверку синтаксиса и проверку на безопасность, после чего загружаются в Nexus.
  3. Ansible в виде плейбука запускает процесс применения миграций.
  4. После обновления БД, Ansible проверяет логи Liquibase, была ли успешной миграция. Если всё хорошо, он переходит к следующей схеме, если нет — выводит сообщение об ошибке.

Liquibase можно запускать напрямую из агентов TeamCity, в виде команды liquibase —changelog-file=master.changelog.xml update-sql, но мы поместили его запуск в Ansible, чтобы весь процесс деплоя был в плейбуке и не хранился в билдах TeamCity.

Зелёным цветом подсвечиваем успешные выполнения задач, а красным то что выполняется с ошибкой.

Иллюстрация: деплой приложения

Иллюстрация: деплой приложения

Иногда миграция БД завершается ошибкой, чаще всего из-за неверных SQL-скриптов. Такие ошибки передаются специалисту, который занимался их разработкой.

Почему Liquibase

В нашем проекте, в БД хранятся не только данные, но логика приложения (да-да, так тоже бывает, когда приложению более 10 лет).

И так как у нас есть множество стендов (Dev/Test/Prod и другие), то нужно контролировать процесс миграции схемы базы данных. Запускать файлы с SQL-скриптами для можно, но процесс требует человеческого контроля. А где человек — там потенциальные ошибки: не доглядел, забыл, не проверил. В итоге через какое то время БД на разных стендах будет отличаться. Поэтому для управления процессом миграции схем мы используем Liquibase. Кроме того, он:

  • позволяет хранить все изменения, которые мы вносим в базу данных в виде кода;
  • позволяет делать ревью миграции;
  • лучше контролирует процесс изменения схемы БД;
  • разрешён к использованию внутри компании.

Деплой бэкенда и фронтенда приложения

Ansible из коробки управляет файлами и фаерволом, создаёт сайты и пулы приложений в IIS, настраивает порты, привязывает SSL-сертификаты и многое другое.

Это ускоряет создание деплоя. Мы можем взять пустой сервер с ОС Windows, запустить установку фронтенда или бэкенда и Ansible настроит всё за нас:

проверит папку приложения и SSL-сертификат;Иллюстрация: деплой приложения

  • загрузит файлы приложения из Nexus и скопирует на сервер в нужную папку;

  • настроит пул приложений и сайт и привяжет порты и SSL-сертификата;

  • настроит XML-файлы конфигурации приложения — об этом подробнее ниже;

Иллюстрация: деплой приложения

  • настроит аутентификацию для приложения;

  • проверит, что все всё запущено и работает;

Иллюстрация: деплой приложения

  • настроит сервис Windows.

Иллюстрация: деплой приложения

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

Кстати, мы используем и сокращённую версию деплоя, которая пропускает половину задач: останавливает сервис, обновляет файлы и конфигурацию и запускает сервис в работу. Делается это при выполнения плейбука Ansible с помощью тэгов. Такой подход ускоряет деплой примерно на 30%, используется при разворачивании фич на тестирование.

Отдельное внимание стоит обратить на файлы конфигураций

В .NET Framework 4.8 и ниже конфигурация приложения хранится в XML-файлах  web.config или app.config (далее — конфиг-файл). Из-за этого возникают проблемы:

  • надо заботиться об информационной безопасности — то есть в файлах конфигураций не должно быть паролей, токенов и всего что запрещено регламентами ИБ;
  • при автоматизации деплоя, нужно оставить возможность откатиться на предыдущую версию;
  • кто-то из сотрудников может случайно изменить конфигурацию при коммите; и приложение может перестать работать
  • сложно динамически переопределить некоторые параметры конфигурации для стендов.

В .NET версий, 5.0 и выше всё чуть проще: можно хранить конфиги внутри проекта с переопределением для конкретных стендов, а также использовать app secrets и dotnet_environment. В другом проекте, мы уже используем именной такой подход.

Есть два варианта решения.

Использовать механизм трансформации конфиг-файлов msbuild

Мы делаем несколько конфиг-файлов под разные стенды или серверы. И в момент сборки, указываем в Configuration Manager, для какой среды собираем проект: Test, Dev или Prod. Затем msbuild через схему XDT меняет конфиг и помещает его в папку с остальными артефактами приложения

У такого подхода есть несколько минусов:

  • все настройки и схема изменения хранятся внутри проекта;
  • конфиг собирается в момент сборки, хранится в артефактах приложения и уже в готовом виде попадает на стенд в процессе деплоя;
  • изменениями конфиг-файлов занимаются разработчики;
  • хранение паролей в открытом виде в Git и артефактах.

Да, есть механизм шифрования секций конфигурационных файлов. Но он не снимает проблемы с хранением в  Git — и достаточно сложный в эксплуатации. Лучше доработать приложение, чтобы оно взаимодействовало с ПО HashiCorp Vault или Cyberark.

Шаблонизировать конфиг-файлы в Ansible

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

В Ansible хранится файл вида app.config.xdt.j2, в котором хранится шаблонизированная схема XDT для модификации эталонного файла. Звучит странно, но это самый гибкий, безопасный и удобный в эксплуатации способ.

Файл app.config.xdt.j2

Первичные затраты времени на подготовку таких xdt.j2-файлов, сводятся к сравнению эталонного конфиг-файла с тем что есть на стенде. С этим помогает утилита FatAntelope, которая сравнивает файлы и готовит XDT-схему для модификации. Схему мы помещаем в Jinja-файл и шаблонизируем конкретные параметры.

То есть в процессе деплоя приложения мы делаем следующее:

  1. формируем схему: xdt.j2 -> XDT-схема;
  2. применяем её к эталонному конфигу: Git config + XDTсхема
  3. gолучаем .config-файл для стенда

Минусы:

  • тратится время на модификацию xdt.j2-файлов

И пара лайфхаков

Ускоряем Ansible

Когда мы использовали PowerShell для деплоя приложения, запуск скрипта и обновление файлов занимали 20–30 секунд. Но плейбуки на Ansible занимали по 1–2 минуты. Мы начали искать способы ускорить работу.

Сперва оптимизировали запуск самого PowerShell. В чём суть? Библиотеки, связанные с PowerShell, лежат не в машинных кодах, а выполняют JIT-компиляцию каждый раз в момент запуска PowerShell. Это тормозит запуск любого скрипта Ansible.

Чтобы такого не было, достаточно выполнить скрипт, который предлагают сами разработчики Ansible, один раз на всех серверах.

function Optimize-PowershellAssemblies {
  # NGEN powershell assembly, improves startup time of powershell by 10x
  $old_path = $env:path
  try {
    $env:path = [Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory()
    [AppDomain]::CurrentDomain.GetAssemblies() | % {
      if (! $_.location) {continue}
      $Name = Split-Path $_.location -leaf
      if ($Name.startswith("Microsoft.PowerShell.")) {
        Write-Progress -Activity "Native Image Installation" -Status "$name"
        ngen install $_.location | % {"`t$_"}
      }
    }
  } finally {
    $env:path = $old_path
  }
}
Optimize-PowershellAssemblies

Так, выполнение плейбуков на Windows ускорится на 20–30%.

Затем мы выяснили, что в Ansible начиная с версии 2.7 добавлена поддержка протокола PSRP. Это ускоряет работу плейбуков ещё на 30%. Из минусов — протокол не так просто включить в нашем случае, так как нужно скачать несколько пакетов и установить их на агентах в TeamCity, где используется Ansible. Для большинства же, всё просто: pip install pypsrp.

Третий способ — установить OpenSSH 8-й версии на Windows Server и подключаться к нему по SSН-протоколу, а не WinRM. Это тоже ускорит работу, но фактические замеры мы не делали.

Добавляем статистику

В Teamcity логи Ansible красиво подсвечены, и в конце есть статистика скорости выполнения плейбука и конкретных задач. Это включается добавлением в корень проект деплоя Ansbile конфига anisible.cfg.

[defaults]
force_color = True
deprecation_warnings = False
host_key_checking = False
callback_enabled = timer, profile_tasks, profile_roles
callback_whitelist =  timer, profile_tasks, profile_roles
stdout_callback = teamcity

Линтинг скриптов Ansible

Мы достаточно много времени тратим на разработку деплоя. И хорошо бы перед его запуском проверять общее качество кода, синтаксические ошибки. Для этого используйте линтер Anisble, который установлен на агентах TeamCity.

Нужно установить триггер в TeamCity на появление нового коммита или Pull Request в проекте деплоя. И после автоматом проверяете код на потенциальные ошибки.

Тестируем деплой

Обычно стенды Dev/Test/Prod отличаются друг от друга. На Dev стенде всё устанавливается на одном сервере, а в продуктиве всё разнесено по разным серверам и используется балансировка.

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

Самое простое — запускать его на стенды. Но если это не получается сделать, например, они все заняты тестировщиками и разработчиками, можно добавить параметр —check во время запуска плейбука. Тогда плейбук отработает всю логику, но без фактического применения на сервере, и вы убедитесь, что всё работает корректно. Для удобства можно сделать кнопку «Тестовый запуск».

Важно! Не все модули корректно работают в режиме --check. Если вы сначала загружаете файл артефакта, а потом распаковываете его, даже при тестовом запуске он будет реально искать файл для распаковки. А не найдя его выдаст ошибку. Решается это с помощью параметра check_mode: no.

Иллюстрация: деплой приложения

На этом всё, если будут вопросы пишите. А если что-то заинтересует, расскажем подробнее.