(java || kotlin) && devOps
374 subscribers
6 photos
1 video
7 files
317 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Заметка из серии "хозяйке на заметку" про Docker.
При сборке docker образа мы можем передать в команду docker build контекст сборки.
Как правило во всех примерах это последний аргумент в виде точки. Т.е. текущего каталога.
Что это такое?
Это каталог в хостовой системе, из которого можно копировать данные в образ командами COPY в Dockerfile. Да, Dockerfile тоже должен лежать в контексте
Как его можно задать при сборке:
1) указав каталог
2) указав архив с нужными файлами
3) указав git репозиторий (!)
4) указать только Dockerfile как контекст, если копировать в образ ничего не надо
5) указать только Dockerfile как контекст, и с помощью команд RUN wget или RUN curl в нем выкачать данные для образа по http

Что важно - docker client при запуске сборки упаковывает все содержимое контекста и оправляет его docker daemon. Т.е. указывать корневую папку точно не стоит) Лучше создать новую папку и положить туда только необходимое. Альтернатива - использовать файл .dockerignore
Детали - https://docs.docker.com/engine/reference/commandline/build/

P.S Оффтопик - похоже создатели Docker вдохновлялись git-ом. docker push\pull\commit И упомянутый выше .dockerignore

#docker
March 19, 2023
Всем привет!

При создании образа Docker нужно выбрать базовый образ - образ содержащий минимальный набор необходимых CLI утилит, сервисов, конфигураций и фреймворков необходимых для того, чтобы заработало ваше приложение. Какой минимальный размер этого образа?
Ответ - нулевой.
Есть специальное зафиксированное имя scratch - в DockerFile будет выглядеть как:
FROM scratch
https://docs.docker.com/build/building/base-images/#create-a-simple-parent-image-using-scratch
Но сразу скажу - там не будет даже shell - sh, bash. Вообще ничего.
Все необходимые утилиты нужно будет добавлять руками в процессе сборки образа.
Путь для сильных духом) Или случай каких-то очень специфичных образов.

Что же должно быть в образе для Java приложения:
1) JRE и все необходимое для того, чтобы она запустилась)
Далее все зависит от необходимости в отладке внутри образа. По моему опыту она нужна, а значит нужны:
2) Linux shell
3) CLI утилиты для работы с файловой системой
4) curl\wget - для проверки маршрутизации в k8s
5) CLI редактор - vi, nano - для правки конфигов "на ходу"
6) возможно ssh сервер
7) возможно утилиты из состава JDK

Минималистичные образы можно поискать по словам busybox и alpine.
Размер - до 5 Мб(!) Само собой они без Java. Но есть основанные на них образы с Java размером порядка 55 Мб с JRE (Linux Temurin Java 11). Для сравнения обычные образы c JRE - 85-150 Мб. С JDK размер можно умножать на 3.
Что важно - в Linux куча настроек, поэтому важно выбрать проверенный и оптимизированный для работы с Java базовый образ.

P.S. Точно не стоит использовать образы с полноценным Linux - Debian, Ubuntu... Размер будет порядка 500+ Мб, а пользы - ноль.

P.P.S. Еще нужно помнить, что активное использование Spring Framework легко добавляет в размер образа ~ 100 Мб)

#docker
March 27, 2023
Всем привет!

Когда-то давно - год назад - у меня была заметка, чем хорош k8s: https://t.me/javaKotlinDevOps/6
Там был упомянут Docker, пришло время подробнее раскрыть, что же дают нам контейнеры. Вообще говоря контейнеры и Docker не одно и тоже, но в данном случае различием можно пренебречь.

1) идентичное окружение на dev, test и prod. Да, JRE уже дает нам уровень абстракции от ОС и железа, и это большой плюс в плане запуска Java в разных ОС. Но есть проблемы:
а) разные версии JDK
б) разные сервера приложений\контейнеры сервлетов
в) разный classpath, часто как следствие предыдущего пункта
г) разные переменные среды
д) разное состояние файловой системы
Все это можно решить, но часто решение дорогое - сложные CD pipeline, долгое время деплоя, сложность поднятия prod-like среды на машине разработчика.
C Docker-ом мы получаем immutable infrastructure - набор ПО, настроек и состояние файловой системы зафиксированы на dev и остаются неизменными дальше.

