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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Оптимизация образов: безопасность и размер

jlink: минимальная JVM под конкретное приложение

Инструмент JDK для создания настраиваемой JVM, включающей только необходимые модули (например, java.base, java.logging).

Как это работает
:

1. Анализ зависимостей через jdeps:
jdeps --print-module-deps target/myapp.jar
Вывод: java.base,java.logging,java.xml.


2. Сборка минимальной JVM:
   RUN jlink \
--add-modules java.base,java.logging,java.xml \
--output /jlinked \
--strip-debug \ — удаление отладочной информации.
--compress 2 \ — максимальное сжатие (уменьшает размер на 30%).
--no-header-files \
--no-man-pages

Результат:
- Стандартный образ OpenJDK 17 — 450 МБ.
- Образ с jlink — 120 МБ.


Нюансы:
- Некоторые библиотеки (например, Hibernate) требуют модуля jdk.unsupported.
- Проверяйте совместимость через --dry-run.



Distroless runtime образы (Google)

Образы без операционной системы, содержащие только JVM и ваше приложение. Созданы Google для минимизации attack surface.

Пример:
FROM gcr.io/distroless/java17-debian11
COPY --from=builder /app/target/myapp.jar /app.jar
ENTRYPOINT ["/app.jar"]


Как это работает:
- Distroless использует scratch (пустой образ) и добавляет только:
- Мусоросборщик (glibc или musl)
- Базовые сертификаты SSL,
- Минимальный набор библиотек для JVM
- Нет shell (/bin/sh), поэтому docker exec -it bash невозможен.


Преимущества:
- Размер образа — 80 МБ против 450 МБ у OpenJDK.
- Нулевой attack surface: нет curl, bash, apt для эксплуатации.


Отладка:
- Для диагностики используйте sidecar-контейнеры с curl или netcat.
- Логи читайте через docker logs, метрики — через /actuator/prometheus.



Non-root user: запуск Java-приложений безопасно

Запуск процесса Java не от root, чтобы ограничить ущерб при компрометации контейнера.

Как это работает:
# Создаем пользователя с UID 1001
RUN adduser --uid 1001 --disabled-password --gecos "" appuser
USER 1001
COPY --chown=1001:1001 target/myapp.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

Нюансы безопасности:
- UID/GID:
- Используйте фиксированный UID (1001), чтобы избежать конфликтов с томами.
- Если том смонтирован с правами root, пользователь 1001 не сможет писать в него.

- Capabilities:
- По умолчанию контейнер получает capabilities NET_BIND_SERVICE (привязка к портам < 1024).
- Для запуска на порту 80:

    # docker-compose.yml
app:
cap_add:
- NET_BIND_SERVICE


Критическая ошибка
:
- Если приложение требует записи в /tmp, убедитесь, что директория доступна для записи:
  RUN mkdir /app/tmp && chown 1001:1001 /app/tmp
ENV JAVA_OPTS="-Djava.io.tmpdir=/app/tmp"


#Java #middle #Docker #Debug
👍3
Минимизация attack surface (удаление ненужных слоёв)

Техники:
1. Многоступенчатая сборка (multi-stage build):
   # Stage 1: Сборка
FROM maven:3.8.6 AS builder
COPY . .
RUN mvn package

# Stage 2: Финальный образ
FROM openjdk:17-jre-slim
COPY --from=builder target/myapp.jar /app.jar

Промежуточные слои (Maven, исходники) не попадают в финальный образ.

2. Очистка кэша в том же слое:
   RUN apt-get update && \
