mirror of
https://github.com/Dannecron/spring-boot-demo.git
synced 2025-12-25 16:22:35 +03:00
Compare commits
3 Commits
02854b775c
...
e6db3360c2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6db3360c2 | ||
|
|
11847af074 | ||
|
|
9a98763261 |
@@ -1,2 +1,3 @@
|
||||
*
|
||||
!build/libs/
|
||||
!build/libs/
|
||||
!entrypoint.sh
|
||||
|
||||
14
.env.example
14
.env.example
@@ -9,4 +9,16 @@ DB_PASSWORD=postgres
|
||||
|
||||
KAFKA_SERVERS=localhost:9095
|
||||
|
||||
OTLP_TRACING_HTTP_URL=http://localhost:4318/v1/traces
|
||||
OTLP_TRACING_HTTP_URL=http://localhost:4318/v1/traces
|
||||
|
||||
# jvm tuning
|
||||
TOMCAT_THREADS_MAX=30
|
||||
#TOMCAT_THREADS_MIN=
|
||||
HIKARI_DB_MAXIMUM_POOL_SIZE=4
|
||||
#HIKARI_DB_MINIMUM_IDLE_SIZE
|
||||
#JVM_NATIVE_MB=120
|
||||
#RESERVED_CODE_CACHE_SIZE_MB=64
|
||||
MAX_METASPACE_SIZE_MB=100
|
||||
#DIRECT_BYTES_BUFFERS_MB=10
|
||||
#COMPRESSED_CLASS_SPACE_MB=16
|
||||
#OVERHEAD_GC_SIZE_PERCENT=5
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.gradle
|
||||
build/
|
||||
gradle.properties
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@@ -1,3 +1,9 @@
|
||||
FROM openjdk:17-jdk-slim
|
||||
COPY --chmod=777 build/libs/demo-single-version.jar /application/demo.jar
|
||||
CMD ["java", "-jar", "/application/demo.jar"]
|
||||
FROM eclipse-temurin:20-jdk
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./entrypoint.sh .
|
||||
RUN chmod +x ./entrypoint.sh
|
||||
COPY ./build/libs/*.jar .
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
idea
|
||||
alias(libs.plugins.kotlin.kover)
|
||||
alias(libs.plugins.kotlin.jpa)
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
alias(libs.plugins.kotlin.spring)
|
||||
alias(libs.plugins.spring.boot)
|
||||
alias(libs.plugins.spring.dependencyManagement)
|
||||
alias(libs.plugins.io.spring.dependency.management)
|
||||
alias(libs.plugins.org.jetbrains.kotlin.jvm)
|
||||
alias(libs.plugins.org.jetbrains.kotlin.plugin.jpa)
|
||||
alias(libs.plugins.org.jetbrains.kotlin.plugin.serialization)
|
||||
alias(libs.plugins.org.jetbrains.kotlin.plugin.spring)
|
||||
alias(libs.plugins.org.jetbrains.kotlinx.kover)
|
||||
alias(libs.plugins.org.springframework.boot)
|
||||
}
|
||||
|
||||
group = "com.github.dannecron.demo"
|
||||
@@ -14,26 +16,28 @@ version = "single-version"
|
||||
|
||||
allprojects {
|
||||
apply {
|
||||
plugin(rootProject.libs.plugins.kotlin.jvm.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.kotlin.serialization.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.kotlin.kover.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.spring.boot.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.org.jetbrains.kotlin.jvm.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.org.jetbrains.kotlin.plugin.serialization.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.org.jetbrains.kotlinx.kover.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.org.springframework.boot.get().pluginId)
|
||||
|
||||
plugin("java")
|
||||
}
|
||||
|
||||
plugins.withId("org.jetbrains.kotlinx.kover") {
|
||||
plugins.withId(rootProject.libs.plugins.org.jetbrains.kotlinx.kover.get().pluginId) {
|
||||
tasks.named("koverXmlReport") {
|
||||
dependsOn(tasks.test)
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
sourceCompatibility = JavaVersion.VERSION_20
|
||||
targetCompatibility = JavaVersion.VERSION_20
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_20)
|
||||
freeCompilerArgs.addAll("-Xjsr305=strict")
|
||||
apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_1)
|
||||
}
|
||||
@@ -44,17 +48,17 @@ allprojects {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
runtimeOnly(rootProject.libs.micrometer.registry.prometheus)
|
||||
runtimeOnly(rootProject.libs.io.micrometer.micrometer.registry.prometheus)
|
||||
|
||||
implementation(rootProject.libs.bundles.tracing)
|
||||
implementation(rootProject.libs.kotlin.reflect)
|
||||
implementation(rootProject.libs.kotlinx.serialization.json)
|
||||
implementation(rootProject.libs.logback.encoder)
|
||||
implementation(rootProject.libs.springFramework.aspects)
|
||||
implementation(rootProject.libs.net.logstash.logback.logstash.logback.encoder)
|
||||
implementation(rootProject.libs.org.jetbrains.kotlin.kotlin.reflect)
|
||||
implementation(rootProject.libs.org.jetbrains.kotlinx.kotlinx.serialization.json)
|
||||
implementation(rootProject.libs.org.springframework.spring.aspects)
|
||||
|
||||
testImplementation(rootProject.libs.kotlin.test.junit)
|
||||
testImplementation(rootProject.libs.mockito.kotlin)
|
||||
testImplementation(rootProject.libs.springBoot.starter.test)
|
||||
testImplementation(rootProject.libs.org.jetbrains.kotlin.kotlin.test.junit5)
|
||||
testImplementation(rootProject.libs.org.mockito.kotlin.mockito.kotlin)
|
||||
testImplementation(rootProject.libs.org.springframework.boot.spring.boot.starter.test)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
@@ -67,9 +71,9 @@ allprojects {
|
||||
|
||||
subprojects {
|
||||
apply {
|
||||
plugin(rootProject.libs.plugins.kotlin.spring.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.spring.boot.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.spring.dependencyManagement.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.io.spring.dependency.management.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.org.jetbrains.kotlin.plugin.spring.get().pluginId)
|
||||
plugin(rootProject.libs.plugins.org.springframework.boot.get().pluginId)
|
||||
}
|
||||
|
||||
tasks.bootJar {
|
||||
@@ -86,12 +90,12 @@ dependencies {
|
||||
implementation(project(":edge-consuming"))
|
||||
implementation(project(":edge-rest"))
|
||||
|
||||
implementation(libs.springBoot.starter.mustache)
|
||||
implementation(libs.springBoot.starter.web)
|
||||
implementation(libs.org.springframework.boot.spring.boot.starter.mustache)
|
||||
implementation(libs.org.springframework.boot.spring.boot.starter.web)
|
||||
|
||||
testImplementation(libs.archUnit.junit)
|
||||
testImplementation(libs.com.tngtech.archunit.archunit.junit5)
|
||||
|
||||
developmentOnly(libs.springBoot.devtools)
|
||||
developmentOnly(libs.org.springframework.boot.spring.boot.devtools)
|
||||
|
||||
kover(project(":edge-contracts"))
|
||||
kover(project(":db"))
|
||||
|
||||
@@ -3,8 +3,8 @@ dependencies {
|
||||
implementation(project(":edge-producing"))
|
||||
implementation(project(":edge-integration"))
|
||||
|
||||
implementation(rootProject.libs.springBoot.starter.actuator)
|
||||
implementation(rootProject.libs.springData.commons)
|
||||
implementation(rootProject.libs.org.springframework.boot.spring.boot.starter.actuator)
|
||||
implementation(rootProject.libs.org.springframework.data.spring.data.commons)
|
||||
|
||||
testImplementation(rootProject.libs.springBoot.starter.actuatorAutoconfigure)
|
||||
testImplementation(rootProject.libs.org.springframework.boot.spring.boot.starter.actuator.autoconfigure)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jpa)
|
||||
alias(libs.plugins.org.jetbrains.kotlin.plugin.jpa)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(rootProject.libs.flyway.core)
|
||||
implementation(rootProject.libs.postgres)
|
||||
implementation(rootProject.libs.springBoot.starter.jdbc)
|
||||
implementation(rootProject.libs.org.flywaydb.flyway.core)
|
||||
implementation(rootProject.libs.org.postgresql.postgresql)
|
||||
implementation(rootProject.libs.org.springframework.boot.spring.boot.starter.data.jdbc)
|
||||
|
||||
testImplementation(libs.testcontainers)
|
||||
testImplementation(libs.testcontainers.junit.jupiter)
|
||||
testImplementation(libs.testcontainers.postgresql)
|
||||
testImplementation(libs.org.testcontainers.junit.jupiter)
|
||||
testImplementation(libs.org.testcontainers.postgresql)
|
||||
testImplementation(libs.org.testcontainers.testcontainers)
|
||||
}
|
||||
|
||||
278
doc/entrypoint.md
Normal file
278
doc/entrypoint.md
Normal file
@@ -0,0 +1,278 @@
|
||||
# Entrypoint: Запуск JAR-файла и конфигурация JVM
|
||||
|
||||
_LLM-generated документация._
|
||||
|
||||
## Оглавление
|
||||
|
||||
- [Обзор](#обзор)
|
||||
- [Параметры запуска](#параметры-запуска)
|
||||
- [Алгоритм работы](#алгоритм-работы)
|
||||
- [1. Определение ограничений памяти контейнера](#1-определение-ограничений-памяти-контейнера)
|
||||
- [2. Конфигурация компонентов приложения](#2-конфигурация-компонентов-приложения)
|
||||
- [Переменные окружения со значениями по умолчанию:](#переменные-окружения-со-значениями-по-умолчанию)
|
||||
- [3. Расчет "складских" ресурсов](#3-расчет-складских-ресурсов)
|
||||
- [4. Расчет доступной памяти для JVM](#4-расчет-доступной-памяти-для-jvm)
|
||||
- [5. Настройка Non-Heap областей JVM](#5-настройка-non-heap-областей-jvm)
|
||||
- [Конфигурация областей памяти:](#конфигурация-областей-памяти)
|
||||
- [6. Расчет Heap памяти](#6-расчет-heap-памяти)
|
||||
- [Этап 1: Память доступная для Heap + GC](#этап-1-память-доступная-для-heap--gc)
|
||||
- [Этап 2: Резерв для GC overhead](#этап-2-резерв-для-gc-overhead)
|
||||
- [Этап 3: Финальный размер Heap](#этап-3-финальный-размер-heap)
|
||||
- [Этап 4: Процент от MaxRAM для JVM](#этап-4-процент-от-maxram-для-jvm)
|
||||
- [JVM флаги и их назначение](#jvm-флаги-и-их-назначение)
|
||||
- [Контейнерная поддержка](#контейнерная-поддержка)
|
||||
- [Управление памятью](#управление-памятью)
|
||||
- [Оптимизация производительности](#оптимизация-производительности)
|
||||
- [Дополнительные опции](#дополнительные-опции)
|
||||
- [Экспортируемые переменные](#экспортируемые-переменные)
|
||||
- [Пример расчета](#пример-расчета)
|
||||
- [Дано:](#дано)
|
||||
- [Расчет:](#расчет)
|
||||
- [Результирующая команда Java:](#результирующая-команда-java)
|
||||
- [Мониторинг и отладка](#мониторинг-и-отладка)
|
||||
- [Verbose режим (`-v`)](#verbose-режим--v)
|
||||
- [Рекомендуемые размеры контейнеров](#рекомендуемые-размеры-контейнеров)
|
||||
- [Рекомендации по настройке:](#рекомендации-по-настройке)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Проблема: Приложение падает с OOM](#проблема-приложение-падает-с-oom)
|
||||
- [Проблема: Медленная работа GC](#проблема-медленная-работа-gc)
|
||||
- [Проблема: Много database connections timeout](#проблема-много-database-connections-timeout)
|
||||
|
||||
## Обзор
|
||||
|
||||
Скрипт `entrypoint.sh` выполняет интеллектуальную настройку JVM на основе ограничений памяти контейнера. Он автоматически вычисляет оптимальные размеры heap, non-heap областей и других параметров для обеспечения стабильной работы Spring Boot приложения.
|
||||
|
||||
### Параметры запуска
|
||||
|
||||
- **`-v`** - включает verbose режим с выводом отладочной информации о расчетах памяти
|
||||
- **`JAR_FILE_NAME`** - имя JAR-файла для запуска (позиционный аргумент)
|
||||
|
||||
**Пример использования:**
|
||||
```bash
|
||||
./entrypoint.sh -v app.jar # С отладочной информацией
|
||||
./entrypoint.sh app.jar # Без отладочной информации
|
||||
```
|
||||
|
||||
## Алгоритм работы
|
||||
|
||||
### 1. Определение ограничений памяти контейнера
|
||||
|
||||
```bash
|
||||
# Проверка версии cgroups и получение лимита памяти
|
||||
if [ -f /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
|
||||
# Cgroups v1
|
||||
LIMITED_RAM_CONTAINER_CGROUP_SIZE_BYTES=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)
|
||||
elif [ -f /sys/fs/cgroup/memory.max ]; then
|
||||
# Cgroups v2
|
||||
LIMITED_RAM_CONTAINER_CGROUP_SIZE_BYTES=$(cat /sys/fs/cgroup/memory.max)
|
||||
else
|
||||
# Ошибка: нет доступа к информации о памяти
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**Результат:** Получение лимита памяти контейнера в байтах.
|
||||
|
||||
### 2. Конфигурация компонентов приложения
|
||||
|
||||
#### Переменные окружения со значениями по умолчанию:
|
||||
|
||||
| Переменная | Значение по умолчанию | Описание |
|
||||
|-------------------------------|-------------------------------|----------------------------------------|
|
||||
| `TOMCAT_THREADS_MAX` | 100 | Максимальное количество потоков Tomcat |
|
||||
| `TOMCAT_THREADS_MIN` | = TOMCAT_THREADS_MAX | Минимальное количество потоков Tomcat |
|
||||
| `HIKARI_DB_MAXIMUM_POOL_SIZE` | 10 | Максимальный размер пула соединений БД |
|
||||
| `HIKARI_DB_MINIMUM_IDLE_SIZE` | = HIKARI_DB_MAXIMUM_POOL_SIZE | Минимальное количество idle соединений |
|
||||
| `JVM_NATIVE_MB` | 120 | Резерв памяти для native кода JVM |
|
||||
|
||||
### 3. Расчет "складских" ресурсов
|
||||
|
||||
```bash
|
||||
STOCK_SIZE_MB = (TOMCAT_THREADS_MAX / 2) + HIKARI_DB_MAXIMUM_POOL_SIZE + JVM_NATIVE_MB
|
||||
```
|
||||
|
||||
**Логика расчета:**
|
||||
- **Tomcat потоки:** каждый поток потребляет ~0.5 MB памяти
|
||||
- **Пул соединений БД:** каждое соединение ~1 MB
|
||||
- **Native память JVM:** фиксированный резерв для JNI, сжатия, etc.
|
||||
|
||||
**Пример:** При дефолтных значениях: `(100/2) + 10 + 120 = 180 MB`
|
||||
|
||||
### 4. Расчет доступной памяти для JVM
|
||||
|
||||
```bash
|
||||
LIMITED_MAXRAM_JAVA_SIZE_MB = LIMITED_RAM_CONTAINER_CGROUP_SIZE_MB - STOCK_SIZE_MB
|
||||
```
|
||||
|
||||
**Назначение:** Память, которую JVM может использовать без риска превышения лимитов контейнера.
|
||||
|
||||
### 5. Настройка Non-Heap областей JVM
|
||||
|
||||
#### Конфигурация областей памяти:
|
||||
|
||||
| Область | Переменная | Значение по умолчанию | Назначение |
|
||||
|----------------------------|-------------------------------|-----------------------|----------------------------|
|
||||
| **Code Cache** | `RESERVED_CODE_CACHE_SIZE_MB` | 64 MB | Компилированный JIT код |
|
||||
| **Metaspace** | `MAX_METASPACE_SIZE_MB` | 80 MB | Метаданные классов |
|
||||
| **Direct Buffers** | `DIRECT_BYTES_BUFFERS_MB` | 10 MB | NIO буферы |
|
||||
| **Compressed Class Space** | `COMPRESSED_CLASS_SPACE_MB` | 16 MB | Сжатые указатели на классы |
|
||||
|
||||
```bash
|
||||
NON_HEAP_SIZE_MB = RESERVED_CODE_CACHE_SIZE_MB + MAX_METASPACE_SIZE_MB +
|
||||
DIRECT_BYTES_BUFFERS_MB + COMPRESSED_CLASS_SPACE_MB
|
||||
```
|
||||
|
||||
### 6. Расчет Heap памяти
|
||||
|
||||
#### Этап 1: Память доступная для Heap + GC
|
||||
```bash
|
||||
HEAP_GC_SIZE_MB = LIMITED_MAXRAM_JAVA_SIZE_MB - NON_HEAP_SIZE_MB
|
||||
```
|
||||
|
||||
#### Этап 2: Резерв для GC overhead
|
||||
```bash
|
||||
OVERHEAD_GC_SIZE_PERCENT = 5 # По умолчанию 5%
|
||||
OVERHEAD_GC_SIZE_MB = (HEAP_GC_SIZE_MB * OVERHEAD_GC_SIZE_PERCENT) / 100
|
||||
```
|
||||
|
||||
#### Этап 3: Финальный размер Heap
|
||||
```bash
|
||||
HEAP_SIZE_MB = HEAP_GC_SIZE_MB - OVERHEAD_GC_SIZE_MB
|
||||
```
|
||||
|
||||
#### Этап 4: Процент от MaxRAM для JVM
|
||||
```bash
|
||||
MAX_RAM_PERCENTAGE = (HEAP_SIZE_MB * 100) / LIMITED_MAXRAM_JAVA_SIZE_MB
|
||||
```
|
||||
|
||||
## JVM флаги и их назначение
|
||||
|
||||
### Контейнерная поддержка
|
||||
- **`-XX:+UseContainerSupport`** - Включает автоопределение ресурсов контейнера
|
||||
- **`-XX:MaxRAM="${LIMITED_MAXRAM_JAVA_SIZE_MB}m"`** - Максимальная память для JVM
|
||||
- **`-XX:MaxRAMPercentage="$MAX_RAM_PERCENTAGE"`** - Процент MaxRAM для heap
|
||||
|
||||
### Управление памятью
|
||||
- **`-XX:+ExitOnOutOfMemoryError`** - Принудительное завершение при OOM
|
||||
- **`-XX:MaxMetaspaceSize="${MAX_METASPACE_SIZE_MB}m"`** - Лимит Metaspace
|
||||
|
||||
### Оптимизация производительности
|
||||
- **`-XX:+SegmentedCodeCache`** - Сегментированный code cache для лучшей производительности
|
||||
- **`-XX:ReservedCodeCacheSize="${RESERVED_CODE_CACHE_SIZE_MB}m"`** - Размер code cache
|
||||
|
||||
### Дополнительные опции
|
||||
- **`$JAVA_OPTS_OVERRIDE`** - Переменная для переопределения опций
|
||||
|
||||
## Экспортируемые переменные
|
||||
|
||||
Скрипт экспортирует рассчитанные значения для использования приложением:
|
||||
|
||||
```bash
|
||||
export TOMCAT_THREADS_MAX=$TOMCAT_THREADS_MAX
|
||||
export TOMCAT_THREADS_MIN=$TOMCAT_THREADS_MIN
|
||||
export HIKARI_DB_MAXIMUM_POOL_SIZE=$HIKARI_DB_MAXIMUM_POOL_SIZE
|
||||
export HIKARI_DB_MINIMUM_IDLE_SIZE=$HIKARI_DB_MINIMUM_IDLE_SIZE
|
||||
```
|
||||
|
||||
## Пример расчета
|
||||
|
||||
### Дано:
|
||||
- Лимит контейнера: **512 MB**
|
||||
- Дефолтные значения всех переменных
|
||||
|
||||
### Расчет:
|
||||
|
||||
1. **Складские ресурсы:**
|
||||
```
|
||||
STOCK_SIZE_MB = (100/2) + 10 + 120 = 180 MB
|
||||
```
|
||||
|
||||
2. **Доступная память для JVM:**
|
||||
```
|
||||
LIMITED_MAXRAM_JAVA_SIZE_MB = 512 - 180 = 332 MB
|
||||
```
|
||||
|
||||
3. **Non-heap память:**
|
||||
```
|
||||
NON_HEAP_SIZE_MB = 64 + 80 + 10 + 16 = 170 MB
|
||||
```
|
||||
|
||||
4. **Память для Heap + GC:**
|
||||
```
|
||||
HEAP_GC_SIZE_MB = 332 - 170 = 162 MB
|
||||
```
|
||||
|
||||
5. **GC overhead:**
|
||||
```
|
||||
OVERHEAD_GC_SIZE_MB = (162 * 5) / 100 = 8 MB
|
||||
```
|
||||
|
||||
6. **Финальный размер Heap:**
|
||||
```
|
||||
HEAP_SIZE_MB = 162 - 8 = 154 MB
|
||||
```
|
||||
|
||||
7. **Процент RAM для heap:**
|
||||
```
|
||||
MAX_RAM_PERCENTAGE = (154 * 100) / 332 = 46%
|
||||
```
|
||||
|
||||
### Результирующая команда Java:
|
||||
|
||||
```bash
|
||||
exec java \
|
||||
-XX:+UseContainerSupport \
|
||||
-XX:+ExitOnOutOfMemoryError \
|
||||
-XX:MaxRAM="332m" \
|
||||
-XX:MaxRAMPercentage="46" \
|
||||
-XX:+SegmentedCodeCache \
|
||||
-XX:ReservedCodeCacheSize="64m" \
|
||||
-XX:MaxMetaspaceSize="80m" \
|
||||
-jar /app/app.jar
|
||||
```
|
||||
|
||||
## Мониторинг и отладка
|
||||
|
||||
### Verbose режим (`-v`)
|
||||
|
||||
При запуске с флагом `-v` скрипт выводит отладочную информацию:
|
||||
|
||||
```bash
|
||||
# Версия cgroups
|
||||
Cgroups v2 are used
|
||||
|
||||
# Расчеты памяти
|
||||
LIMITED_MAXRAM_JAVA_SIZE_MB=332
|
||||
HEAP_SIZE_MB=154
|
||||
MAX_RAM_PERCENTAGE=46
|
||||
```
|
||||
|
||||
**Без флага `-v`** - никаких отладочных сообщений не выводится, только стандартные логи приложения.
|
||||
|
||||
### Рекомендуемые размеры контейнеров
|
||||
|
||||
| Размер контейнера | Heap | Статус |
|
||||
|-------------------|-----------------|---------------------|
|
||||
| **≤ 352 MB** | ❌ Отрицательный | Не работает |
|
||||
| **353 MB** | 🔴 3 MB | Критический минимум |
|
||||
| **400 MB** | 🟡 47 MB | Базовый |
|
||||
| **512 MB** | 🟢 154 MB | Рекомендуемый |
|
||||
| **768 MB** | 🟢 380 MB | Комфортный |
|
||||
|
||||
### Рекомендации по настройке:
|
||||
|
||||
1. **Для высоко нагруженных приложений** - увеличьте `TOMCAT_THREADS_MAX`
|
||||
2. **Для БД-интенсивных приложений** - увеличьте `HIKARI_DB_MAXIMUM_POOL_SIZE`
|
||||
3. **Для приложений с большим количеством классов** - увеличьте `MAX_METASPACE_SIZE_MB`
|
||||
4. **При частых OOM** - уменьшите `OVERHEAD_GC_SIZE_PERCENT` или увеличьте память контейнера
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Проблема: Приложение падает с OOM
|
||||
**Решение:** Проверьте соотношение heap/non-heap памяти, возможно нужно увеличить лимит контейнера.
|
||||
|
||||
### Проблема: Медленная работа GC
|
||||
**Решение:** Увеличьте `OVERHEAD_GC_SIZE_PERCENT` или используйте альтернативный GC через `JAVA_OPTS_OVERRIDE`.
|
||||
|
||||
### Проблема: Много database connections timeout
|
||||
**Решение:** Увеличьте `HIKARI_DB_MAXIMUM_POOL_SIZE` и соответственно лимит памяти контейнера.
|
||||
@@ -5,16 +5,16 @@ services:
|
||||
build:
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
environment:
|
||||
SPRING_LOG_LEVEL: $SPRING_LOG_LEVEL
|
||||
SPRING_ACTIVE_PROFILE: $SPRING_ACTIVE_PROFILE
|
||||
DB_URL: $DB_URL
|
||||
DB_NAME: $DB_NAME
|
||||
DB_SCHEMA: $DB_SCHEMA
|
||||
DB_USERNAME: $DB_USERNAME
|
||||
DB_PASSWORD: $DB_PASSWORD
|
||||
KAFKA_SERVERS: $KAFKA_SERVERS
|
||||
OTLP_TRACING_HTTP_URL: $OTLP_TRACING_HTTP_URL
|
||||
env_file:
|
||||
- .env
|
||||
expose:
|
||||
- 8080
|
||||
- 8081
|
||||
command:
|
||||
- app.jar
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "--silent", "http://localhost:8081/health" ]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
|
||||
@@ -2,10 +2,10 @@ dependencies {
|
||||
implementation(project(":edge-contracts"))
|
||||
implementation(project(":core"))
|
||||
|
||||
implementation(rootProject.libs.jackson.datatype.jsr)
|
||||
implementation(rootProject.libs.jackson.module.kotlin)
|
||||
implementation(rootProject.libs.springCloud.starter.streamKafka)
|
||||
implementation(rootProject.libs.springCloud.stream)
|
||||
implementation(rootProject.libs.com.fasterxml.jackson.datatype.jackson.datatype.jsr310)
|
||||
implementation(rootProject.libs.com.fasterxml.jackson.module.jackson.module.kotlin)
|
||||
implementation(rootProject.libs.org.springframework.cloud.spring.cloud.starter.stream.kafka)
|
||||
implementation(rootProject.libs.org.springframework.cloud.spring.cloud.stream)
|
||||
|
||||
testImplementation(rootProject.libs.springCloud.streamTestBinder)
|
||||
testImplementation(rootProject.libs.org.springframework.cloud.spring.cloud.stream.test.binder)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
dependencies {
|
||||
implementation(rootProject.libs.json.schema.validator)
|
||||
implementation(rootProject.libs.springBoot.starter.web)
|
||||
implementation(rootProject.libs.springData.commons)
|
||||
implementation(rootProject.libs.springDoc.openapi.starter)
|
||||
implementation(rootProject.libs.springCloud.stream)
|
||||
|
||||
implementation(rootProject.libs.io.github.optimumcode.json.schema.validator)
|
||||
implementation(rootProject.libs.org.springdoc.springdoc.openapi.starter.webmvc.ui)
|
||||
implementation(rootProject.libs.org.springframework.boot.spring.boot.starter.web)
|
||||
implementation(rootProject.libs.org.springframework.cloud.spring.cloud.stream)
|
||||
implementation(rootProject.libs.org.springframework.data.spring.data.commons)
|
||||
}
|
||||
|
||||
@@ -5,19 +5,21 @@ import com.github.dannecron.demo.edgecontracts.validation.SchemaValidatorImp
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.util.ResourceUtils
|
||||
import org.springframework.core.io.ResourceLoader
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ValidationProperties::class)
|
||||
class SchemaValidationConfig(
|
||||
private val validationProperties: ValidationProperties,
|
||||
private val resourceLoader: ResourceLoader,
|
||||
) {
|
||||
|
||||
@Bean
|
||||
fun schemaValidator(): SchemaValidator = SchemaValidatorImp(
|
||||
schemaMap = validationProperties.schema.mapValues {
|
||||
schema -> ResourceUtils.getFile("classpath:json-schemas/${schema.value}")
|
||||
.readText(Charsets.UTF_8)
|
||||
schema -> resourceLoader.getResource("classpath:json-schemas/${schema.value}")
|
||||
.takeIf { it.exists() }!!
|
||||
.getContentAsString(Charsets.UTF_8)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
dependencies {
|
||||
implementation(rootProject.libs.springFramework.context)
|
||||
implementation(rootProject.libs.ktor.client.cio)
|
||||
implementation(rootProject.libs.ktor.client.core)
|
||||
implementation(rootProject.libs.io.ktor.ktor.client.cio)
|
||||
implementation(rootProject.libs.io.ktor.ktor.client.core)
|
||||
implementation(rootProject.libs.org.springframework.spring.context)
|
||||
|
||||
testImplementation(rootProject.libs.ktor.client.mock)
|
||||
testImplementation(rootProject.libs.io.ktor.ktor.client.mock)
|
||||
}
|
||||
|
||||
@@ -5,43 +5,57 @@ import com.github.dannecron.demo.edgeintegration.client.neko.dto.ImagesResponse
|
||||
import com.github.dannecron.demo.edgeintegration.client.neko.exceptions.RequestException
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.plugins.defaultRequest
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import io.ktor.http.path
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
class ClientImpl(
|
||||
engine: HttpClientEngine,
|
||||
private val baseUrl: String,
|
||||
): Client {
|
||||
private val httpClient = HttpClient(engine)
|
||||
private val httpClient = HttpClient(engine) {
|
||||
defaultRequest {
|
||||
url(baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCategories() = runBlocking {
|
||||
httpClient.get(urlString = baseUrl) {
|
||||
httpClient.get {
|
||||
url {
|
||||
path("/api/v2/endpoints")
|
||||
}
|
||||
}
|
||||
.takeIf { it.status.value in 200..209 }
|
||||
?.let {
|
||||
response -> Json.decodeFromString<Map<String, CategoryFormat>>(response.bodyAsText()).keys
|
||||
.let { response ->
|
||||
val responseBody = response.bodyAsText()
|
||||
if (response.status.value in 200..209) {
|
||||
Json.decodeFromString<Map<String, CategoryFormat>>(responseBody).keys
|
||||
} else {
|
||||
throw RequestException(
|
||||
"get categories error. Status: ${response.status.value}, response: $responseBody"
|
||||
)
|
||||
}
|
||||
}
|
||||
?: throw RequestException("get categories error")
|
||||
}
|
||||
|
||||
override fun getImages(category: String, amount: Int) = runBlocking {
|
||||
httpClient.get(urlString = baseUrl) {
|
||||
httpClient.get {
|
||||
url {
|
||||
path("/api/v2/$category")
|
||||
parameters.append("amount", amount.toString())
|
||||
}
|
||||
}
|
||||
.takeIf { it.status.value in 200..209 }
|
||||
?.let {
|
||||
response -> Json.decodeFromString<ImagesResponse>(response.bodyAsText())
|
||||
.let { response ->
|
||||
val responseBody = response.bodyAsText()
|
||||
if (response.status.value in 200..209) {
|
||||
Json.decodeFromString<ImagesResponse>(responseBody)
|
||||
} else {
|
||||
throw RequestException(
|
||||
"get images error. Status: ${response.status.value}, response: $responseBody"
|
||||
)
|
||||
}
|
||||
}
|
||||
?: throw RequestException("get images error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
dependencies {
|
||||
implementation(project(":edge-contracts"))
|
||||
|
||||
implementation(rootProject.libs.jackson.datatype.jsr)
|
||||
implementation(rootProject.libs.jackson.module.kotlin)
|
||||
implementation(rootProject.libs.springBoot.starter.validation)
|
||||
implementation(rootProject.libs.springCloud.starter.streamKafka)
|
||||
implementation(rootProject.libs.com.fasterxml.jackson.datatype.jackson.datatype.jsr310)
|
||||
implementation(rootProject.libs.com.fasterxml.jackson.module.jackson.module.kotlin)
|
||||
implementation(rootProject.libs.org.springframework.boot.spring.boot.starter.validation)
|
||||
implementation(rootProject.libs.org.springframework.cloud.spring.cloud.starter.stream.kafka)
|
||||
|
||||
testImplementation(rootProject.libs.springCloud.streamTestBinder)
|
||||
testImplementation(rootProject.libs.org.springframework.cloud.spring.cloud.stream.test.binder)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@ dependencies {
|
||||
implementation(project(":edge-contracts"))
|
||||
implementation(project(":core"))
|
||||
|
||||
implementation(rootProject.libs.springBoot.starter.web)
|
||||
implementation(rootProject.libs.springData.commons)
|
||||
implementation(rootProject.libs.org.springframework.boot.spring.boot.starter.web)
|
||||
implementation(rootProject.libs.org.springframework.data.spring.data.commons)
|
||||
}
|
||||
|
||||
77
entrypoint.sh
Executable file
77
entrypoint.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERBOSE=false
|
||||
while getopts "v" arg; do
|
||||
case $arg in
|
||||
v )
|
||||
VERBOSE=true
|
||||
;;
|
||||
* )
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Сдвигаем позиционные параметры после обработки опций
|
||||
shift $((OPTIND-1))
|
||||
JAR_FILE_NAME=$1
|
||||
|
||||
if [ -f /sys/fs/cgroup/memory/memory.limit_in_bytes ]
|
||||
then
|
||||
LIMITED_RAM_CONTAINER_CGROUP_SIZE_BYTES=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)
|
||||
if [ $VERBOSE = true ]; then echo "Cgroups v1 are used"; fi
|
||||
|
||||
elif [ -f /sys/fs/cgroup/memory.max ]
|
||||
then
|
||||
LIMITED_RAM_CONTAINER_CGROUP_SIZE_BYTES=$(cat /sys/fs/cgroup/memory.max)
|
||||
if [ $VERBOSE = true ]; then echo "Cgroups v2 are used"; fi
|
||||
else
|
||||
echo "No cgroups files with memory limits"; exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
LIMITED_RAM_CONTAINER_CGROUP_SIZE_MB=$((LIMITED_RAM_CONTAINER_CGROUP_SIZE_BYTES / 1024 / 1024))
|
||||
TOMCAT_THREADS_MAX=${TOMCAT_THREADS_MAX:-100}
|
||||
TOMCAT_THREADS_MIN=${TOMCAT_THREADS_MIN-$TOMCAT_THREADS_MAX}
|
||||
HIKARI_DB_MAXIMUM_POOL_SIZE=${HIKARI_DB_MAXIMUM_POOL_SIZE:-10}
|
||||
HIKARI_DB_MINIMUM_IDLE_SIZE=${HIKARI_DB_MINIMUM_IDLE_SIZE:-$HIKARI_DB_MAXIMUM_POOL_SIZE}
|
||||
JVM_NATIVE_MB=${JVM_NATIVE_MB:-120}
|
||||
STOCK_SIZE_MB=$((TOMCAT_THREADS_MAX / 2 + HIKARI_DB_MAXIMUM_POOL_SIZE + JVM_NATIVE_MB))
|
||||
LIMITED_MAXRAM_JAVA_SIZE_MB=$((LIMITED_RAM_CONTAINER_CGROUP_SIZE_MB - STOCK_SIZE_MB))
|
||||
#
|
||||
RESERVED_CODE_CACHE_SIZE_MB=${RESERVED_CODE_CACHE_SIZE_MB:-64}
|
||||
MAX_METASPACE_SIZE_MB=${MAX_METASPACE_SIZE_MB:-80}
|
||||
DIRECT_BYTES_BUFFERS_MB=${DIRECT_BYTES_BUFFERS_MB:-10}
|
||||
COMPRESSED_CLASS_SPACE_MB=${COMPRESSED_CLASS_SPACE_MB:-16}
|
||||
NON_HEAP_SIZE_MB=$((RESERVED_CODE_CACHE_SIZE_MB + MAX_METASPACE_SIZE_MB + DIRECT_BYTES_BUFFERS_MB + COMPRESSED_CLASS_SPACE_MB))
|
||||
#
|
||||
HEAP_GC_SIZE_MB=$((LIMITED_MAXRAM_JAVA_SIZE_MB - NON_HEAP_SIZE_MB))
|
||||
OVERHEAD_GC_SIZE_PERCENT=${OVERHEAD_GC_SIZE_PERCENT:-5}
|
||||
OVERHEAD_GC_SIZE_MB=$((HEAP_GC_SIZE_MB * OVERHEAD_GC_SIZE_PERCENT / 100))
|
||||
HEAP_SIZE_MB=$((HEAP_GC_SIZE_MB - OVERHEAD_GC_SIZE_MB))
|
||||
#
|
||||
MAX_RAM_PERCENTAGE=$((HEAP_SIZE_MB * 100 / LIMITED_MAXRAM_JAVA_SIZE_MB))
|
||||
|
||||
# export calculated environments
|
||||
export TOMCAT_THREADS_MAX=$TOMCAT_THREADS_MAX
|
||||
export TOMCAT_THREADS_MIN=$TOMCAT_THREADS_MIN
|
||||
export HIKARI_DB_MAXIMUM_POOL_SIZE=$HIKARI_DB_MAXIMUM_POOL_SIZE
|
||||
export HIKARI_DB_MINIMUM_IDLE_SIZE=$HIKARI_DB_MINIMUM_IDLE_SIZE
|
||||
|
||||
if [ $VERBOSE = true ]
|
||||
then
|
||||
echo "LIMITED_MAXRAM_JAVA_SIZE_MB=$LIMITED_MAXRAM_JAVA_SIZE_MB"
|
||||
echo "HEAP_SIZE_MB=$HEAP_SIZE_MB"
|
||||
echo "MAX_RAM_PERCENTAGE=$MAX_RAM_PERCENTAGE"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
exec java \
|
||||
-XX:+UseContainerSupport \
|
||||
-XX:+ExitOnOutOfMemoryError \
|
||||
-XX:MaxRAM="${LIMITED_MAXRAM_JAVA_SIZE_MB}m" \
|
||||
-XX:MaxRAMPercentage="$MAX_RAM_PERCENTAGE" \
|
||||
-XX:+SegmentedCodeCache \
|
||||
-XX:ReservedCodeCacheSize="${RESERVED_CODE_CACHE_SIZE_MB}m" \
|
||||
-XX:MaxMetaspaceSize="${MAX_METASPACE_SIZE_MB}m" \
|
||||
$JAVA_OPTS_OVERRIDE \
|
||||
-jar /app/"$JAR_FILE_NAME"
|
||||
@@ -7,50 +7,50 @@ spring-cloud = "4.1.5"
|
||||
testcontainers = "1.19.7"
|
||||
|
||||
[libraries]
|
||||
archUnit-junit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.4.1" }
|
||||
flyway-core = { module = "org.flywaydb:flyway-core", version = "9.22.3" }
|
||||
jackson-datatype-jsr = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" }
|
||||
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
|
||||
json-schema-validator = { module = "io.github.optimumcode:json-schema-validator", version = "0.2.3"}
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit5", version.ref = "kotlin" }
|
||||
kotlinx-serialization-json = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
|
||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor"}
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor"}
|
||||
ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor"}
|
||||
logback-encoder = { module = "net.logstash.logback:logstash-logback-encoder", version = "8.0" }
|
||||
micrometer-bridge-otel = { module = "io.micrometer:micrometer-tracing-bridge-otel"}
|
||||
micrometer-registry-prometheus = { module = "io.micrometer:micrometer-registry-prometheus" }
|
||||
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "5.4.0" }
|
||||
otel-exporter = { module = "io.opentelemetry:opentelemetry-exporter-otlp" }
|
||||
postgres = { module = "org.postgresql:postgresql", version = "42.7.5" }
|
||||
springFramework-context = { module = "org.springframework:spring-context"}
|
||||
springFramework-aspects = { module = "org.springframework:spring-aspects" }
|
||||
springBoot-devtools = { module = "org.springframework.boot:spring-boot-devtools" }
|
||||
springBoot-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "spring-boot" }
|
||||
springBoot-starter-actuatorAutoconfigure = { module = "org.springframework.boot:spring-boot-actuator-autoconfigure" }
|
||||
springBoot-starter-jdbc = { module = "org.springframework.boot:spring-boot-starter-data-jdbc", version.ref = "spring-boot"}
|
||||
springBoot-starter-mustache = { module = "org.springframework.boot:spring-boot-starter-mustache", version.ref = "spring-boot" }
|
||||
springBoot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "spring-boot" }
|
||||
springBoot-starter-validation = { module = "org.springframework.boot:spring-boot-starter-validation", version.ref = "spring-boot" }
|
||||
springBoot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" }
|
||||
springCloud-starter-streamKafka = { module = "org.springframework.cloud:spring-cloud-starter-stream-kafka", version.ref = "spring-cloud"}
|
||||
springCloud-stream = { module = "org.springframework.cloud:spring-cloud-stream", version.ref = "spring-cloud"}
|
||||
springCloud-streamTestBinder = { module = "org.springframework.cloud:spring-cloud-stream-test-binder", version.ref = "spring-cloud"}
|
||||
springData-commons = { module = "org.springframework.data:spring-data-commons", version.ref = "spring-boot" }
|
||||
springDoc-openapi-starter = "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0"
|
||||
testcontainers = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers"}
|
||||
testcontainers-junit-jupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers"}
|
||||
testcontainers-postgresql = { module = "org.testcontainers:postgresql", version.ref = "testcontainers"}
|
||||
com-fasterxml-jackson-datatype-jackson_datatype_jsr310 = { group = "com.fasterxml.jackson.datatype", name = "jackson-datatype-jsr310", version.ref = "jackson" }
|
||||
com-fasterxml-jackson-module-jackson_module_kotlin = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version.ref = "jackson" }
|
||||
com-tngtech-archunit-archunit_junit5 = { group = "com.tngtech.archunit", name = "archunit-junit5", version = "1.4.1" }
|
||||
io-github-optimumcode-json_schema_validator = { group = "io.github.optimumcode", name = "json-schema-validator", version = "0.5.2" }
|
||||
io-ktor-ktor_client_cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" }
|
||||
io-ktor-ktor_client_core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
|
||||
io-ktor-ktor_client_mock = { group = "io.ktor", name = "ktor-client-mock", version.ref = "ktor" }
|
||||
io-micrometer-micrometer_registry_prometheus = { group = "io.micrometer", name = "micrometer-registry-prometheus" }
|
||||
io-micrometer-micrometer_tracing_bridge_otel = { group = "io.micrometer", name = "micrometer-tracing-bridge-otel" }
|
||||
io-opentelemetry-opentelemetry_exporter_otlp = { group = "io.opentelemetry", name = "opentelemetry-exporter-otlp" }
|
||||
net-logstash-logback-logstash_logback_encoder = { group = "net.logstash.logback", name = "logstash-logback-encoder", version = "8.0" }
|
||||
org-flywaydb-flyway_core = { group = "org.flywaydb", name = "flyway-core", version = "9.22.3" }
|
||||
org-jetbrains-kotlin-kotlin_reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
|
||||
org-jetbrains-kotlin-kotlin_test_junit5 = { group = "org.jetbrains.kotlin", name = "kotlin-test-junit5", version.ref = "kotlin" }
|
||||
org-jetbrains-kotlinx-kotlinx_serialization_json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version = "1.6.3" }
|
||||
org-mockito-kotlin-mockito_kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version = "5.4.0" }
|
||||
org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.5" }
|
||||
org-springdoc-springdoc_openapi_starter_webmvc_ui = { group = "org.springdoc", name = "springdoc-openapi-starter-webmvc-ui", version = "2.6.0" }
|
||||
org-springframework-boot-spring_boot_devtools = { group = "org.springframework.boot", name = "spring-boot-devtools" }
|
||||
org-springframework-boot-spring_boot_starter_actuator = { group = "org.springframework.boot", name = "spring-boot-starter-actuator", version.ref = "spring-boot" }
|
||||
org-springframework-boot-spring_boot_starter_actuator_autoconfigure = { group = "org.springframework.boot", name = "spring-boot-actuator-autoconfigure" }
|
||||
org-springframework-boot-spring_boot_starter_data_jdbc = { group = "org.springframework.boot", name = "spring-boot-starter-data-jdbc", version.ref = "spring-boot" }
|
||||
org-springframework-boot-spring_boot_starter_mustache = { group = "org.springframework.boot", name = "spring-boot-starter-mustache", version.ref = "spring-boot"}
|
||||
org-springframework-boot-spring_boot_starter_test = { group = "org.springframework.boot", name = "spring-boot-starter-test", version.ref = "spring-boot"}
|
||||
org-springframework-boot-spring_boot_starter_validation = { group = "org.springframework.boot", name = "spring-boot-starter-validation", version.ref = "spring-boot"}
|
||||
org-springframework-boot-spring_boot_starter_web = { group = "org.springframework.boot", name = "spring-boot-starter-web", version.ref = "spring-boot"}
|
||||
org-springframework-cloud-spring_cloud_starter_stream_kafka = { group = "org.springframework.cloud", name = "spring-cloud-starter-stream-kafka", version.ref = "spring-cloud"}
|
||||
org-springframework-cloud-spring_cloud_stream = { group = "org.springframework.cloud", name = "spring-cloud-stream", version.ref = "spring-cloud" }
|
||||
org-springframework-cloud-spring_cloud_stream_test_binder = { group = "org.springframework.cloud", name = "spring-cloud-stream-test-binder", version.ref = "spring-cloud" }
|
||||
org-springframework-data-spring_data_commons = { group = "org.springframework.data", name = "spring-data-commons", version.ref = "spring-boot" }
|
||||
org-springframework-spring_aspects = { group = "org.springframework", name = "spring-aspects" }
|
||||
org-springframework-spring_context = { group = "org.springframework", name = "spring-context"}
|
||||
org-testcontainers-junit_jupiter = { group = "org.testcontainers", name = "junit-jupiter", version.ref = "testcontainers" }
|
||||
org-testcontainers-postgresql = { group = "org.testcontainers", name = "postgresql", version.ref = "testcontainers" }
|
||||
org-testcontainers-testcontainers = { group = "org.testcontainers", name = "testcontainers", version.ref = "testcontainers" }
|
||||
|
||||
[bundles]
|
||||
tracing = ["micrometer-bridge-otel", "otel-exporter"]
|
||||
tracing = ["io-micrometer-micrometer_tracing_bridge_otel", "io-opentelemetry-opentelemetry_exporter_otlp"]
|
||||
|
||||
[plugins]
|
||||
kotlin-kover = { id = "org.jetbrains.kotlinx.kover", version = "0.8.3" }
|
||||
kotlin-jpa = { id = "org.jetbrains.kotlin.plugin.jpa", version.ref = "kotlin" }
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
kotlin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin" }
|
||||
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
|
||||
spring-dependencyManagement = { id = "io.spring.dependency-management", version = "1.1.7"}
|
||||
io-spring-dependency-management = { id = "io.spring.dependency-management", version = "1.1.7" }
|
||||
org-jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
org-jetbrains-kotlin-plugin-jpa = { id = "org.jetbrains.kotlin.plugin.jpa", version.ref = "kotlin" }
|
||||
org-jetbrains-kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
org-jetbrains-kotlin-plugin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin" }
|
||||
org-jetbrains-kotlinx-kover = { id = "org.jetbrains.kotlinx.kover", version = "0.8.3" }
|
||||
org-springframework-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
|
||||
|
||||
@@ -31,7 +31,7 @@ Demo приложение для изучения языка `kotlin` и фре
|
||||
* убедиться, что все запущенные контейнеры будут видеть контейнер с приложением (например, добавить везде сеть `spring-boot-demo_default`)
|
||||
* скопировать [.env.example](/.env.example) в [.env](/.env) и изменить конфигурацию
|
||||
|
||||
Перед каждым запуском необходимо собрать приложение:
|
||||
После каждого изменения в исходный код необходимо собрать приложение:
|
||||
```shell
|
||||
./gradlew assemble
|
||||
```
|
||||
|
||||
@@ -9,6 +9,8 @@ spring:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
hikari:
|
||||
schema: ${DB_SCHEMA:public}
|
||||
maximum-pool-size: ${HIKARI_DB_MAXIMUM_POOL_SIZE}
|
||||
minimum-idle: ${HIKARI_DB_MINIMUM_IDLE_SIZE}
|
||||
flyway: #flyway automatically uses the datasource from the application to connect to the DB
|
||||
enabled: true # enables flyway database migration
|
||||
locations: classpath:db/migration/structure, classpath:db/migration/data # the location where flyway should look for migration scripts
|
||||
@@ -98,6 +100,12 @@ management:
|
||||
sampling:
|
||||
probability: 1.0
|
||||
|
||||
server:
|
||||
tomcat:
|
||||
threads:
|
||||
max: ${TOMCAT_THREADS_MAX}
|
||||
min-spare: ${TOMCAT_THREADS_MIN}
|
||||
|
||||
tracing:
|
||||
url: ${OTLP_TRACING_HTTP_URL}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user