Когда вы впервые сталкиваетесь с задачей деплоя, процесс может показаться сложным и пугающим. Докер-образы, безопасность, container registry, а тем более Kubernetes — для новичка это настоящая головная боль. Именно поэтому наши партнеры из Amplicode решили написать статью, которая поможет вам максимально просто и быстро задеплоить ваше первое Spring-приложение в облако.
Если вам удобнее смотреть, а не читать — вы можете ознакомиться с этим материалом в видео-формате.
❯ Описание приложения
Наше приложение — это стандартный пример Spring Petclinic, используемый для демонстрации возможностей Spring Boot. Помимо самого приложения нам также понадобятся два внешних сервиса: база данных PostgreSQL и брокер сообщений Kafka. Конечно, мы могли бы воспользоваться готовыми облачными сервисами, получив простоту настройки и быстрый старт. Однако сегодня мы пойдем другим путем: развернем все сервисы самостоятельно через Docker Compose.

❯ Контейнеризация Spring Boot приложения
Первый шаг — это создание файла docker-compose.yml:

В этот файл мы добавляем наше Spring Boot приложение, указываем параметры запуска и экспоузим необходимые порты. Современные IDE, а также плагины для них позволяют это сделать довольно просто. Воспользуемся действиями от Amplicode:

Сгенерированные файлы
services: spring-petclinic: image: org.springframework.samples.spring-petclinic:latest build: context: ../.. dockerfile: existing-spring-boot-app-modification/spring-petclinic-main/Dockerfile args: DOCKER_BUILDKIT: 1 restart: "no" ports: - "8080:8080" healthcheck: test: wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1 interval: 30s timeout: 5s start_period: 30s retries: 5 labels: amplicode.image: springboot
FROM gradle:9.0.0 AS builder WORKDIR /application COPY . . RUN --mount=type=cache,target=/root/.gradle gradle clean :org.springframework.samples.spring-petclinic:build -x test FROM bellsoft/liberica-openjre-alpine:23 AS layers WORKDIR /application COPY --from=builder /application/existing-spring-boot-app-modification/spring-petclinic-main/build/libs/*.jar app.jar RUN java -Djarmode=layertools -jar app.jar extract FROM bellsoft/liberica-openjre-alpine:23 VOLUME /tmp RUN adduser -S spring-user USER spring-user WORKDIR /application COPY --from=layers /application/dependencies/ ./ COPY --from=layers /application/spring-boot-loader/ ./ COPY --from=layers /application/snapshot-dependencies/ ./ COPY --from=layers /application/application/ ./ ENV JAVA_RESERVED_CODE_CACHE_SIZE="240M" ENV JAVA_MAX_DIRECT_MEMORY_SIZE="10M" ENV JAVA_MAX_METASPACE_SIZE="179M" ENV JAVA_XSS="1M" ENV JAVA_XMX="345M" ENV JAVA_ERROR_FILE_OPTS="-XX:ErrorFile=/tmp/java_error.log" ENV JAVA_HEAP_DUMP_OPTS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp" ENV JAVA_ON_OUT_OF_MEMORY_OPTS="-XX:+CrashOnOutOfMemoryError" ENV JAVA_NATIVE_MEMORY_TRACKING_OPTS="-XX:NativeMemoryTracking=summary -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics" ENV JAVA_GC_LOG_OPTS="-Xlog:gc*,safepoint:/tmp/gc.log::filecount=10,filesize=100M" ENV JAVA_FLIGHT_RECORDING_OPTS="-XX:StartFlightRecording=disk=true,dumponexit=true,filename=/tmp/,maxsize=10g,maxage=24h" ENV JAVA_JMX_REMOTE_OPTS="-Djava.rmi.server.hostname=127.0.0.1 \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -Dcom.sun.management.jmxremote.port=5005 \ -Dcom.sun.management.jmxremote.rmi.port=5005" ENTRYPOINT java \ -XX:ReservedCodeCacheSize=$JAVA_RESERVED_CODE_CACHE_SIZE \ -XX:MaxDirectMemorySize=$JAVA_MAX_DIRECT_MEMORY_SIZE \ -XX:MaxMetaspaceSize=$JAVA_MAX_METASPACE_SIZE \ -Xss$JAVA_XSS \ -Xmx$JAVA_XMX \ $JAVA_HEAP_DUMP_OPTS \ $JAVA_ON_OUT_OF_MEMORY_OPTS \ $JAVA_ERROR_FILE_OPTS \ $JAVA_NATIVE_MEMORY_TRACKING_OPTS \ $JAVA_GC_LOG_OPTS \ $JAVA_FLIGHT_RECORDING_OPTS \ $JAVA_JMX_REMOTE_OPTS \ org.springframework.boot.loader.JarLauncher
Обратите внимание, что в процессе создания сервиса для compose, мы сгенерировали и настроили Dockerfile согласно лучшим практикам написания подобных файлов для продакшена. Однако если у нас уже есть Dockerfile мы могли выбрать его:

Или даже уже собранный образ приложения:

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

Также заранее настраиваем инструменты для анализа и отладки: heap dump, GC-логи, Java Flight Recorder (JFR) и JMX. Эти инструменты помогут нам эффективно диагностировать проблемы в будущем (если вдруг когда они появятся).

Важный нюанс: по умолчанию я использую временные директории (например, /tmp), которые очищаются после перезапуска контейнера или виртуальной машины. Для продакшн-среды рекомендую подключить постоянный volume или сетевой диск.
❯ Создание PostgreSQL и Kafka сервисов для Docker Compose
Помимо приложения, в docker-compose.yml объявляем сервисы PostgreSQL и Kafka. В продакшн-среде не рекомендуется экспоузить порты этих сервисов напрямую наружу — достаточно, чтобы доступ к ним имело только ваше приложение.

Сгенерированные сервисы
services: postgres: image: postgres:17.5 restart: "no" volumes: - postgres_data:/var/lib/postgresql/data environment: POSTGRES_USER: root POSTGRES_PASSWORD: root POSTGRES_DB: spring-petclinic healthcheck: test: pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB interval: 10s timeout: 5s start_period: 10s retries: 5 kafka: image: confluentinc/cp-kafka:8.0.0 restart: "no" volumes: - kafka_data:/var/lib/kafka/data environment: KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT,CONTROLLER:PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_NODE_ID: 1 CLUSTER_ID: koa_uLJGTQe-qKkjpbagQg KAFKA_PROCESS_ROLES: controller,broker KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093 KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://0.0.0.0:9092,CONTROLLER://kafka:9093 healthcheck: test: kafka-topics --bootstrap-server localhost:9092 --list interval: 10s timeout: 5s start_period: 30s retries: 5 labels: amplicode.image: confluent/kafka volumes: postgres_data: kafka_data:
❯ Дополнительная конфигурация Spring Boot приложения
Чтобы наше приложение корректно работало в Docker-контейнере и могло гибко принимать параметры извне, необходимо внести небольшие изменения в настройки самого приложения. В частности, значения, такие как URL подключения к базе данных PostgreSQL, логин и пароль, а также адрес брокера Kafka, мы вынесем в переменные окружения. Это легко реализовать с помощью функции «Wrap properties into» от Amplicode, которая автоматически заменит статичные значения в файле свойств (application.properties) на переменные окружения.

Затем нам останется только передать эти переменные в Docker Compose сервис нашего приложения.

❯ Разворачиваем приложение в облаке
После того, как Dockerfile и docker-compose файл готовы, коммитим весь код в удаленный репозиторий. Например, в GitFlic. Затем переходим к облачной инфраструктуре. Я использую виртуальную машину в Timeweb Cloud, выбирая готовый образ с установленными Docker и Git, чтобы не тратить лишнее время на настройку окружения.

Все остальные настройки оставляю по умолчанию. После создания виртуальной машины подключаюсь к ней по SSH:

Остается только клонировать репозиторий и запустить приложение командой docker-compose up -d:

Проверяем приложение на публичном ip.

Создадим несколько новых записей, и убедимся, что в логах виднеется корректная работа самого приложения и его взаимодействия со сторонними сервисами.

Всё работает великолепно!
❯ Итог
Конечно, такой подход далек от идеального продакшена, однако он отлично подходит для быстрого старта. С его помощью вы сможете на практике разобраться в основах деплоя и понять, как устроены докер-контейнеры и запуск приложений в облаке. В следующей статье мы рассмотрим более «взрослый» способ деплоя — с использованием Kubernetes.
Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале ↩
ссылка на оригинал статьи https://habr.com/ru/articles/936148/
Добавить комментарий