apt-get install -y curl && \
rm -rf /var/lib/apt/lists/*

- Если очистка в отдельном слое, размер образа не уменьшится (слой сохранится в истории).

3. Удаление ненужных файлов:
   RUN rm -rf $JAVA_HOME/jmods/java.corba.jmod

- Некоторые модули (CORBA, RMI) не используются в современных приложениях.


Performance tuning: настройка под контейнеры

CPU/Memory ограничения (--cpus, --memory)
Как это работает:
- Docker использует cgroups v2 для ограничения ресурсов:
  docker run -m 512m --cpus=1.5 myapp

- -m 512m — лимит памяти (записывается в /sys/fs/cgroup/memory.max),
- --cpus=1.5 — лимит CPU (эквивалентно --cpu-period=100000 --cpu-quota=150000).


Нюансы для JVM:
- По умолчанию JVM не видит лимиты cgroups и выделяет память, равную объему хоста.
- Решение:
  environment:
JAVA_TOOL_OPTIONS: "-XX:MaxRAMPercentage=75.0" //указывает JVM использовать 75% от лимита cgroups.


Проверка лимитов
:
docker exec myapp cat /sys/fs/cgroup/memory.max
docker exec myapp cat /sys/fs/cgroup/cpu.max



Thread-pool tuning под контейнеры

Проблема:
- Стандартные пулы потоков (например, ForkJoinPool) используют Runtime.getRuntime().availableProcessors(),
- В контейнере это значение равно количеству CPU хоста, а не лимиту (--cpus).


Решение:
1. Для Spring Boot:
   # application.properties
spring.task.execution.pool.core-size=4
spring.task.execution.pool.max-size=8


2. Для ванильного Java:
   int availableCpus = (int) Math.min(
Runtime.getRuntime().availableProcessors(),
Double.parseDouble(System.getenv("CPU_LIMIT"))
);
ExecutorService executor = Executors.newFixedThreadPool(availableCpus * 2);


Как получить лимит CPU:
public static int getContainerCpuLimit() {
try (BufferedReader reader = new BufferedReader(
new FileReader("/sys/fs/cgroup/cpu.max"))) {
String line = reader.readLine();
String[] parts = line.split(" ");
long quota = Long.parseLong(parts[0]);
long period = Long.parseLong(parts[1]);
return (int) (quota / period); // Например, 1.5 → 1
}
}



JVM-параметры для контейнеров

Критические параметры:
environment:
JAVA_TOOL_OPTIONS: >-
-XX:+UseContainerSupport
-XX:MaxRAMPercentage=75.0
-XX:+UseZGC
-Djava.security.egd=file:/dev/./urandom


Объяснение:
- -XX:+UseContainerSupport (включено по умолчанию в JDK 8u191+):
- Позволяет JVM читать лимиты из cgroups.
- Без него -XX:MaxRAMPercentage игнорируется.

- -XX:MaxRAMPercentage=75.0:
- Heap = 75% от лимита памяти контейнера.
- Оставшиеся 25% — для Metaspace, native-памяти, стеков потоков.

- -XX:+UseZGC:
- Низколатентный GC (макс. задержки ~1 мс).
- Альтернативы: Shenandoah (JDK 12+), G1GC (по умолчанию).

- -Djava.security.egd=file:/dev/./urandom:
- Ускоряет старт приложений, заменяя блокирующий /dev/random на неблокирующий /dev/urandom.


Проверка работы GC:
docker exec myapp jstat -gcutil 1 1000

- Столбец ZGC покажет использование памяти и паузы сборки мусора.

#Java #middle #Docker #Debug
👍4
Debug и мониторинг: production-ready диагностика

docker exec, attach к процессу

Стандартные команды:
# Стэк-трейс
docker exec myapp jstack 1 > thread_dump.txt

# Мониторинг GC
docker exec myapp jstat -gcutil 1 1000

# Heap-дамп
docker exec myapp jcmd 1 GC.heap_dump /tmp/heap.hprof

Нюансы:
- В distroless-образах нет jstack/jstat.

Решение:
- Используйте sidecar-контейнер с OpenJDK:

    debug-tools:
image: openjdk:17
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: ["jstack", "myapp"]


- Или добавьте инструменты в образ через jlink:
    RUN jlink \
--add-modules jdk.jfr,jdk.management \
--output /jlinked



JMX/JFR в контейнере

Настройка JMX:
environment:
JAVA_TOOL_OPTIONS: >-
-Dcom.sun.management.jmxremote.port=9090
-Dcom.sun.management.jmxremote.rmi.port=9090
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=myapp
ports:
- "9090:9090"


Проблемы:
- RMI-порт: JMX использует динамические порты для RMI. Чтобы зафиксировать их:
  -Dcom.sun.management.jmxremote.rmi.port=9090


- DNS-имя:
-Djava.rmi.server.hostname=myapp — имя сервиса в Docker Compose.

JFR (Java Flight Recorder):
# Запуск записи
docker exec myapp jcmd 1 JFR.start name=recording duration=60s filename=/tmp/recording.jfr

# Экспорт метрик в Prometheus
RUN jcmd 1 JFR.configure stackdepth=128


Интеграция с Prometheus/Grafana


Шаги:
1. Добавьте Micrometer в приложение:
   <dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>


2. Настройте эндпоинт:
   management.endpoints.web.exposure.include=prometheus


3. Docker Compose:
   services:
app:
ports:
- "8080:8080"
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"


4. prometheus.yml:
   scrape_configs:
- job_name: 'java'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app:8080']


Ключевые метрики:
- jvm_memory_used_bytes — использование heap,
- http_server_requests_seconds_count — количество HTTP-запросов,
- jvm_gc_pause_seconds — длительность GC-пауз.


#Java #middle #Docker #Debug
👍4
Что выведет код?

public class Task100925 {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 10;
System.out.println(a[0]);
}
}


#Tasks
👍3
Варианты ответа:
Anonymous Quiz
0%
0
28%
1
62%
10
10%
Ошибка компиляции
👍4😱1
Вопрос с собеседований

Как работает throw с generics? 🤓

Ответ:

throw
может выбрасывать generic исключения, но тип стирается в runtime.

Пример:
<T extends Throwable> void throwIt(T t) throws T {
throw t;
}

Полезно для utility методов.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤯1
🗓 История IT-технологий сегодня — 11 сентября


ℹ️ Кто родился в этот день

Не нашел никого - если кого-то знаете, пишите в комментариях.


🌐 Знаковые события

1997 — Американская автоматическая межпланетная станция Mars Global Surveyor достигла Марса


#Biography #Birth_Date #Events #11Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Основы ООП в Java

Глава 6. Ключевые модификаторы ООП

final: переменные, методы, классы

Модификатор final в Java означает "окончательный" и используется для предотвращения изменений. В зависимости от контекста — переменные, методы или классы — он ограничивает возможность переопределения, изменения или наследования.

Зачем нужен final:
Неизменяемость: Защищает данные от изменений, делая код предсказуемым.
Безопасность: Предотвращает нежелательное изменение поведения в подклассах.
Оптимизация: Компилятор может оптимизировать final-элементы, зная, что они не изменятся.
Дизайн: Помогает явно указать намерения разработчика (например, класс не для наследования).



final — один из ключевых инструментов для создания robust и maintainable кода в ООП.

1. Final переменные: Неизменяемые значения
Когда переменная помечена final, ее значение нельзя изменить после инициализации. Это делает переменную константой.

Типы переменных:
Локальные: Инициализируются один раз в методе.
Поля класса: Должны быть инициализированы при объявлении, в блоке инициализации или конструкторе.
Ссылочные типы: Ссылка неизменна, но объект, на который она указывает, может меняться (если он mutable).


Пример:
public class Circle {
private final double PI = 3.14159; // Константа
private final double radius; // Поле, инициализируется в конструкторе

public Circle(double radius) {
this.radius = radius; // Инициализация final
}

public double getArea() {
final double area = PI * radius * radius; // Локальная final переменная
// area = 10; // Ошибка: нельзя изменить
return area;
}
}


Нюанс: Для final ссылки (например, final StringBuilder sb = new StringBuilder();) нельзя переназначить sb = new StringBuilder();, но можно sb.append("text");.

Практика:

Константы: Обычно static final (например, public static final double PI = 3.14159;).
Именование: Константы в верхнем регистре с подчеркиваниями (MAX_VALUE).


2. Final методы: Запрет переопределения
Когда метод помечен final, его нельзя переопределить (override) в подклассах. Это полезно, когда поведение метода должно остаться неизменным.

Пример с наследованием:
public class Animal {
public final void eat() {
System.out.println("Животное ест.");
}
}

public class Dog extends Animal {
// Ошибка, если попытаться:
// @Override
// public void eat() { System.out.println("Собака ест кости."); }
}


Зачем:
Гарантия неизменного поведения.
Безопасность: Критичные методы (например, валидация) не изменятся.
Нюанс: final не влияет на вызов метода, только на override.


3. Final классы: Запрет наследования
Когда класс помечен final, его нельзя использовать как суперкласс (extends). Это предотвращает создание подклассов.

Пример:
public final class ImmutablePoint {
private final int x;
private final int y;

public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() { return x; }
public int getY() { return y; }
}

// Ошибка:
// public class ExtendedPoint extends ImmutablePoint {}


Зачем:
Иммутабельность: Классы вроде String или Integer — final, чтобы гарантировать неизменность.
Безопасность: Например, в криптографии или конфигурации.
Дизайн: Сигнализирует, что класс завершен и не предназначен для расширения.


#Java #для_новичков #beginner #OOP #final
👍3
Все нюансы final

Переменные:
Инициализация: Должна быть до завершения конструктора (для полей) или до использования (локальные).
Blank final: final поле без начального значения, но с обязательной инициализацией в конструкторе.
Нюанс: final List<String> list = new ArrayList<>(); — можно менять содержимое list, но не саму ссылку.


Методы:
Не влияет на полиморфизм: Вызов метода работает как обычно.
Нельзя с abstract: Абстрактный метод требует override, final запрещает.
Нюанс: Используйте для методов, где логика критична (например, security checks).


Классы:
Все методы implicitly final, но это не нужно явно указывать.
Нюанс: String, Integer, Double — примеры final классов в Java.


Ошибки:

Изменение final переменной: Ошибка компиляции.
Override final метода: Ошибка компиляции.
Extends final класса: Ошибка компиляции.


Дизайн и производительность:
Final улучшает оптимизацию JIT (компилятор знает, что не будет изменений).
Избегайте чрезмерного использования: Final классы ограничивают гибкость (например, тестирование с mocking).
Константы: static final для глобальных неизменяемых значений.


Сценарии использования:
Immutable классы: Все поля final, класс final.
Utility классы: Часто final (например, java.lang.Math).
Конфигурации: Final поля для неизменяемых настроек.



Как создать это в IntelliJ IDEA

Final переменные: Объявите поле с final, IDE проверит инициализацию.
Final методы: Добавьте final перед методом, IDE предупредит о попытке override.
Final классы: Добавьте final к классу, IDE покажет ошибку при extends.
Тестирование: Создайте Main и проверьте поведение.



Полезные советы для новичков

Константы: Используйте static final для PI, MAX_VALUE и т.д.
Иммутабельность: Делайте поля final для защиты данных.
Дизайн: Final классы для завершенных реализаций, но не злоупотребляйте.
Проверяйте: Попробуйте override final метода — IDE покажет ошибку.
Ресурсы: Oracle Tutorials on Final Classes and Methods.



#Java #для_новичков #beginner #OOP #final
👍5
Что выведет код?

public class Task110925 {
public static void main(String[] args) {
final int x = 10;
final int y = getValue();

System.out.println(x + y);
}

static int getValue() {
return 20;
}
}


#Tasks
👍3
Варианты ответа?:
Anonymous Quiz
3%
0
6%
10
54%
30
37%
Ошибка компиляции
👍3
Вопрос с собеседований

Что такое Charset в Java? 🤓

Ответ:

Charset
представляет кодировку символов (UTF-8, ISO-8859-1).

Пример:
Charset utf8 = Charset.forName("UTF-8");
byte[] bytes = "text".getBytes(utf8);

Для работы с текстом в файлах/сетях.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🗓 История IT-технологий сегодня — 12 сентября


ℹ️ Кто родился в этот день

Мадху Судан (Madhu Sudan; род. 12 сентября 1966, Ченнаи, Индия) — индийско-американский учёный в теории вычислений и кодировании; лауреат многих престижных наград за работы по проверке и реконструкции доказательств и сложности приближений.


🌐 Знаковые события

1958 — Испытана первая интегральная схема, созданная инженером фирмы «Texas Instruments» Джеком Килби. Независимо от него в то же время этой проблемой занимался Роберт Нойс, который первым сумел создать промышленный образец. Ему же достались слава и деньги.

1959 — с космодрома Байконур осуществлён запуск советской межпланетной станции «Луна-2». Она станет первым в истории космическим аппаратом, достигшим поверхности Луны.

1994 В Атланте Марк Андриссен представил новый веб-браузер «Mosaic Netscape», который был выпущен в октябре.


#Biography #Birth_Date #Events #12Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
CI/CD и финальный проект: production-ready Java-приложение с Docker

Финальный проект: архитектура и реализация


Сборка Java-приложения с Kafka и PostgreSQL
Требования к системе:
- Java 17 (сборка через Maven),
- PostgreSQL 15 (для хранения данных),
- Kafka 3.5+ (в режиме KRaft, без ZooKeeper),
- Безопасность: non-root пользователь, distroless-образы,
- Production-ready: healthcheck, лимиты ресурсов, мониторинг.


Финальный Dockerfile: multi-stage, non-root, distroless (не тестировался, возможно содержит ошибки, написан для визуализации)
# Stage 1: Сборка с Maven
FROM maven:3.8.6-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B # Загружаем зависимости без исходников
COPY src ./src
RUN mvn package -DskipTests

# Stage 2: Минимальная JVM через jlink
FROM openjdk:17 AS jlink
ARG TARGETARCH
RUN jlink \
--add-modules java.base,java.logging,java.xml,java.management,java.naming \
--output /jlinked \
--strip-debug \
--compress 2 \
--no-header-files \
--no-man-pages

# Stage 3: Distroless-образ
FROM gcr.io/distroless/java17-debian11
COPY --from=jlink /jlinked /jlinked
COPY --from=builder /app/target/myapp.jar /app.jar

# Создаем non-root пользователя
RUN addgroup --gid 1001 appgroup && \
adduser --uid 1001 --gid 1001 --disabled-password --gecos "" appuser
USER 1001

# Настройка JVM под контейнеры
ENV JAVA_OPTS="\
-XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 \
-XX:+UseZGC \
-Djava.security.egd=file:/dev/./urandom"
ENTRYPOINT ["/jlinked/bin/java", "${JAVA_OPTS}", "-jar", "/app.jar"]


Объяснение

1. Multi-stage build:
- Stage 1 (builder):
- Использует официальный образ Maven для загрузки зависимостей (dependency:go-offline ускоряет сборку в CI).
- Сборка происходит в изолированном окружении — зависимости не попадут в финальный образ.


- Stage 2 (jlink):
- Создает минимальную JVM через jlink, включая только необходимые модули (анализируйте зависимости через jdeps --print-module-deps).
- --compress 2 сжимает классы (уменьшает размер на 30%).


- Stage 3 (distroless):
- Базовый образ без ОС — только JVM и приложение.
- Нет shell, curl, apt — нулевой attack surface.


2. Non-root пользователь:
- adduser --uid 1001 создает пользователя с фиксированным UID для совместимости с томами.
- Почему это важно: Если контейнер скомпрометирован, злоумышленник не получит root-доступ к хосту.


3. JVM-параметры:
- -XX:MaxRAMPercentage=75.0 — ограничивает heap 75% от лимита контейнера (оставшиеся 25% — для Metaspace и native-памяти).
- -XX:+UseZGC — низколатентный GC (макс. паузы ~1 мс).


Критические нюансы:
- В distroless нет jcmd/jstack.

Для дампов используйте:
  docker cp myapp:/tmp/heap.hprof .  # Если heap_dump настроен в JAVA_TOOL_OPTIONS


- Проверяйте лимиты памяти через:
  docker exec myapp cat /sys/fs/cgroup/memory.max



#Java #middle #Docker
👍3
Финальный docker-compose.yaml: Java + Kafka (KRaft) + PostgreSQL (не тестировался, возможно содержит ошибки, написан для визуализации)
version: '3.8'
services:
app:
image: myapp:latest
ports:
- "8080:8080"
environment:
DB_URL: jdbc:postgresql://db:5432/mydb
DB_PASSWORD: ${DB_PASSWORD}
KAFKA_BOOTSTRAP_SERVERS: kafka:9092
depends_on:
db:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- app_net
deploy:
resources:
limits:
cpus: '1.5'
memory: 512M

db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 10
networks:
- app_net
deploy:
resources:
limits:
memory: 256M

kafka:
image: bitnami/kafka:3.5.1
container_name: kafka
ports:
- "9092:9092"
environment:
KAFKA_CFG_NODE_ID: 0
KAFKA_CFG_PROCESS_ROLES: "broker,controller"
KAFKA_CFG_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093"
KAFKA_CFG_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092"
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: "PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT"
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CFG_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
volumes:
- kafka_data:/bitnami/kafka
healthcheck:
test: ["CMD", "kafka-broker-api-versions.sh", "--bootstrap-server", "localhost:9092"]
interval: 10s
timeout: 10s
retries: 20
networks:
- app_net
deploy:
resources:
limits:
memory: 512M

volumes:
pg_data:
driver: local
kafka_data:
driver: local

networks:
app_net:
driver: bridge


Ключевые решения

1. KRaft вместо ZooKeeper:
- KAFKA_CFG_PROCESS_ROLES: "broker,controller" — единый процесс для метаданных (упрощает настройку).
- Важно: KAFKA_CFG_ADVERTISED_LISTENERS должен указывать на имя сервиса (kafka), а не на localhost.


2. Healthcheck для всех сервисов:
- Для PostgreSQL: pg_isready проверяет готовность принимать подключения.
- Для Kafka:
kafka-broker-api-versions.sh убеждается, что брокер принимает запросы.
- Почему это критично: depends_on без healthcheck не предотвращает race condition.


3. Лимиты ресурсов:
- deploy.resources.limits — ограничивает использование CPU/memory через cgroups.
- Без этого JVM может выделить память, превышающую лимит контейнера (падение с OutOfMemoryError).


4. Сеть:
- Все сервисы в одной сети app_net — общаются по именам (db, kafka).
- Встроенный DNS Docker резолвит имена в IP-адреса контейнеров.



#Java #middle #Docker
👍2
CI/CD pipeline: от коммита до production

Сборка образа в GitHub Actions
name: Build and Push Docker Image
on:
push:
branches: [ main ]
tags: [ 'v*' ]

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU for multi-arch
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: ${{ runner.os }}-buildx-

- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: myapp:latest,myapp:${{ github.sha }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
build-args: |
BUILDKIT_INLINE_CACHE=1



Как это работает


1. Кэширование слоев:
- actions/cache сохраняет результаты сборки в /tmp/.buildx-cache.
- При следующем запуске Buildx использует кэш через cache-from, пропуская этапы с неизмененными инструкциями (например, загрузку зависимостей Maven).
- Экономия времени: Сборка с кэшем — 2 минуты вместо 10.


2. Multi-arch сборка:
- platforms: linux/amd64,linux/arm64 — собирает образы для x86 и ARM.
- Использует QEMU для эмуляции архитектур (установлен через docker/setup-qemu-action).


3. Тегирование:
- myapp:latest — для dev-окружения (не рекомендуется для production!),
- myapp:${{ github.sha }} — уникальный тег на коммит (для отката),
- При тегировании релиза (v1.0.0) — myapp:1.0.0.


Нюансы:
- Для production никогда не используйте latest — это нарушает идемпотентность.
- Вместо latest применяйте семантическое версионирование: major.minor.patch.



#Java #middle #Docker
👍4
Сканирование образа на уязвимости

Добавьте в пайплайн после сборки:
- name: Scan with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'table'
exit-code: '1'
ignore-unfixed: true
severity: 'CRITICAL,HIGH'


Как это работает:
- Trivy сканирует образ на наличие уязвимостей в:
- Базовом образе (distroless — минимум пакетов),
- Зависимостях Java (через анализ JAR-файлов).
- ignore-unfixed: true — игнорирует уязвимости без патчей (чтобы не блокировать сборку).
- severity: CRITICAL,HIGH — падает при критических уязвимостях.


Альтернатива: Snyk
- name: Snyk Container scan
uses: snyk/actions/container@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
image: myapp:${{ github.sha }}
args: --severity-threshold=high --fail-on=all



Организация production-ready релиза

Политики хранения образов в registry

1. Для DockerHub/приватного registry:
- Удаляйте образы старше 30 дней (кроме tagged релизов)
- Оставляйте последние 5 образов для каждого major-версии (например, v1.*).


2. Как автоматизировать:
- В GitLab CI используйте cleanup policy для registry,
- В AWS ECR — Lifecycle Policy:

     {
"rules": [
{
"rulePriority": 1,
"description": "Удалять образы старше 30 дней",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 30
},
"action": { "type": "expire" }
}
]
}


Multi-environment setup через override.yml

Структура проекта:

├── docker-compose.yml        # Базовая конфигурация
├── docker-compose.dev.yml # Dev-окружение
├── docker-compose.prod.yml # Production
└── .env


Пример docker-compose.prod.yml:
services:
app:
environment:
SPRING_PROFILES_ACTIVE: prod
JAVA_TOOL_OPTIONS: >-
-XX:MaxRAMPercentage=75.0
-XX:+UseZGC
deploy:
replicas: 3
update_config:
parallelism: 1
order: start-first
networks:
- monitoring_net

db:
environment:
POSTGRES_PASSWORD: ${PROD_DB_PASSWORD}
volumes:
- /mnt/prod/pg_data:/var/lib/postgresql/data


Запуск для production:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d


Ключевые отличия:
- Dev:
- Горячая перезагрузка кода через bind mounts,
- Отключенные лимиты ресурсов.

- Production:
- Фиксированные теги образов (не latest),
- Подключение к сети мониторинга (monitoring_net),
- Приватные тома на выделенном диске (/mnt/prod/pg_data).



Будущее: переход к Kubernetes/Helm

Почему Docker Compose не для production?
- Нет оркестрации на нескольких нодах,
- Отсутствует self-healing (автовосстановление упавших сервисов),
- Нет встроенного балансировщика нагрузки.


Как мигрировать
:
1. Замените `docker-compose.yml` на Helm chart:
helm create myapp


2. Настройте values.yaml:

   app:
replicaCount: 3
image:
repository: myapp
tag: "v1.0.0"
resources:
limits:
memory: 512Mi
cpu: "1.5"


3. Интегрируйте Kafka через Strimzi Operator:
   # kafka.yaml
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
spec:
kafka:
version: 3.5.0
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false


Преимущества Kubernetes:
- Автомасштабирование (HPA),
- Сетевая изоляция через Network Policies,
- Управление секретами через kubectl create secret.



#Java #middle #Docker
👍3
Что выведет код?

public class Task120925 {
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;
double c = 0.3;

System.out.println(a + b == c);
}
}


#Tasks
👍3
Варианты ответа:
Anonymous Quiz
47%
true
50%
false
0%
null
3%
Ошибка компиляции
👍32
Вопрос с собеседований

Что такое Instant в Java? 🤓

Ответ:

Instant
— момент времени в UTC из java.time.

Пример:
Instant now =
Instant.now();

Для timestamp без часового пояса.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Всех с днем программиста! ❤️

В соответствии с Указом Президента Российской Федерации от 11.09.2009 г. № 1034, сегодня мы отмечаем! 🥳

Всем и каждому желаю добиться невероятных успехов в программировании, знании всех известных алгоритмов и библиотек, зп в 300кк в 1 наносекунду, на удаленке с Бали и прочих плюшек о которых мечтаете! 🏝

Я верю что вместе все мы добьемся успеха!

С праздником! 🍸
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10🍾3