2) легковесная изоляция сервисов. Контейнеризация обеспечивает изоляцию файловой системы, процессов, сетевых интерфейсов и резервирование ресурсов для каждого запущенного на сервере контейнера. Используются механизмы ядра Linux, подробнее см. https://habr.com/ru/articles/659049/
Ключевой момент тут - легковесная, т.к. технологии изоляции в виде виртуальных машин известны давно. Но виртуальная машина эмулирует железо, что сложно, см. стоимость лицензии VMware, к тому же приводит к достаточно высоким накладным расходам по CPU, памяти и диску. Плюс поверх виртуалки нужна гостевая операционная система, а значит запуск виртуалки - это долго.

3) легкость установки. Т.к в Docker сейчас упаковывается почти все (https://hub.docker.com/search, нужна регистрация), то появляется возможность быстро и без ущерба для компьютера разработчика развернуть необходимое серверное ПО - СУБД, Kafka, кэши, мониторинг... А если данные сервисы нужны для тестов - на помощь приходит Testсontainers https://java.testcontainers.org/ Все это работает на Linux, MacOS и Windows, например, с помощью Docker Desktop https://www.docker.com/products/docker-desktop/ Может возникнуть вопрос - откуда на Windows появились механизмы ядра Linux? Ответ: благодаря технологии WSL - https://learn.microsoft.com/ru-ru/windows/wsl/.
Аналогично на серверах - установка образа проще и стабильнее установки классического серверного ПО.

Если говорить именно о Docker - то в общем то это все, остальные преимущества раскрываются в связке с k8s и Service Mesh.

#docker #k8s
June 26, 2023
Всем привет!

Формат yaml все больше входит в нашу жизнь, самые очевидные примеры - k8s, Docker Compose и Ansible.
Его главным преимуществом я считаю ссылки - соблюдается принцип DRY.
Главным недостатком - зависимость от числа tab\пробелов как в Python.

А чтобы не дать лишнему пробелу все сломать - нужна валидация.

Для начала - валидация синтаксиса https://yamllint.readthedocs.io/en/stable/index.html
Хотя в списке ОС для скачивания нет Windows - он ставится на Win с помощью python + pip.
Также есть плагин для IDEA https://plugins.jetbrains.com/plugin/15349-yamllint

Да, подсветка синтаксиса хотя и не заменяет валидацию, но тоже полезна - IDEA, Notepad++ и Atom поддерживают его из коробки.

Далее можно прикрутить валидацию, специфичную для конкретной области применения.
Для k8s есть утилиты kubeval, kube-score и Polaris см. https://habr.com/ru/companies/flant/articles/511018/
Они проверяют манифесты на соответствие best practices.
В docker-compose валидация вызывается с помощью команды https://docs.docker.com/engine/reference/commandline/compose_config/
Для Ansible - базовые проверки встроены в Ansible, также есть ansible-lint, детали см. https://www.deploymastery.com/2023/03/31/how-to-verify-ansible-playbook-syntax/

Альтернатива - написать нужные проверки самому. Тут есть 4 библиотеки из уже приведенной выше статьи:
config-lint, copper, conftest, Polaris
https://habr.com/ru/companies/flant/articles/511018/ Основное различие - в языке, на котором будет ваш код проверки. Есть и декларативный yaml, есть и императивный JS.

#yaml #k8s #ansible #docker-compose #validation
November 7, 2023
8) каждый образ можно пометить тэгом, например, с версией. Но есть нюанс - образ с конкретным тэгом можно перезаписать. Причем это не вопрос прав доступа, а фича Docker. И это несекьюрно. Поэтому нужно использовать хэш образа вместо тэга. Он не задается при сборке, а высчитывается реестром и меняется при изменении содержимого образа. Более продвинутая защита - подпись образа его создателем, для этого есть ряд утилит https://dev.to/snyk/signing-container-images-comparing-sigstore-notary-and-docker-content-trust-1bfm

