Привет! На первый взгляд название этой статьи может показаться вам странным: Java и Visual Studio – что между ними общего? Зачем вообще Visual Studio, когда есть множество других классных инструментов для разработки на Java: Eclipse, NetBeans, IntelliJ IDEA и прочих (холивар устраивать не будем). На самом деле, Visual Studio сейчас – это не просто среда для разработки, а целое семейство продуктов, где IDE Visual Studio лишь один из инструментов. Под катом мы поговорим о Microsoft Visual Studio Team Services (VSTS).
Microsoft Visual Studio Team Services – это DevOps облачная платформа, позволяющая гибко выстраивать DevOps процессы непрерывной интеграции, сборки и развертывания (CI/CD). Конечно, тут не обходится без поддержки контроля версий, встроенной системы bag tracking, инструментов Agile планирования и многих других возможностей для разработчиков разных «религий», и «мастей». И, конечно, для разработчиков на Java тоже найдётся полезный функционал для DevOps автоматизации своих решенияй. О том, как им можно эффективно использовать возможности VSTS, и пойдет речь в нашей сегодняшней статье.
На протяжении 20 лет своего существования Java платформа сформировала вокруг себя богатую экосистему из разных инструментов для сборки, развёртывания, тестирования приложений, которыми Java разработчики пользуются в повседневной практике, и многие из которых, по сути, уже стали промышленным стандартом (Maven, Gradle, Ant, JUnit, JMeter и многие другие). И, конечно, у каждого разработчика или команды есть свои предпочтения по выбору инструментов: кто-то привык собирать проект используя Maven, а кто-то, использует Gradle. Основная идея VSTS — предоставить разработчикам возможности, которые позволят выстроить CI/CD процессы максимально гибко, используя знакомые и привычные OSS инструменты для сборки, развертывания, тестирования. VSTS — это облачная платформа (в отличие от Microsoft Team Foundation Server, который развертывается on-premise), однако, благодаря такому механизму как агенты сборки (build agents), о которых мы будем говорить ниже, сборку можно производить, например, on-premise (у вас в ЦОДе), и, конечно, на ваших виртуальных машинах в облаках (Azure, AWS, Google и другие платформы).
Нагляднее всего возможности VSTS можно проиллюстрировать на простом примере Java приложения с полным циклом сборки и развертывания. Сразу оговорюсь, что я не буду описывать полный и детальный step-by-step tutorial, цель данной статьи донести идею использования VSTS платформы для Java DevOps процессов.
Для наших экспериментов вам понадобится учетная запись Microsoft Visual Studio Team Services. Вы можете получить ее бесплатно, используя свой Microsoft Account или, создав новый.
Итак, начнем наше увлекательное путешествие. Зарегистрировавшись, нам нужно создать проект.
Указываем имя проекта, Git как систему контроля версий и создаем новый проект.
После создания проекта, VSTS автоматически создает новый Git репозиторий и предлагает клонировать его на вашу рабочую машину используя Git CLI или клонировать и открыть его в Java IDE, например, IntelliJ IDEA, также поддерживается и Eclipse. Для этих двух IDE есть плагины для интеграции с VSTS.
Мы вернемся к интеграции с IDE в нашей статье чуть позже, а сейчас просто клонируем код из GitHub. Кликаем Import, указываем URL нашего GitHub репозитория (https://github.com/easkerov/SampleJava.git) и завершаем импорт. В нашем случае репозиторий публичный и авторизация не нужна, но, конечно, вы можете использовать и приватные репозитории, указав нужные credentials для доступа.
После завершения импорта, будет открыт Filesexplorer для нашего репозитория, где можно добавлять и вносить изменения в артефакты приложения, переключаться между ветками или создавать новые. Конечно, в рамках одного проекта, может быть несколько репозиториев, и вы можете конфигурировать отдельные CI/CD процессы для них.
А мы переходим к следующему этапу – сборке нашего приложения. Для этого нам нужно создать Build Definition (определение сборки) в нашем проекте.
В VSTS есть 2 важных понятия, связанных с конфигурированием CI/CD процессов. Это определение сборки (Build Definition) и определение релиза (Release Definition). Оба определения позволяют очень гибко выстроить DevOps процессы через концепцию заданий (tasks). Задания могут быть разных типов: например, сборка проекта в Maven, выполнение Bash скрипта, сборка Docker контейнера, копирование файлов, развертывание приложения в Tomcat контейнере – все это примеры заданий, из которых вы можете собирать ваши CI/CD процессы. При создании определения процесса сборки, можно пользоваться уже готовым шаблоном (template) c заданным набором заданий под определенную задачу (например, сборка проекта в Maven/Gradle) или создать пустое определение сборки и самому определить набор заданий в этом процессе. В нашем случае, мы выберем пустой шаблон (empty template) и сами определим задания в нем.
Порядок сборки и публикации нашего приложение будет следующий: первым шагом мы должны установить все front-end зависимости используя менеджер пакетов Bower, далее собираем наше приложение в Maven, в результате получаем war артефакт, который помещаем в Docker контейнер c Tomcat и публикуем его в Docker Registry (в нашем случае это будет приватный registry на базе Azure Container Registry).
Создав пустой шаблон, мы должны определить в нем необходимые задачи. Каждый шаг нашего CI процесса – это отдельная задача. Например, сборка Bower – это отдельный task, который нам нужно добавить в наш CI pipeline и настроить. Однако, не все задачи доступны в VSTS «из коробки». Например, Bower задачи по умолчанию в VSTS нет. Но, к счастью, есть Visual Studio Marketplace, где Microsoft и сторонние разработчики публикуют VSTS расширения для интеграции с различными инструментами. Установка этих расширений в VSTS предельно простая, достаточно найти нужный модуль и установить его к себе в окружение, кликнув Install и указав свою учетную запись VSTS.
Перед тем, как определить конкретные задания для сборки нашего приложения, необходимо указать где будет происходить сборка нашего приложения. Собирать мы его можем, используя механизм агентов сборки и релиза/развертывания (Build/Release agents) который есть в VSTS. Агенты могут быть двух типов: hosted и private. Hosted агенты использовать проще всего, так как эти окружения (VM) для сборки нам выделяет сама VSTS платформа со всеми вытекающими преимуществами cloud computing (обслуживание, upgrade и т.д.). Причем есть выбор ОС для окружения — это может быть Windows/Linux (последний пока в preview). Но что, если у нас сложный случай, и для окружения, в котором мы будем собирать Java приложение нужна специфическая сложная настройка компонентов сборки (например, нужно определить приватный репозиторий Maven в settings.xml). В этом случае можно самим развернуть окружение (на Linux/Windows/MacOS), установить Private Build Agent и инициировать сборку приложения в нем из VSTS консоли. Причем собственное окружение (VM) может быть развернуто в облаках (Azure, Google, AWS) или в собственном ЦОДе.
Для нашего примера вполне достаточно Hosted агента на Linux машине. Необходимо задать это явно в настройках процесса (Process).
Далее выстраиваем CI процесс, и определяем задачи, которые будут выполняться в нем.
В нашем CI процессе будет 6 задач. Давайте рассмотрим подробнее из чего он будет состоять.
Перед началом сборки, клонирование файлов из Git репозитория проекта в текущее окружение (виртуальную машину) происходит автоматически, далее VSTS выполняет последовательность задач, которые мы указали в определении сборки.
Bower.Install. Первая задача, Bower.Install, позволяет нам установить все front-end зависимости используя менеджер пакетов Bower. Для этого нужно лишь правильно настроить параметры задачи. Как видно из скриншота выше, конфигурация простая и не требует специальных комментариев (разве что нужно указать явно --allow-root).
Maven.Build. На втором шаге мы осуществляем сборку приложения, используя Maven task, и pom.xml артефакт из Git репозитория нашего приложения. Кроме имени задачи и Maven goals, можно настроить параметры публикации JUnit тестов, указать настройки JDK (версия, архитектура, настройки памяти и т.д.), а также подключить инструменты для статического анализа кода (SonarQube, Checkstyle, PMD, FindBugs) и покрытия кода (JaCoCo, Cobertura и т.д.).
Docker.ImageBuild. На третьем шаге мы выполняем сборку Docker образа, используя уже готовый Dockerfile из Git репозитория нашего проекта. Для этого шага используется задача Docker task (которая, будет использоваться и на следующем шаге). В качестве Action параметра мы выбираем Build an image и Dockerfile. Дополнительно также можно указать параметры для сборки образа.
Docker.ImagePush. На четвертом шаге происходит публикация собранного нами на предыдущем шаге Docker образа в приватный Docker registry, в качестве registry в нашем случае используется Azure Container Registry (ACR), но вы можете использовать и другие приватные/публичные Docker registry (Docker Hub). Обратите внимание, что здесь мы используем тот же самый Docker task, что и на предыдущем шаге, но Action параметр в этом случае установлен как Push an Image. В качестве имени образа, который собираем и публикуем мы указываем выражение devopsdemoregistry.azurecr.io/javademo:v$(Build.BuildId), где $(Build.BuildId) это переменная с ID текущей сборки.
Приложение мы собираемся развертывать в облачную службу контейнеров Azure Container Service и в качестве системы управления контейнерами будем использовать хорошо известный Kubernetes. Для публикации был заранее подготовлен YAML манифест с описанием deployment и service объектов Kubernetes.
Shell Script. В YAML артефакте нужно правильно определить Docker image, который мы собираемся использовать в deployment. В случае каждой новой сборки помечаем каждый собранный Docker image с нашим приложением используя Build ID в image tag, соответственно и при развертывании, в CD процессе мы должны запускать deployment процесс, используя образ c нужным нам Build Id. Для этого в YAML манифесте нужный образ определяется при помощи подстановки значения параметра, и происходит это на 5 шаге с помощью Shell Script task и Linux команды sed.
Publish Artifact. Наконец, мы подошли к финальному, 6-му шагу нашего CI процесса. Так как приложение запускается в контейнере, Docker image которого мы опубликовали в ACR на 4-ом шаге, никаких других артефактов приложения мы публиковать не будем. Единственный артефакт, который нам необходим для CD процесса это модифицированный YAML манифест для развертывания в Kubernetes. Его мы и будем публиковать на этом шаге. Опубликованный YAML артефакт будет использоваться далее в release definition для развертывания приложения через Kubernetes task.
Наш CI процесс почти сконфигурирован, остается лишь несколько дополнительных настроек, и мы можем проверять процесс сборки. Для запуска CI процесса после каждого изменения в выбранной ветке исходного кода (например, master), необходимо включить опцию Continuous Integration в свойствах Build Definition. Кроме того, одновременно можно включить опцию сборки по расписанию (Scheduled).
Наш build definition готов и сейчас самое время его протестировать. Жмем Save & queue, далее VSTS предложит нам подтвердить настройки сборки, и наслаждаемся процессом.
После размещения сборки в очереди, процессу будет присвоен Build ID, о чем VSTS сообщит нам.
Перейдя по ссылке с Build ID, вы увидите процесс выполнения сборки и исполнения тех задач, который мы определили ранее. После завершения сборки, можно просмотреть статистику тестов, покрытия кода (если вы настраивали), logs и, наконец, загрузить артефакты, которые были опубликованы в результате сборки.
Мы публикуем наш Docker image после каждой сборки в Azure Container Registry и открыв Azure Portal консоль, для нашего registry, можем действительно убедиться, что наш образ опубликован.
После завершения CI процесса, мы готовы двигаться далее и настроить CD процесс для нашего Java приложения. Для этого нам необходимо создать новый Release Definition (определение релиза) в нашем проекте.
Для приложения мы будем использовать пустое определение и добавим в него нужные задачи.
На следующем шаге VSTS предлагает указать проект и определение сборки на основе которого будет происходить наше развертывание. Дополнительно включаем опцию Continuous deployment, что означает что развертывание начнется сразу после успешного окончания сборки (CI процесса) для нашего приложения.
Для CD процесса необходимо выполнить некоторые настройки: дать осмысленное имя определению и CD окружению и выбрать Release Agent который будет использоваться для развертывания. В нашем случае продолжаем использовать Hosted Linux Preview. Обратите внимание на понятие окружения (environment) в контексте Release Definition. Окружения – это логические сущности, которые определяют, где мы будем развертывать приложение. В нашем простом примере — это только Dev окружение, но для промышленных решений сюда могут добавиться Test, Q&A, Stage, Prod окружения и т.д. Соответственно, для каждого окружения может быть свой набор задач, с разными алгоритмами развертывания в разные физические или виртуальные окружения. Кроме того, существует специальный механизм утверждений (approvals), который позволяет не начинать развертывание в следующем окружении до тех пор, пока пользователь или группа пользователей с соответствующими правами не утвердит (или откажет) в продолжении CD процесса. Например, развертывать приложения в Prod после Stage только после утверждения одного или нескольких пользователей.
Теперь мы готовы добавить одну единственную задачу для CD процесса, — Kubernetes task. Однако, по умолчанию этого расширения в каталоге VSTS нет, но снова выручает Visual Studio Marketplace, о котором я уже говорил выше, где его можно найти и установить для своей учетной записи VSTS.
По сути, в Kubernetes task, используется kubectl CLI и при помощи команды apply применяется наш YAML манифест и происходит развертывание приложения в Kubernetes (напоминаю о том, что приложение мы собираемся публиковать в облачную службу контейнеров Azure Container Service).
CD процесс готов и самое время запустить развертывание.
После запуска развертывания, мы увидим наш процесс в списке, после этого его можно открыть и проследить прогресс выполнения и результат.
Как видно из результатов выполнения, CD процесс завершился успешно и объекты deployment и service созданы в Kubernetes успешно.
Результаты развертывания можно проверить, проверяя статус pods, deployments и services через CLI kubectl. Ну и конечно, просто перейдя в любимом браузере по ссылке: http://<EXTERNAL-IP>:8080
А что еще есть полезного для Java-разработчиков в VSTS?
VSTS поддерживает интеграцию c различными IDE, позволяя разработчикам работать с платформой, по сути не покидая пределы своей среды разработки. То есть просматривать список задач, назначенных на вас, проводить code review, создавать Pull Requests и многое другое, не говоря уже о привычной работе с GIT репозиторием. В настоящее время поддерживается интеграция через plug-ins для популярных Java IDE: IntelliJ IDEA, Android Studio, Eclipse.
Давайте проверим на простом примере, как это работает для IDE IntelliJ IDEA. Для этого нужно установить plug-in для VSTS. Где его скачать, и как установить описано здесь.
Предположим, нам была назначена новая задача из backlog в VSTS и предварительно создана новая ветка Git branch c названием homepage (это операции можно проделать в консоли VSTS). Первым шагом клонируем нужный Git репозиторий на рабочую машину. Проще всего это сделать, используя опцию Clone и выбрав пункт IntelliJ IDEA. Специальный скрипт автоматически запустит IDE и checkout процесс.
Для примера, отредактируем файл index.jsp, добавив новый элемент в список с заголовком Deployment и сделаем commit и push.
В окне Commit кроме основных настроек вы можете указать непосредственную задачу, с которой этот commit связан. Далее делаем commit и push.
Следующим шагом создадим pull request прямо в IntelliJ IDEA и укажем в качестве target branch ветки — master. Также мы указываем наш последний commit в качестве изменений и создаем pull request.
После создания pull request, его можно открыть и просмотреть в VSTS консоли в браузере.
Для завершения pull request, его необходимо утвердить (approve). Доступ для утверждения имеют пользователи или группа пользователей со специальными правами в VSTS. После завершения approve процесса, pull request можно завершить (complete).
При необходимости можно удалить рабочую ветку homepage, которую мы использовали под разработку определенного функционала приложения и сделать squash merge.
Слияние (merge) изменений в master ветку автоматически инициирует CI/CD процесс сборки, тестирования и развертывания нашего приложения в Azure Container Service. Перейдя в раздел Build&Release, можно отслеживать процесс выполнения сборки и развертывания.
После завершения CI/CD процессов, открываем любимый браузер и наслаждаемся изменениями в приложении.
Часто задаваемые вопросы
- У меня CI процесс построен в Jenkins, зачем мне VSTS? Jenkins и VSTS хорошо интегрируются и дополняют друг друга. Например, вы можете продолжать использовать Jenkins Server для CI сборок (on-premise или в облаках), а для CD процессов использовать VSTS. Более того, у вас может быть сложный CI процесс, где сборка в Jenkins представляет собой лишь часть определения сборки в VSTS. Интеграция Jenkins с VSTS осуществляется при помощи специального Team Foundation Server Plugin модуля.
- А что с нагрузочным тестированием? Могу ли я использовать JMeter в VSTS? Да, Apache JMeter доступен уже «из коробки» в VSTS. Как его использовать можно посмотреть в документации.
- Могу ли я написать собственное расширение для VSTS? Да, можете, доступен специальный SDK для разработчиков. Подробную информацию можно посмотреть здесь: Write your first extension for Visual Studio Team Services.
- Где найти дополнительные материалы и примеры про Java-разработку в VSTS? Для Java-разработчиков существует отдельный портал с информацией, примерами, tutorials, на тему использования VSTS в Java разработке: http://java.visualstudio.com/. Ну и конечно доступна официальная документация по VSTS.
Заключение
В данной статье был рассмотрен лишь простой пример использования VSTS в Java DevOps и некоторые аспекты не были рассмотрены детально, например, интеграция с инструментами покрытия кода (JaCoCo, Cobertura) и статического анализа кода (SonarQube, PMD, CheckStyle и так далее). Как я отмечал в начале статьи, самое большое преимущество VSTS платформы для разработчиков – это ее гибкость, универсальность, расширяемость и простота и тут девиз «Any Developer, Any Language, Any Platform» полностью себя оправдывает!
Автор: Microsoft