Сейчас мало кого удивишь инструментами управления зависимостями проекта вроде npm
, composer
, bundler
, pip
, maven
, cargo
и других. Их общий недостаток — невозможность управлять непосредственно средой выполнения. Такая задача решается через nvm
, php-build
, rvm
, virtualenv
, sdkman
, rustup
и прочие глобальные "манагеры" версий runtime, обычно написанные под Bash/Zsh.
Следующий уровень "проблем" начинается, когда универсальный разработчик ежедневно занимается проектами с использованием совершенно разных технологий. Переменные окружения превращаются в месиво, а запуск шелла может занимать несколько секунд. Неизбежно начинаются бытовые ошибки в работе с этим зоопарком.
Далее разброд и шатание настегает Continuous Integration & Delivery, где ручные танцы с бубном установки инструментов и активирования конкретных версий совершенно не приветствуются, а в идеале требуется в принципе максимально абстрагироваться от используемых технологий и довести процесс до примитивных нейтральных команд: подготовить к релизу, затегить, скачать, подготовить, построить, упаковать, выложить, проверить, одобрить(подписать), выкатить.
Тут сам собой напрашивается инструмент, унифицировано работающий поверх уже существующих технологий,
который из себя и представляет FutoIn CID — FutoIn Continuous Integration & Delivery tool.
Философия FutoIn CID
- Использовать специализированные проекты внутри, а не заменять их.
- Работать без конфигурации и автоматически определять используемые технологии.
- Избавить пользователя-разработчика от деталей установки зависимостей проекта.
- Работать даже на "голом" Python 2.7 и 3.x
- Оставлять возможность настройки CID и переопределения команд по-умолчанию.
- Обособленная спецификация FTN16, допускающая альтернативные реализации.
- Поддержка всех распространённых операционных систем и неограниченного количества инструментов разработки.
- Полная абстракция от конкретного инструмента и его особенностей. Лишь деление инструментов по типу применения: для сборки, для тестирования, система контроля версий, система управления релизами, среда исполнения, миграции данных и т.п.
- Вынужденная унификация и ограничение слишком вольных инструментов (например Subversion в плане веток и тегов).
- Всё состояние хранится в древовидной структуре, которая полностью отражает конфигурационные опции, среду развёртывания и динамические значения параметров командной строки.
Базовые операции
cid tag
— подготовить код к релизу, затегить.cid prepare
— получить и подготовить код к чистой сборке, установить все зависимости.cid build
— собрать проект.cid package
— подготовить бинарный артефакт.cid check
— запустить тесты, не требующие развёртывания.cid promote
— отправить бинарный артефакт в RMS или же продвинуть ранее
загруженный в другой пул.cid deploy
— развернуть из бинарного артефакта, из VCS тега или же из ветки.cid run
— запустить проект по конфигурации "точек входа", по конкретной точке входа или же по именованной команде.cid ci_build
—prepare
,build
,package
иpromote
в одном флаконе для выполнения на CI сервере.cid tool (install|uninstall|update|test|env)
— интерфейс для управления инструментами.cid tool (prepare|build|check|package|migrate)
— вызов стандартный операций для конкретного инструмента.cid tool (list|describe)
— список поддерживаемых инструментов и более подробное описание.cid init
— инициализация файла конфигурацииfutoin.json
.
Немного реальных действий
Всё происходит на девственно чистом vagrant боксе debian/jessie64
.
1. Устанавливаем на примере APT-based дистрибутива (Debian, Ubuntu и прочие форки).
sudo apt-get install -y python-pip
sudo pip install futoin-cid
# Наша импровизированная RMS
mkdir -p ~/Releases/Builds ~/Releases/Prod
2. Настройка sudo
В целях нахождения баланса между паранойей и удобством предлагается разрешить только установку пакетов без пароля. Подробнее в README.
Для некоторых случаев Docker и JRE/JDK от Zulu требуется возможность устанавливать ключи для проверки подписи и дополнительные репозитории. Если есть опасения в рамках sudo
, то это не так уж сложно сделать и руками, т.к. все исполняемые команды выводятся.
В случае Vagrant'а нам можно всё по умолчанию.
3. Попробуем собрать какой-нибудь HelloWorld.
cid ci_build master Builds --vcsRepo=git:https://github.com/laravel/quickstart-basic.git --rmsRepo=scp:${HOME}/Releases
много буковок
А теперь посмотрим, что же вышло.
tar tJf ~/Releases/Builds/laravel-CI-*.txz --exclude="*/*/*"
./
./composer.json
./storage/
./vendor/
./resources/
./.package.checksums
./LICENSE.txt
./composer.lock
./database/
./.env.example
./.env
./LICENSE.txt.gz
./node_modules/
./artisan
./.gitattributes
./phpunit.xml
./tests/
./gulpfile.js
./app/
./gulpfile.js.gz
./config/
./package.json
./public/
./server.php
./composer.json.gz
./readme.md
./package.json.gz
./bootstrap/
Мы видим полноценный бинарный артефакт, готовый для развёртывания. По умолчанию, CID также сделает GZIP версии найденных .js, .json, .css, .svg и *.txt файлов для использования вместе с модулем gzip_static в nginx.
В качестве импровизированного манифеста создаётся файл .package.checksums
с хешами SHA-512.
Примечание: упаковка корня проекта лишь стандартное действие в отсутствии иной реализации. Например, maven или puppet сами создают артефакты
4. Развёртываем с RMS
cid deploy Builds --rmsRepo=scp:${HOME}/Releases --deployDir=deploy
Примечание: по умолчанию CID сам находит наиболее поздний артефакт в выбранном пуле для развёртывания, если явно не указывать название. То же относится к тегам.
Разумеется, для развёртывания на одной машине не очень серьёзного проекта такой шаг возможно пропустить и разворачивать прямо с VCS тега.
5. Развёртываем прямо с VCS
Ввиду отсутствия тегов в примере, будем использовать живую ветку проекта.
cid deploy vcsref master --vcsRepo=git:https://github.com/laravel/quickstart-basic.git --deployDir=deploy
много буковок
Повторим без изменений ветки и получим предупреждение об уже развёрнутой ревизии. С тегами и артефактами будет то же самое.
cid deploy vcsref master --vcsRepo=git:https://github.com/laravel/quickstart-basic.git --deployDir=deploy
Пример подготовки кода проекта к релизу
Подготовка конкретной версии, вызывая из локальной копии.
cid tag master 1.0.0
Релиз следующей инкрементальной версии, не имея локальной копии на момент вызова.
cid tag master --vcsRepo=git:user@somehost:project.git
Стандартные действия: синхронизация с удалённым репозиторием, обновление всех возможных файлов метаданных, коммит, создание тега. Пример релиза самого CID:
Проект может использовать дополнительные плагины. Например, CID обновляет версию в исходном коде и в CHANGELOG.
Работаем с отдельными инструментами
rubyVer=2.3 cid tool exec ruby -- -e 'puts "Hello World!"'
Если инструмент ещё не установлен, то будут сделаны все необходимые операции. В данном случае установлен RVM, а потом уже и актуальный Ruby 2.3.*. При этом RVM не будет грузиться при запуске шелла и стандартные переменные окружения не будут загрязнены.
Информация об инструменте
cid tool describe maven
Чуток технических деталей
Файл futoin.json
По аналогии с небезызвестными package.json
, composer.json
, Cargo.toml
и прочими представляет из себя описание проекта, если располагается в его корне. В нём допускается задавать общие настройки проекта, но наличие файла не является обязательным.
При запуске, CID ищет возможные настройки среды развёртывания в корневой папке развёртывания — позволяет задать и настройки проекта, и настройки окружения (узел .env
), а в домашней папке активного пользователя и в /etc/futoin/futoin.json
— только узел .env
.
Примечание: узел .env не является аналогом и не заменяет "dotenv" файлы.
Более подробно допустимые значения документированы в FTN16.
Самые интересные узлы:
actions
— позволяет переопределить или дополнить стандартные операции tag/prepare/build/package/check.plugins
— позволяет добавить дополнительные инструменты.tools
— позволяет жёстко указать список используемых инструментов и опционально их версии.
- Версия
'*'
иtrue
— требует версию по умолчанию - Иначе, версия попадает прямо в переменную среды
{tool}Ver
и доступна в плагинах как узел.env.{tool}Ver
глобального состояния.
- Версия
toolTune
— возможность специфичной тонкой настройки каждого инструмента. Детали доступны вcid tool describe {tool}
.entryPoints
— указание именованных точек входа.persistent
— список read-write путей в проекте. Специфично для веба.
Пример файла futoin.json
в корне проекта:
{
"name": "example-package",
"version": "0.4.2",
"actions": {
"package": []
},
"plugins": {
"examplerelease": "some.project.specific.release",
"examplehelper": "some.other.helpertool"
},
"vcs": "git",
"tools": {
"examplerelease": true,
"python": "*",
"node": "stable",
"gradle": "*"
},
"toolTune" : {
"gradle": {
"package": "jar"
}
},
"rms": "scp",
"rmsRepo": "rms@somehost",
"rmsPool": "ReleaseBuilds",
"entryPoints": {
"app": {
"tool": "python",
"path": "app.py",
"tune": {}
}
}
}
Нюансы развёртывания
- {.deployDir} — наша условная корневая папка для развёртывания конкретного проекта.
- {.deployDir}/persistent — область хранения read-write файлов. В кластере подразумевается область сетевой файловой системы.
- {.deployDir}/current — символическая ссылка на актуальную версию.
- {.deployDir}/{version_dir} — конечное размещение конкретной версии:
- {artifact} — название пакета из RMS без расширения,
- {vcsref}_{vcsrevision} — в случае развёртывания из ветки,
- {vcstag} — в случае развёртывания из тега.
- {.deployDir}/{version_dir}.tmp — временная папка в обработке.
- {.deployDir}/{version_dir}.{ext} — не распакованный бинарный артефакт в режиме
rms
. - {.deployDir}/vcs — локальная копия репозитория в режиме
vcsref
иvcstag
. - {.deployDir}/.futoin-deploy.lock — файл блокировки, а также фича безопасности от непреднамеренной зачистки неправильно указанной целевой папки.
- всё остальное зачищается.
Немного о кишках для добавления инструментов
Все инструменты делятся на несколько типов. Один инструмент может сразу относится к нескольким. В перспективе, их может стать больше.
SubTool
— база, интерфейс авто-определения, определения зависимостей, установки, обновления, удаления.BuildTool
— база для инструментов сборки (prepare, build, package).MigrationTool
— база для инструментов миграции (migrate).RmsTool
— база для RMS (promote) и внутренний API.RunEnvTool
— база для version manager'ов (nvm, rvm, gvm и т.п.).RuntimeTool
— база для инструментов запуска (run). Сюда входят: java, python, ruby и т.д.TestTool
— база для инструментов, поддерживающих тестирование (check).VcsTool
— база для VCS (tag) и внутренний API
Для вспомогательных нужд существует набор mixin'ов, часть из которых уже включена в SubTool.
Что есть на данный момент?
Поддерживаются практически все распространённые дистрибутивы Linux: от CentOS и Debian до ArchLinux и Gentoo.
Добавлена экспериментальная поддержка macOS. Нет подходящего оборудования — помощь в тестировании крайне приветствуется.
В качеству proof-of-concept поддерживаются самые различные языки программирования и сопутствующие инструменты: от PHP, Python и Ruby до Go, Rust и Scala. Возможность по расширению и добавлению кастомных плагинов почти неограниченна.
Также поддерживаются три разных VCS: Git, Mercurial и Subversion.
Чего ещё нет?
Поддержка RMS реализована принципиально. Для целей тестирования пока работает только scp
, но основной прицел на Archiva, Artifactory и Nexus.
Поддержка unit test'ов полагается на инструменты сборки проектов (make, gradle, grunt и т.д.), а вот сбор результатов пока не определён. Рекомендации также приветствуются.
Процесс криптографического подписывания пока не определён. Требуется проанализировать и найти общий знаменатель для use case'ов.
В случае необходимости поддержка *BSD предположительно потребует минимальных усилий, а вот поддержка Windows с упором на .Net скорее потребует альтернативную специализированную реализацию.
Интерфейс для миграции данных предусмотрен, но пока не имеет стандартной реализации.
Подытожим
Движимая ленью, патологическим неприятием монотонной возни и страстью к автоматизации, родилась обобщающая концепция для практически всех возможных технологий. К ней добавилась реализация в виде конкретного инструмента FutoIn CID. Безусловно требуется серьёзная шлифовка и обкатка на практике. Помимо упрощения жизни разработчика, дальним прицелом является автоматизация инфраструктуры DevOps.
Разумеется, это не первый инструмент, поддерживающий различные технологии, но возможно первый, который может работать вообще без настройки, улучшая производительность труда и уменьшая количество повседневных ошибок.
sutarmin
На первый взгляд кажется, что от CI инструментов вроде TeamCity ваш отличается только тем, что может по выданному ему репозиторию сам определить необходимые действия сборки и деплоя без какой-либо конфигурации. Но ведь это до первой технологии, которая будет неизвестна вашему мета-сборщику. Может я что-то пропустил или вообще не понял концепции? Объясните, пожалуйста.
andvgal
Из того, что возможно почерпнуть из документации TeamCity не особо похоже уже с самого начала:
Разумеется, тут не машинное обучение и требуется создавать плагины для каждой поддерживаемой технологии. В большинстве случаев эти плагины умещаются в 20-30 строк кода.
Во-вторых, CI-сервер это один из кейсов. В первую очередь инструмент предназначен для рабочей среды разработчика, потом для CI сервера и частично для CD,