#docker #security
December 12, 2023
January 9, 2024
Есть еще ряд интересных моментов. Я расскажу про них на примере Spring Boot native image.

Для борьбы с тем, что часть кода недостижима если идти от точки входа (метод main), есть два инструмента.
1) специальный tracing агент, который можно подключить к приложению, и он будет в runtime логировать такие скрытые вызовы. https://www.graalvm.org/22.3/reference-manual/native-image/metadata/AutomaticMetadataCollection/
2) далее можно создать т.наз. hints - подсказки AOT компилятору, что включить в native image, из того, что он не нашел сам - https://www.graalvm.org/latest/reference-manual/native-image/metadata/ Собственно, большая доля в адаптации фреймворка типа Spring для native image - подготовка таких hints, https://docs.spring.io/spring-boot/docs/3.2.1/reference/html/native-image.html

А что делать если в момент сборки еще не ясно - нужен native image или нет? Или нужны обе версии? Нет проблем - можно совместить оба режима JIT и AOT и создать артефакт, Spring Boot Executable Jar, с байткодом и всеми необходимыми для native image метаданными. И собрать из него native image позже в DevOps pipeline при необходимости.

Для Spring Boot есть два режима сборки. Основной - Native Image Using Buildpacks, в котором в итоге получается docker образ. Для него нужен только Docker на машине-сборщике. И т.наз. Native Build Tools - нужно устанавливать дистрибутив GraalVM, содержащий эти tools, в итоге получается бинарник для железа, на котором происходит сборка.

Итого - штука полезная, но только если вас категорически не устраивает время запуска приложения и все используемые вами фреймворки поддерживают native image.

#jvm #performance #native_image #spring #docker #buildpacks #cloud #startup_time
January 9, 2024
Всем привет!

Как можно собрать Docker образ?
Есть плагины для Maven\Gradle, позволяющие использовать всю мощь соответствующих инструментов при сборке.
А есть собственно Docker и команда docker build, собирающая образ на основании Dockerfile. Ну и еще Docker Compose, позволяющий описать, собрать и запустить группу образов, полезный при локальной разработки или если нет k8s.

До какого-то момента возможности Docker по кастомизации процесса сборки были скажем так базовыми.
Но как вы уже догадываетесь - все поменялось.
Появился Docker Bake. Вот хорошая статья на Хабре https://habr.com/ru/articles/886938/

Команда для сборки: docker buildx bake
buildx - это расширенный вариант build, позволяющий выбрать движок для сборки образа.
В последние версии Docker функционал Bake включен по умолчанию.

Основные плюсы с примерами конфигураций:

1) функции

function "tag" {
params = [name, tag]
result = ["${name}:${tag}"]
}

2) группировка образов для сборки одной командой

group "default" {
targets = ["frontend", "api"]
}

target "frontend" {
...
target "api" {


2) наследование конфигурации

target "app-base" {
dockerfile = "Dockerfile"
args = {
BASE_IMAGE = "node:16-alpine"
}
}

target "app-dev" {
inherits = ["app-base"]
...
}

3) кросс-платформенная сборка

target "app-all" {
platforms = ["linux/amd64", "linux/arm64"]
}

4) профили сборки

variable "ENV" {
default = "dev"
}

group "default" {
targets = ["app-${ENV}"]
}

target "app-dev" {
...

target "app-stage" {
..

target "app-prod" {
...

и сборка командой

ENV=prod docker buildx bake

5) матричная сборка - сборка всех возможных комбинаций, указанных в матрице

target "app" {
matrix = {
platform = ["linux/amd64", "linux/arm64"]
version = ["1.0", "2.0"]
}

6) встроенное распараллеливание сборки

7) чтение переменных из файла

// Импорт переменных из JSON-файла
variable "settings" {
default = {}
}

target "app" {
dockerfile = "Dockerfile"
args = {
CONFIG = "${settings.app_config}"
}
}

Ну и главное - декларативность описания процесса сборки, описываем результат, а не действия. За исключением пользовательских функций, конечно)

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

P.S. Docker Compose заменяет только в части сборки. И может с ним интегрироваться.

#docker #gradle #maven
March 19