Java for Beginner
743 subscribers
708 photos
196 videos
12 files
1.14K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Docker

Контейнеры, образы и сборка


Что такое контейнер и как он работает

Контейнер — это легковесный способ упаковки и запуска приложения вместе с его зависимостями в изолированной среде. Представьте контейнер как отдельную "комнату" в операционной системе, где ваше приложение живет само по себе, не мешая другим. В отличие от традиционных программ, которые запускаются напрямую на хост-машине (компьютере, где все работает), контейнер использует механизмы операционной системы для создания иллюзии полной изоляции.

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

Пространства имен — это способ разделить системные ресурсы так, чтобы процессы внутри контейнера видели только свою часть системы. Например, пространство имен для процессов (PID namespace) делает так, что процессы в контейнере имеют свои собственные идентификаторы, начиная с 1, как будто они в отдельной системе. Пространство имен для сети изолирует сетевые интерфейсы, так что контейнер может иметь свой IP-адрес. Есть также пространства для пользователей, файловой системы и других. В памяти это значит, что процессы контейнера не видят процессы хоста напрямую — они работают в своем "пузыре", но делят одно ядро операционной системы. Это экономит ресурсы: нет overhead от полной виртуализации.

Группы контроля ресурсов (cgroups) — это механизм ограничения ресурсов, таких как процессор, память и диск. Например, вы можете сказать: "Этот контейнер может использовать не больше 512 МБ памяти". В памяти это работает через ядро, которое отслеживает использование и при превышении может убить процессы (OOM killer). Cgroups также помогают в изоляции ввода-вывода, чтобы один контейнер не "загружал" диск для всех.

Когда вы запускаете контейнер,
Docker создает новый процесс (или группу процессов) с этими изоляциями. В памяти хоста процессы контейнера выглядят как обычные, но с метками для изоляции. Это делает контейнеры быстрыми: запуск занимает секунды, в отличие от виртуальных машин.


Отличие контейнера от виртуальной машины

Виртуальная машина (VM) — это полная эмуляция отдельного компьютера с собственным ядром операционной системы, процессором и памятью. Она использует гипервизор (программу вроде VirtualBox или VMware), который эмулирует аппаратное обеспечение. В памяти хоста VM занимает отдельный блок: ее процессы работают в изолированном пространстве с overhead от эмуляции (до 10-20% потерь производительности).

Контейнер, напротив, делит ядро хоста. Нет эмуляции аппаратного уровня — все процессы используют одно ядро. Это делает контейнеры легче: образ (шаблон для контейнера) может быть в разы меньше (сотни МБ vs гигабайты для VM), запуск быстрее, и overhead минимален (1-5%). Но есть минус: контейнеры менее безопасны, если есть уязвимость в ядре, она может затронуть все. Для Java это значит, что ваше приложение в контейнере запускается на той же JVM (виртуальной машине Java), что и на хосте, но с изоляцией зависимостей, что упрощает развертывание.



#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍6🔥1
OCI-спецификации: образы, манифесты и слои

Open Container Initiative (OCI) — это стандарт, который определяет, как должны выглядеть контейнерные образы и runtime (среда выполнения). Docker следует этим спецификациям, чтобы образы были совместимы с другими инструментами, вроде Podman или containerd.

Образ — это шаблон для контейнера, как архив с файлами, конфигурацией и инструкциями. Он состоит из слоев (layers) — последовательных изменений файловой системы. Каждый слой — это blob (бинарный объект), хранящий дельту (изменения) от предыдущего.

Манифест — это JSON-файл, описывающий образ: платформу (архитектуру процессора), слои, конфигурацию (команда запуска, порты). Для multi-platform образов (для разных CPU, как AMD64 и ARM) есть index-манифест, указывающий на подманифесты.

Content-addressable storage
— хранение по хэшу содержимого. Каждый слой имеет уникальный хэш (SHA256), так что если слой не изменился, он не перезагружается. Это влияет на кэш: при сборке
Docker проверяет хэш и использует кэш, если ничего не поменялось. "Тонкие" образы (thin images) — это когда слои минимальны, без лишних файлов, что экономит место в памяти и на диске. В памяти при запуске слои монтируются как union-файловая система (overlayfs): верхние слои перекрывают нижние, но в RAM загружается только то, что нужно.

Это позволяет эффективно хранить образы: общие слои (например, базовый Ubuntu) делятся между образами, снижая использование диска.


Регистры образов: Docker Hub, теги и управление

Регистр — это хранилище для образов, как репозиторий для кода. Docker Hub — публичный регистр, где хранятся официальные образы (например, openjdk). Можно использовать частные, вроде в AWS ECR или self-hosted.

Теги — это метки для версий образа, как "latest" или "21-jre". Образы иммутабельны (неизменяемы): после загрузки в регистр их нельзя изменить, только перезаписать тег. Это обеспечивает воспроизводимость: тег "1.0" всегда тот же.

Удаление и сборка мусора (GC): Когда вы удаляете тег, слой не удаляется сразу, если он используется другими тегами. GC (garbage collection) — процесс, который чистит неиспользуемые слои. В Docker Hub это автоматически, но в частных регистрах нужно настраивать. Нюанс: dangling images (висячие, без тегов) накапливаются и жрут место; используйте "docker image prune" для очистки.

Для Java полезно: официальные образы вроде eclipse-temurin:21-jre хранятся в Docker Hub, и теги помогают управлять версиями JVM.


Dockerfile: декларативный подход и подводные камни

Dockerfile — это текстовый файл с инструкциями для сборки образа. Он декларативный: вы описываете, что нужно, а Docker строит слои последовательно.

Ключевые инструкции:
FROM: базовый образ, например, FROM eclipse-temurin:21-jre.
RUN: выполняет команду, создает слой (например, RUN apt-get install ...).
COPY/ADD: копирует файлы в образ.
CMD/ENTRYPOINT: команда запуска.


