(java || kotlin) && devOps
369 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем доброго вечера. Возвращаясь к теме k8s - может возникнуть вопрос: как его можно запустить на машине разработчика? Покрутить, поиграться с конфигами. Все-таки кластер, nodes, БД для хранения конфигурации, контроллеры, ingress proxy, администратор в придачу - выглядит страшно) Но есть альтернативы.
1) minikube. Упомянут в официальной документации k8s - https://kubernetes.io/docs/tutorials/hello-minikube/ Давно развивается. Поддерживает Win, Mac, Lin. Позволяет запустить k8s внутри VM, Docker образа или даже на голой операционке через механизм драйверов https://minikube.sigs.k8s.io/docs/drivers/ Последние два варианта запуска, увы, доступны только на Linux. Скорость запуска и требования к ресурсам при этом меняются от медленно и много к быстро и мало) Позволяет выбрать Docker или Podman. Позволяет подключать частные Docker репозитории или создать локальный. По умолчанию, как впрочем и все его соперники, стартует в режиме одной node, на которой расположены как служебные модули k8s, так и ваш код. Но можно и добавить node, и создать несколько кластеров. Есть web dashboard. kubectl - утилиту по управлению кластером через CLI API и VM гипервизор нужно ставить отдельно, но есть хорошая инструкция.
Подробнее https://minikube.sigs.k8s.io/docs/start/
2) kind. Работает поверх Docker Desktop, т.е. внутри Docker контейнера. Поддерживает Win, Mac, Lin. В случае Win есть возможность запуска без VM через WSL - https://docs.docker.com/desktop/windows/wsl/. Можно выбрать Docker образ с разными версиями k8s. Запускается достаточно быстро, хорошо совместим с CI системами. Позволяет настраивать частные и локальный Docker Registry, мультикластерную систему. kubectl и Docker Desktop нужно ставить отдельно.
https://kind.sigs.k8s.io/docs/user/quick-start/
3) Docker Desktop. Как ни странно включает в себя урезанный вариант k8s. Включается в админке Docker Desktop. Не кастомизируется. Все в одном - включает kubectl, не нужно ставить отдельно гипервизор. Хорош для начального знакомства.
https://docs.docker.com/desktop/kubernetes/
4) k3s. Интересно происхождение названия - если в слове k8s\kubernetes 10 символов, то k3s - 5, т.к. по задумке он должен потреблять в 2 раза меньше ресурсов. Запускается внутри Docker контейнера. Заточен под запуск на слабых машинах, в том числе ARM. Состоит из одного бинарника, из которого выкинуто все лишнее. Заточен под Lin, но вроде бы появилась поддержка Win. Но не Mac. Самый быстрый и легковесный. Хорошо совместим с CI системами. Позволяет подключать частные репозитории Docker образов. Для хранения конфигурации кластера по умолчанию использует SQLite, но через адаптер позволяет подключить внешнюю СУБД. Подчеркивает, что по умолчанию безопасно настроен. Позиционируется как production ready. Может запускаться как в режиме одной ноды, так и с несколькими, а также в режиме мультикластера.
https://k3s.io/ #cloud #ci
Всем привет!
На данный момент для сборки Java/Kotlin проектов используются два основных инструмента: Maven и Gradle. Можно вспомнить Ant, сказать: «Покойся с миром» - и забыть) Их можно сравнивать по разным параметрам, но сегодня я хочу остановиться на инкрементальной сборке. Может возникнуть вопрос - что тут сравнивать, в Maven ее нет, в Gradle - есть. Но не все так очевидно) На самом деле в maven-compile-plugin такая опция заявлена https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html и даже включена по умолчанию. Но фактически не работает( Почему?
Для начала стоит разделить понятия сборки в целом и компиляции как одну из частей сборки. В Maven жизненный цикл сборки - это линейная последовательность фаз сборки, запуск каждой из которых не зависит от результата предыдущих фаз. В Gradle цикл - граф из task, а у каждой таски есть inputs и outputs, являющиеся файлами на диске. Т.к результат сборки в конечном итоге - файлы. Выходы одной таски являются входами другой. Если входы не изменились - таска пропускается. Причём проверка идёт по контрольной сумме, не по дате изменения. Т.об. если не менялся боевой код и код его теста, то тест не будет запущен повторно. В Maven этого нет в принципе.
По-разному работает и собственно компиляция. Если maven видит изменения в любом классе модуля или в модуле, от которого зависит текущий - идёт полная перекомпиляция модуля. И далее по цепочке( Gradle же во-первых умеет отслеживать зависимости по классам, а во-вторых проверять изменился ли интерфейс, application binary interface, ABI если быть точным, или только реализация, и в зависимости от этого перекомпилировать только нужные файлы. Кроме того в Gradle с появлением Java Library plugin появилась возможность разделять compile зависимости на api и implementation. Любые изменения в implementation зависимости не приводят к повторной компиляции использующих ее модулей.
Вывод: ребята из Gradle сильно заморочились скоростью сборки. Результаты можно увидеть тут: https://blog.gradle.org/incremental-compiler-avoidance. А ведь ещё есть Gradle Cache, от котором расскажу отдельно.
P.S. для Maven есть сторонний плагин, заменяющий 5 стандартных и предоставляющий настоящую инкрементальную сборку http://takari.io/book/40-lifecycle.html Честно скажу, не тестировал, смущает, что решение внешнее #buildtool #java #ci
Может возникнуть вопрос - что такое groovy.lang.Script? По сути это аналог Object для Groovy скриптов. Да, в Groovy код может быть не только в классах, но и в скриптах https://docs.groovy-lang.org/latest/html/documentation/#_scripts_versus_classes

5) В API своих классов не используем def, всегда объявляем типы явно.
def - это как var в Java, но опаснее, т.к в отличие от Java его можно использовать везде вместо указания типа. Как по мне - использовать def можно только для локальных переменных, т.е по сути я за подход Java.

6) кроме подсветки синтаксиса рекомендую периодически вызывать Inspect Code в IDEA, а лучше повесить его на commit. Не все проверки по умолчанию актуальны для Jenkins pipeline кода, лишние можно отключить.

