Обновление процесса CI/CD: год спустя
Это четвертая и заключительная часть цикла об обновлении CI/CD процессов. Кстати, вот оглавление:
Часть 1: что есть, почему оно не нравится, планирование, немного bash. Я бы назвал эту часть околотехнической.
Часть 2: teamcity.
Часть 3: octopus deploy.
Часть 4: внезапно вполне себе техническая. Что произошло за прошедший год.
Сейчас у нас есть рабочая система доставки обновлений, которая прошла испытание временем. О настройке этой системы можно прочесть в первых трёх частях, а сейчас предлагаю вкратце вспомнить что там было.
Осуществлялся переезд CI/CD системы с CruiseControl.NET + git deploy на Teamcity + octopus. Будем честны, CD там и не пахло. Об этом, возможно, будет отдельная статья, но не в этом цикле.
С момента выхода первой статьи цикла прошло чуть больше года, с момента начала работы системы в проде — примерно полтора. Процесс разработки во время внедрения новой системы практически не прерывался. Было два раза, когда делали code freeze: один раз в момент перехода с mercurial репозитория в git (чтобы не потерять коммиты во время конвертации), и второй раз во время перехода билда production окружения с ccnet на teamcity (просто так, на всякий случай).
В результате мы получили систему которая способна наиболее оптимально (с минимальными время- и ресурсозатратами, а также с минимальными рисками) доставлять обновления во все существующие окружения.
С момента выхода 3 части статьи в конфигурации произошли некоторые изменения, о которых, наверное, стоит рассказать.
Что произошло за этот год
Мы практически полностью отказались от конфигураций вида «Build + deploy». Теперь используем отдельно Build и отдельно Deploy. Последние всё также вызываются из teamcity, но это сделано исключительно для упрощения жизни всем менее причастным. На самом деле, для того чтобы обезопасить Octopus от вмешательства любопытных.
Полностью перешли на semver. К сожалению, до момента внедрения девопс в проект, ни о каком semver речи не было. Картинка с этой версионностью уже мелькала в 3 части, останавливаться подробно не будем.
Появился опыт настройки деплоя на сервере без каких-либо доступов, только с установленным octopus агентом. Не то, чтобы его не было, просто он был забыт как страшный сон за много лет. А тут пришлось вспоминать. Приятного мало, но на удивление, терпимо.
Перешли с Visual studio (sln) раннера на .net msbuild ввиду окончания поддержки первого (Teamcity).
Для Special Module (см часть 1) появился интересный вызов билда из деплоя с пробросом параметров через reverse.dep…
Появился какой-никакой роллбек.
Переработали variable set«ы в octopus, используем tenant variables.
Практически везде перешли от хранения connection string в репозитории на хранение в Octopus и подстановкой при деплое. К сожалению, раньше хранили именно в репозитории.
Для деплоя особо важных модов добавили защиту от тестировщика (подробнее чуть позже).
Выросли на 7 новых тенантов (клиентов).
В общем, звучит круто, предлагаю остановиться на некоторых пунктах подробнее.
Build-chain наоборот (пункт 4)
Для Special module, как и для любых других есть несколько окружений. Список всех пайплайнов для этого модуля в teamcity выглядит так:
Build конфигурация используется одна, с вот таким параметром ветки:
Также в данной конфигурации используются две prompted переменные типа Select: env.Environment и env.buildBranch. Выглядят они примерно одинаково, отличаются только Items. Для каждого env ставится в соответствие ветка репозитория.
С учётом всех настроек, перечисленных выше, запуск билда вручную выглядит следующим образом:
В каждой Deploy конфигурации, есть зависимость от актуальности конфигурации build и параметры типа reverse.dep, которые при запуске Build устанавливают для него env.Environment и env.buildBranch. Например, для development это выглядит так:
Как всё это работает вместе: при нажатии кнопки deploy соответствующего окружения проверяется наличие изменений в репозитории. Если изменения есть — запускается конфигурация Build с установленными через reverse.dep переменными. По завершению билда, запускается ожидавший всё это время деплой новой версии пакета.
Rollback (пункт 6)
Rollback построен на следующем алгоритме:
Определить номер текущего и предыдущего релизов в octopus для Core и Module.
Откатить Core (задеплоить предыдущий релиз)
Откатить Module.
Octopus хранит 3 предыдущих релиза так, на всякий случай. Rollback из teamcity работает только с предыдущим релизом. Откат на более давний релиз надо делать вручную, но такой необходимости ни разу не возникало. Так выглядят определение версий:
$packageRelease = ((%env.octoExe% list-deployments --server="%env.octoUrl%" --apikey="%env.octoApiKey%" --project="ProjectName.%env.modName%" --environment="%env.Environment%" --outputFormat=json) | ConvertFrom-Json).Version[0..1]
$coreRelease = (((%env.octoExe% list-deployments --server="%env.octoUrl%" --apikey="%env.octoApiKey%" --project="%env.coreProjectName%" --environment="%env.Environment%" --outputFormat=json) | ConvertFrom-Json).Version | Get-Unique)[0..1]
$OctopusPackageCurrentRelease = $packageRelease[0]
$OctopusPackagePreviousRelease = $packageRelease[1]
$corePreviousVersion = $OctopusPackagePreviousRelease | %{ $_.Split('-')[0]; }
$coreEnv = $OctopusPackagePreviousRelease | %{ $_.Split('-')[1]; } | %{ $_.Split('+')[0]; }
$OctopusCoreCurrentRelease = $coreRelease[0]
$OctopusCorePreviousRelease = "$corePreviousVersion-$coreEnv"
Write-Host "##teamcity[setParameter name='OctopusPackageCurrentRelease' value='$OctopusPackageCurrentRelease']"
Write-Host "##teamcity[setParameter name='OctopusPackagePreviousRelease' value='$OctopusPackagePreviousRelease']"
Write-Host "##teamcity[setParameter name='OctopusCoreCurrentRelease' value='$OctopusCoreCurrentRelease']"
Write-Host "##teamcity[setParameter name='OctopusCorePreviousRelease' value='$OctopusCorePreviousRelease']"
Откат является деплоем соответствующей версии, поэтому глобально ничем не отличается от шага Deploy.2 описанного в части 2. Меняется только Release Number. Вместо latest используется %OctopusCorePreviousRelease% и %OctopusPackagePreviousRelease% соответственно.
Переработка variable sets
Раньше все переменные тенантов хранились в конфигурациях проектов и разруливались расстановкой скоупов. Вот хороший пример из части 3:
При количестве тенантов больше 3 это оказывается неудобно. Поэтому, перешли к хранению переменных клиентов в предназначенном для этого месте — tenant variables — common variables.
Так списки переменных проектов стали чище, и там больше нет каши.
Защита от тестировщика (пункт 9)
В список задач тестировщика входит также деплой на некоторые окружения. Туда, куда деплои не попадают автоматически из за ограничений. Зачастую это выглядит как «клик клик клик клик» по кнопкам Run не задумываясь. Исключение составляет prod окружение, но это не точно. Пару раз были прецеденты деплоя модов, которые помечены как secure. Это особая категория модов, которыми пользуются особые люди. Они очень любят стабильность и все релизы у них планируются, а набор новых фич обсуждается. В общем, для этих модов пришлось добавить элементарную защиту в виде всплывающего «Are you sure» и требованием ввести ответ буквами.
Реализовано это с помощью prompted переменной и regexp.
Заключение
В данный момент я работаю над этим проектом по минимуму. Саппорт практически не требуется, всё работает практически без моего участия. Где-то есть continuous deployment, где-то пришлось ограничиться delivery. Там где надо нажимать кнопки вручную — справляются тестировщик и главный девелопер. Время добавления новых конфигураций (по факту нового клиента) вместе с проверкой работоспособности — час с чайком и без напряга. С CCNet такой результат показался бы фантастикой при условии отcутствия дичайшего оверхеда со стороны ресурсов сервера. Да и удобства никакого. Пропала проблема бесконечной нехватки места, так как на сервере не хранятся лишние копии одного и того же. И даже rollback показал себя с хорошей стороны, и на удивление работает. Всё работает классно шустро, и самое главное — стабильно и прогнозируемо.
Бросать проект в мои планы не входит, но и какие-то крупные изменения в дальнейшем пока не планируются. Так что, я изредка поглядываю в Octopus, радуюсь тому что все работает без моего участия и пилю новые проекты.
Статья получилось вполне технической. На описание неприятных моментов и места то не осталось. Могу сказать, что все неприятные моменты связаны исключительно с впечатлением от windows, а не с проектом. Это всё таки был мой первый проект на оконном стеке. Впечатления непосредственно от проекта только самые лучшие. Хоть это и древнее легаси-зло, проект на самом деле очень крутой и интересный. И опыт поддержки и постановки таких проектов на новые рельсы без преувеличения можно назвать бесценным. В общем, в мире стало на один хороший проект с devops методологией больше.