Подводные камни:
Порядок инструкций: Docker кэширует слои по порядку. Если часто меняющийся RUN в начале, весь кэш сломается. Ставьте стабильные инструкции первыми.
Кэш: Каждый слой кэшируется по хэшу. Если файл в COPY изменился, слои ниже инвалидируются.
Слои: Много RUN создают много слоев — объединяйте в один RUN с && для минимизации. В памяти это значит меньше overhead при монтировании.


Для Java: избегайте установки лишнего в RUN, чтобы образ был маленьким.



#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍6
Современная сборка образов: BuildKit и Buildx как стандарт

BuildKit — это новый движок сборки, который с 2023 года используется по умолчанию в Docker. В отличие от старого билдера, который обрабатывал инструкции последовательно, BuildKit анализирует весь Dockerfile как граф зависимостей. Это значит, что он может выполнять независимые инструкции параллельно. Например, если у вас несколько RUN, которые не зависят друг от друга, BuildKit запустит их одновременно на разных ядрах процессора. На уровне системы это снижает время сборки: вместо линейного ожидания, вы получаете параллельное использование ресурсов, что в памяти хоста проявляется как более эффективное распределение CPU и RAM во время билда.

Одна из ключевых фишек BuildKit — улучшенный кэш. В классическом подходе кэш хранится локально и может сломаться при изменении инструкций. BuildKit вводит inline-кэш: вы можете экспортировать кэш прямо в образ или в регистр. При следующей сборке Docker pulls (загружает) этот кэш, что ускоряет процесс в CI/CD-пайплайнах (системах непрерывной интеграции и доставки). Например, если вы собираете образ в GitHub Actions, inline-кэш позволяет избежать полной перестройки каждый раз.

Еще нюанс — обработка секретов. В старом билдере пароли или API-ключи могли попасть в слои образа, что небезопасно. BuildKit позволяет передавать секреты через --secret флаг: они монтируются временно в память во время RUN, но не сохраняются в финальном образе. В памяти это работает как tmpfs (временная файловая система в RAM), так что секреты не пишутся на диск и не остаются в истории.

Buildx — это расширение BuildKit для сборки мультиплатформенных образов. Оно позволяет создавать один образ, который работает на разных архитектурах процессоров, таких как x86 (AMD64) и ARM (для Raspberry Pi или облачных инстансов). Под капотом Buildx использует эмуляцию через QEMU: для каждой платформы он запускает виртуальный билдер, собирает слой, и объединяет в манифест. Это влияет на память: эмуляция может потреблять больше RAM, но результат — универсальный образ, который
Docker сам выбирает под хост.

Для Java это критично: JVM (виртуальная машина Java) имеет версии для разных платформ, и Buildx обеспечивает, что ваш образ с Java 21 будет работать везде без перестройки. Подводный камень: эмуляция медленнее нативной сборки, так что для больших проектов используйте удаленные билдеры в облаке.


Docker Compose версии 2: оркестрация для локальной разработки и CI

Оркестрация — способ запуска нескольких контейнеров как единой системы. Docker Compose v2 — это инструмент, который стал дефолтным для этого. Он позволяет описать весь стек приложений в одном YAML-файле, включая сервисы, сети и volumes (тома для хранения данных).

Compose работает как надстройка над Docker: он парсит файл docker-compose.yml и вызывает docker run для каждого сервиса. В памяти хоста это значит создание сети по умолчанию (bridge), где контейнеры общаются по именам, и volumes, которые монтируются как bind-mounts (привязки к хост-файлам) или named volumes (управляемые Docker).
Для локальной разработки
Compose идеален: команда docker compose up запускает все сервисы, и вы можете отлаживать Java-приложение с базой данных, например, PostgreSQL. В CI, таком как Jenkins или GitLab CI, Compose используется для тестов: он поднимает окружение, запускает тесты и сносит все после.

Нюансы: Compose v2 быстрее v1 благодаря Go-реализации (вместо Python), и лучше интегрируется с Docker Desktop. Подводный камень — зависимости: если сервис A зависит от B, укажите depends_on, но это не гарантирует готовность (например, база данных может стартовать медленно). Для Java используйте healthchecks: в compose-файле добавьте проверку, чтобы приложение ждало базу.
Еще фишка — профили: вы можете группировать сервисы для разных сред (dev, test), чтобы не запускать все сразу.



#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍5
Примеры кода

Минимальный Dockerfile для Java 21 с использованием BuildKit

text# syntax=docker/dockerfile:1  # Включает расширения BuildKit
FROM eclipse-temurin:21-jre
WORKDIR /app # Рабочая директория внутри контейнера
COPY target/myapp.jar /app/myapp.jar # Копируем скомпилированный JAR
ENTRYPOINT ["java", "-jar", "/app/myapp.jar"] # Команда запуска


Чтобы собрать с BuildKit-фичами:
docker buildx build -t myapp:latest --cache-to=type=inline . 


Inline-кэш сохранит промежуточные результаты в образе.

Если добавить
--secret id=mysecret,source=/path/to/secret

то в RUN можно использовать $mysecret без записи в слой.



Мультиархитектурная сборка с Buildx

Buildx — стандарт для создания образов под несколько платформ.

Сначала создайте билдер:
docker buildx create --name mybuilder --use. 


Затем соберите:
docker buildx build --platform linux/amd64,linux/arm64 -t repo/myapp:latest --push .


Это создаст манифест, где Docker выберет нужный вариант. В памяти во время сборки эмуляция ARM на x86 может занять до 2x больше RAM, но результат — универсальность.


#Java #middle #Docker #DockerFile #Docker_compose #Buildx
👍3