7) ну и возвращаясь к тестам - по максимуму покрываем код в src тестами. Можно использовать JUnit и Mockito. Тесты при этом пишем на Groovy, чтобы воспользоваться преимуществом компактного синтаксиса Groovy.

to be continued

#devops #ci #unittests #jenkins #groovy
Продолжим про тестирование кода джобов Jenkins.

Что еще у нас есть для тестирования.

8) JenkinsPipelineUnit - https://github.com/jenkinsci/JenkinsPipelineUnit По сути набор моков для запуска кода pipeline.
Что может:
а) запуск пайплайн из файла и из строки
б) передача параметров и переменных среды
в) проверка статуса выполнения джобы
г) моки для ряда методов pipeline
д) загрузка shared library
е) возможность добавлять свои моки на команды pipeline или конкретные вызовы sh
ж) печать стектрейса выполнения pipeline
з) сравнение стректрейсов, поиск по вхождению - можно искать были ли выполнена та или иная команда

Из мелких косяков - требует наследования тестового класса от BasePipelineTest, что вышло из моды с появлением Unit 4)))
Из более крупных косяков - по умолчанию многие команды Jenkins DSL не замоканы, при появлении такой команды джоба падает.
То что падает - это правильно, мы же тестируем pipeline. Но часто приходится писать свои mock, примеры: readYaml, readProperties, findFiles.
Mock по умолчанию - ничего не делать. echo выводит данные в лог на машине разработчика.
Могу рекомендовать с ремаркой - моки придется дописывать.

9) Jenkins Test Harness - https://www.jenkins.io/doc/developer/testing/,
Это интеграционное тестирование pipeline. В документации фреймворк предлагается для тех, кто разрабатывает Jenkins или плагины для него.
Можно ли использовать для тестирования своего pipeline и shared libraries - вопрос, дам на него ответ позже.
Коммиты в репозитории есть с 2016 года, но в документации по ссылке выше до сих пор встречаются TODO.
Подключение к тестам в примерах происходит через Rule из JUnit 4 - что тоже намекает.
Что он может:
а) б) в) из списка выше
г) мок для загрузки из SCM
д) проверка записей в логе - как я понял, это в большинстве случаев будет заменой Assert
е) загрузка файлов из среды разработки в workspace
Пока рекомендовать не могу, буду исследовать.

10) com.mkobit.jenkins.pipelines.shared-library - https://github.com/mkobit/jenkins-pipeline-shared-libraries-gradle-plugin,
Это плагин Gradle для разработки shared libraries. Включает в себя два предыдущих фреймворка. Есть тестовый репо https://github.com/mkobit/jenkins-pipeline-shared-library-example, если взять его как основу для своего проекта - получите из коробки подключение ряда библиотек Jenkins для declarative pipeline, некую версию gdsl и готовый проект, который содержит модульные и интеграционные тесты и проходит build.
Выглядит интересно для начала разработки, я к сожалению в свое время его упустил, по сути сделав аналогичный каркас)
Причем для разработки scripted pipeline мой каркас подходит лучше)
Пока рекомендовать не могу, учитывая комментарии выше.

11) любые тесты не на 100% заменяют запуск с реальными интеграциями. Как организовать интеграционное и функциональное тестирование pipeline, что для этого нужно?
а) создаем или копируем тестовый Java проект, который будем собирать. Ключевое требование - небольшой размер кода, чтобы сборка была быстрой и максимальное использование фичей pipeline. Использование настоящих проектов - плохо, т.к. создаются левые tags, build statuses, что может вводить разработчиков в заблуждение
б) тестовые джобы на Jenkins для всех созданных вами pipeline. Можно даже создать джобу, запускающую в параллель все эти джобы
в) тестовый проект SonarQube
г) тестовые репозитории в Nexus\Artifactory
д) тестовый проект на вашем Git сервере если джобы что-то делают в Git
е) важно: описываем в документации чек-лист - что и когда нужно тестировать при внесении изменений в pipeline
ж) придеживаемся описанных нами правил, это важно)

#devops #ci #unittests #jenkins #groovy
Всем привет!

Возвращаясь к вопросу отладки пайплайнов Jenkins. Я уже писал о проблеме CPS - https://t.me/javaKotlinDevOps/42
Если вкратце - весь исполняемый на Jenkins код делится на 2 вида, код А может вызывать А и Б, а код Б - только Б.
И на тестах ошибки вызова не ловятся.
Так вот - это все полбеды. Jenkins не следует очень важному принципу fail fast и часто при ошибке вызова CPS пишет warning в лог, но не фейлит джоб. Т.е. по сути не вызван какой-то метод Х из пайплайна, но джоба идет дальше. К каким последствиям это может привести - можно пофантазировать) Но что очевидно: найти корни такой проблемы сложно.
Мораль: не делайте как Jenkins)

#ci #jenkins #groovy_dsl