Java Spring: От идеи до деплоя в Yandex Cloud

Практический курс по разработке полноценного backend-приложения на Spring Boot. Вы пройдете путь от настройки окружения и работы с базами данных до интеграции брокеров сообщений и финального деплоя в облако.

1. Инициализация проекта Spring Boot, архитектура приложения и создание первого REST контроллера

Введение в курс: Java Spring от идеи до деплоя

Добро пожаловать на курс, который превратит вас из теоретика в практика. Мы не будем изучать абстрактные концепции в вакууме. Вместо этого мы пройдем путь создания реального продукта — системы управления задачами (Task Tracker). Мы начнем с пустой папки и закончим работающим приложением, развернутым в облаке Yandex Cloud.

В этой первой статье мы заложим фундамент: создадим каркас приложения, разберемся с его структурой и научим наш сервер отвечать на первое приветствие.

Что такое Spring Boot и зачем он нам?

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

Однако «чистый» Spring требует много ручной настройки. Вам нужно объяснять системе каждый шаг: как подключаться к базе данных, как обрабатывать веб-запросы и так далее. Здесь на сцену выходит Spring Boot.

Spring Boot — это расширение фреймворка Spring, которое следует философии Convention over Configuration (соглашение важнее конфигурации). Он говорит: «Я вижу, ты подключил библиотеку для работы с вебом. Наверное, тебе нужен веб-сервер? Я запущу его для тебя на порту 8080. Не благодари».

> Spring Boot делает разработку на Java быстрой, убирая необходимость писать сотни строк шаблонного кода настройки.

Шаг 1: Инициализация проекта (Spring Initializr)

Самый простой способ начать — использовать Spring Initializr. Это веб-инструмент, который генерирует архив с готовой структурой проекта.

!Скриншот конфигуратора Spring Initializr с выбранными настройками для создания веб-проекта

Инструкция по созданию:

  • Перейдите на сайт Spring Initializr.
  • Project: Выберите Maven. Это система сборки, которая будет управлять библиотеками (зависимостями) нашего проекта.
  • Language: Выберите Java.
  • Spring Boot: Выберите последнюю стабильную версию (без слов SNAPSHOT или M1).
  • Project Metadata:
  • * Group: ru.yandex.tracker (или ваш домен в обратном порядке). * Artifact: task-tracker (название нашего приложения). * Name: task-tracker. * Package name: сформируется автоматически. * Packaging: Jar. * Java: 17 или 21 (в зависимости от того, какая версия установлена у вас, но 17 — золотой стандарт LTS).
  • Dependencies (Зависимости): Нажмите кнопку ADD DEPENDENCIES и выберите:
  • * Spring Web: Ключевая зависимость. Она включает в себя веб-сервер Tomcat и библиотеки для создания REST API.
  • Нажмите GENERATE. Скачается ZIP-архив.
  • Распакуйте архив в удобную папку и откройте её через вашу IDE (IntelliJ IDEA, Eclipse или VS Code).

    Шаг 2: Структура проекта и точка входа

    Когда вы откроете проект, вы увидите стандартную структуру Maven-проекта. Давайте разберем, что здесь важно.

    Основные файлы и папки

    * pom.xml: Это «паспорт» вашего проекта. Здесь описано, как называется приложение, какая версия Java используется и какие библиотеки (dependencies) подключены. Если вы захотите добавить базу данных позже, вы пропишете её именно сюда. * src/main/java: Здесь живет весь ваш исходный код. * src/main/resources: Место для конфигураций (например, настройки подключения к БД) и статических файлов. * src/test/java: Папка для тестов.

    Класс Application

    Найдите файл TaskTrackerApplication.java (название зависит от того, что вы ввели в поле Artifact). Он выглядит примерно так:

    Это сердце вашего приложения. Аннотация @SpringBootApplication — это магический маркер. Она говорит Spring Boot: «Это главное приложение. Пожалуйста, просканируй все файлы в этой папке и подпапках, найди настройки и запусти всё, что нужно».

    Метод main запускает встроенный веб-сервер Tomcat. Вам не нужно устанавливать сервер отдельно — он уже внутри вашего .jar файла.

    Архитектура приложения: Слои

    Прежде чем писать код, давайте договоримся, куда мы будем его писать. Новички часто пишут всю логику прямо в контроллере или вообще в одном классе. Это плохая практика. В профессиональной разработке используется слоистая архитектура.

    !Диаграмма, показывающая поток данных от клиента через контроллер, сервис и репозиторий к базе данных

    Мы будем придерживаться следующего разделения:

  • Controller (Контроллер):
  • * Задача: Принять HTTP-запрос от пользователя, проверить входные данные, передать их сервису и вернуть ответ (JSON). * Аналогия: Официант в ресторане. Он принимает заказ, передает его на кухню и приносит еду. Он не готовит еду сам.
  • Service (Сервис):
  • * Задача: Вся бизнес-логика. Здесь происходят вычисления, проверки правил, сложные операции. * Аналогия: Повар на кухне. Он знает рецепты и готовит блюдо.
  • Repository (Репозиторий):
  • * Задача: Работа с базой данных (сохранение, чтение, удаление). * Аналогия: Кладовщик. Он знает, где лежат продукты, и выдает их повару.

    В этой статье мы создадим только первый слой — Controller, чтобы проверить работоспособность системы.

    Шаг 3: Создание первого REST контроллера

    Давайте создадим простую «ручку» (endpoint), которая будет приветствовать нас. В терминологии REST это будет GET-запрос.

  • В папке, где лежит TaskTrackerApplication.java, создайте новый пакет (папку) с названием controller.
  • Внутри создайте Java-класс HelloController.
  • Напишем следующий код:

    Разбор кода

    * @RestController: Эта аннотация говорит Spring, что данный класс — это веб-контроллер, и ответы его методов должны быть записаны прямо в тело HTTP-ответа (обычно в формате JSON или простого текста), а не рендерить HTML-страницу. * @GetMapping("/hello"): Мы связываем URL-адрес /hello с методом sayHello. Когда на сервер придет GET-запрос по этому адресу, выполнится этот метод. * @RequestParam: Эта аннотация позволяет извлекать параметры из строки запроса (например, ?name=Ivan). Если параметр не передан, используется значение по умолчанию (`defaultValue =

    2. Работа с данными: подключение PostgreSQL, сущности JPA и реализация CRUD операций

    Работа с данными: подключение PostgreSQL, сущности JPA и реализация CRUD операций

    В предыдущей статье мы создали каркас приложения и научили его отвечать на простой GET-запрос. Но наше приложение пока страдает «амнезией»: любые данные, которые мы могли бы сохранить в переменных, исчезают после перезапуска сервера. Чтобы создать полноценный Task Tracker, нам нужна долговременная память — база данных.

    В этой статье мы подключим профессиональную базу данных PostgreSQL, познакомимся с магией Spring Data JPA и реализуем полный цикл управления задачами: создание, чтение, обновление и удаление (CRUD).

    Подготовка окружения: Docker и PostgreSQL

    Мы не будем устанавливать PostgreSQL прямо в операционную систему. Это «загрязняет» компьютер и усложняет настройку. Вместо этого мы используем Docker. Это стандарт индустрии, позволяющий запускать сервисы в изолированных контейнерах.

    В корне вашего проекта создайте файл docker-compose.yml со следующим содержимым:

    Запустите базу данных командой в терминале (из папки проекта):

    Теперь у нас есть работающая база данных PostgreSQL, доступная на порту 5432.

    Шаг 1: Добавление зависимостей

    Чтобы Java-приложение могло общаться с базой данных, нам нужны драйверы и ORM-фреймворк. Откройте файл pom.xml и добавьте в секцию <dependencies> два новых блока:

    После добавления обязательно обновите Maven-проект (кнопка с иконкой обновления в вашей IDE).

    Шаг 2: Настройка подключения

    Теперь нужно «познакомить» Spring Boot с нашей базой данных. Откройте файл src/main/resources/application.properties и добавьте настройки:

    Шаг 3: Создание сущности (Entity)

    В мире Java мы работаем с объектами (классами), а в базе данных — с таблицами. Чтобы не писать SQL-запросы вручную для каждого поля, используется технология ORM (Object-Relational Mapping). В Spring за это отвечает спецификация JPA (Java Persistence API), а самой популярной реализацией является Hibernate.

    !Визуализация того, как ORM связывает Java-класс с таблицей базы данных.

    Создадим пакет model и в нем класс Task:

    Шаг 4: Репозиторий — доступ к данным

    Здесь начинается магия Spring Data. Нам не нужно писать SQL-запросы SELECT * FROM tasks. Нам достаточно создать интерфейс.

    Создайте пакет repository и интерфейс TaskRepository:

    Наследуясь от JpaRepository, мы получаем готовый набор методов для работы с БД. Spring сам создаст реализацию этого интерфейса при запуске.

    Шаг 5: Реализация CRUD в Контроллере

    Теперь объединим всё в контроллере. Мы пропустим слой Service для простоты примера, но в большом проекте логику лучше выносить туда.

    Создайте (или обновите) TaskController в пакете controller:

    Разбор аннотаций:

    * @RequestBody: Говорит Spring взять JSON из тела запроса и превратить его в Java-объект Task. * @PathVariable: Извлекает переменную из пути URL (например, ID из /tasks/5). * taskRepository.save(): Если у объекта нет ID, он создает новую запись. Если ID есть — обновляет существующую.

    Проверка работы

    Запустите приложение. Теперь вы можете использовать Postman или curl для проверки.

    Пример создания задачи: POST запрос на http://localhost:8080/tasks Body (JSON):

    В ответ вы получите созданный объект с присвоенным id.

    Заключение

    Мы сделали огромный шаг вперед. Наше приложение теперь имеет состояние. Мы подключили PostgreSQL, описали структуру данных через JPA-сущности и реализовали полноценный API для управления задачами. В следующей статье мы займемся валидацией данных, чтобы пользователи не могли создавать задачи без названия, и обработкой ошибок.

    3. Бизнес-логика и безопасность: внедрение Spring Security и аутентификация через JWT токены

    Бизнес-логика и безопасность: внедрение Spring Security и аутентификация через JWT токены

    В предыдущих статьях мы построили фундамент нашего Task Tracker: создали проект, подключили базу данных PostgreSQL и научились сохранять задачи. Однако сейчас наше приложение похоже на дом с открытыми дверями: любой желающий может зайти, прочитать ваши задачи, изменить их или даже удалить. В реальном мире это недопустимо.

    Сегодня мы займемся безопасностью. Мы превратим наш открытый API в защищенную крепость, используя Spring Security и стандарт JWT (JSON Web Token). Мы научим приложение различать пользователей и проверять их права доступа.

    Аутентификация и Авторизация: в чем разница?

    Прежде чем писать код, важно разобраться в терминологии. Эти два понятия часто путают, но они отвечают за разные вещи.

  • Аутентификация (Authentication) — это ответ на вопрос «Кто ты?». Это процесс проверки личности пользователя (обычно через логин и пароль).
  • Авторизация (Authorization) — это ответ на вопрос «Что тебе можно делать?». Это проверка прав доступа уже аутентифицированного пользователя к конкретному ресурсу.
  • !Визуальное различие между проверкой личности и проверкой прав доступа.

    В нашем приложении мы реализуем оба механизма.

    Что такое JWT и зачем он нам?

    Классические веб-приложения используют сессии (Session ID), которые хранятся на сервере. Но для REST API, который мы строим, это неудобно, особенно если мы планируем масштабироваться в облаке (Yandex Cloud). Нам нужен Stateless подход — когда сервер не запоминает состояние пользователя между запросами.

    Здесь на сцену выходит JWT (JSON Web Token). Это стандарт передачи данных в зашифрованном виде.

    Токен выглядит как длинная строка xxxxx.yyyyy.zzzzz и состоит из трех частей:

  • Header (Заголовок): Тип токена и алгоритм шифрования.
  • Payload (Полезная нагрузка): Данные пользователя (например, ID, имя, роль). Не храните здесь пароли!
  • Signature (Подпись): Секретная часть, которая гарантирует, что токен не был изменен злоумышленниками.
  • Логика работы проста: пользователь вводит логин/пароль сервер проверяет их и выдает токен пользователь прикрепляет этот токен к каждому следующему запросу.

    Шаг 1: Подключение зависимостей

    Откройте pom.xml. Нам понадобятся Spring Security и библиотека для работы с JWT.

    После добавления зависимостей и перезагрузки Maven, если вы запустите приложение, вы увидите, что все запросы теперь требуют пароль. Это стандартное поведение Spring Security.

    Шаг 2: Создание сущности User

    Нам нужно где-то хранить пользователей. Создадим класс User в пакете model.

    Также создайте репозиторий UserRepository в пакете repository:

    Шаг 3: Настройка UserDetails

    Spring Security не знает про наш класс User. Ему нужен объект, реализующий интерфейс UserDetails. Создадим адаптер.

    В пакете security (создайте его) создайте класс UserDetailsImpl:

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

    Шаг 4: Утилита для работы с JWT

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

    В application.properties добавьте секретный ключ и время жизни токена:

    Код JwtCore:

    Шаг 5: Фильтр запросов

    Самая важная часть. Нам нужен фильтр, который будет перехватывать каждый HTTP-запрос, доставать из него токен, проверять его и, если все ок, говорить Spring Security: «Этот пользователь авторизован».

    [VISUALIZATION: Диаграмма потока данных (Pipeline). Запрос летит к контроллеру, но на пути стоит стена (Security Filter Chain). В стене есть дверь (TokenFilter), которая проверяет пропуск (JWT) и пропускает запрос дальше.]

    Создайте TokenFilter:

    Шаг 6: Конфигурация безопасности

    Теперь соберем все вместе в классе конфигурации. В Spring Boot 3.x и Spring Security 6.x это делается через бины.

    Создайте SecurityConfigurator:

    Важные моменты: * BCryptPasswordEncoder: Мы никогда не храним пароли в открытом виде. Мы их хешируем. requestMatchers("/auth/*").permitAll(): Мы открываем доступ к регистрации и входу, иначе никто не сможет получить токен. * SessionCreationPolicy.STATELESS: Мы говорим Spring не создавать сессии.

    Шаг 7: Контроллер Аутентификации

    Последний штрих — создать ручки для регистрации и входа. Создайте SecurityController в пакете controller.

    Вам понадобятся DTO (Data Transfer Objects) для запросов. Создайте простые классы SignupRequest (username, email, password) и SigninRequest (username, password).

    Проверка работы

    Теперь наше приложение защищено. Попробуйте сделать GET запрос к /tasks — вы получите ошибку 401 Unauthorized.

    Чтобы получить доступ:

  • Отправьте POST на /auth/signup с JSON { "username": "admin", "email": "admin@ya.ru", "password": "12345" }.
  • Отправьте POST на /auth/signin с теми же данными. В ответ придет длинная строка — это ваш токен.
  • Скопируйте токен.
  • Сделайте GET запрос к /tasks, добавив заголовок:
  • * Key: Authorization * Value: Bearer <ваш_токен>

    Поздравляю! Вы внедрили профессиональную систему безопасности в ваш проект. В следующей статье мы подготовим наше приложение к деплою и упакуем его в Docker-контейнер для отправки в облако.

    4. Асинхронное взаимодействие: подключение брокера очередей Kafka и настройка фоновых задач

    Асинхронное взаимодействие: подключение брокера очередей Kafka и настройка фоновых задач

    В предыдущих статьях мы проделали большой путь: создали REST API, подключили базу данных PostgreSQL и защитили приложение с помощью JWT-токенов. Наш Task Tracker работает, данные сохраняются, а посторонние не могут получить к ним доступ.

    Однако, по мере роста приложения мы сталкиваемся с новой проблемой — производительностью при выполнении «тяжелых» операций. Представьте, что при создании задачи мы хотим отправлять пользователю email-уведомление, генерировать PDF-отчет или отправлять данные в систему аналитики. Если делать это в том же потоке, где обрабатывается HTTP-запрос, пользователь будет ждать ответа несколько секунд. Это плохой пользовательский опыт (UX).

    Решение — асинхронность. Мы должны сказать пользователю «Заявка принята», а тяжелую работу выполнить в фоне. Для этого нам понадобится брокер сообщений Apache Kafka.

    Синхронное vs Асинхронное взаимодействие

    Давайте разберем разницу на примере ресторана.

  • Синхронный подход: Вы делаете заказ официанту. Официант идет на кухню, сам надевает фартук, готовит еду, ждет, пока она сварится, и только потом приносит её вам. Всё это время он недоступен для других клиентов.
  • Асинхронный подход: Вы делаете заказ. Официант записывает его на листочек, вешает на специальную доску (брокер сообщений) и тут же возвращается к вам с улыбкой: «Заказ принят, скоро будет готово». Повара на кухне (фоновые воркеры) видят заказ на доске и начинают готовить его в своем темпе.
  • !Сравнение блокирующего синхронного выполнения и неблокирующего асинхронного через очередь.

    В нашем случае «доской» для заказов будет Apache Kafka.

    Что такое Apache Kafka?

    Apache Kafka — это распределенный брокер сообщений. Это не просто очередь, где сообщение исчезает после прочтения. Это скорее журнал событий (log), который хранит историю.

    Основные понятия Kafka:

    * Producer (Продюсер): Тот, кто отправляет сообщения (наше Spring-приложение при создании задачи). * Consumer (Консумер): Тот, кто читает сообщения и обрабатывает их (наш сервис уведомлений). * Topic (Топик): Тематический канал, куда попадают сообщения. Например, task-created-events. * Broker (Брокер): Сам сервер Kafka, который хранит данные.

    Шаг 1: Обновление инфраструктуры (Docker)

    Kafka — сложная система. Для её работы часто требуется координатор Zookeeper (хотя новые версии Kafka умеют работать без него, классический подход с Zookeeper всё еще стандарт для обучения). Добавим их в наш docker-compose.yml.

    Откройте файл docker-compose.yml и добавьте новые сервисы к уже существующему postgres:

    Перезапустите контейнеры:

    Теперь у нас запущены PostgreSQL, Zookeeper и Kafka.

    Шаг 2: Подключение зависимостей Spring Kafka

    Spring Boot имеет отличную интеграцию с Kafka. Нам нужно добавить всего одну зависимость в pom.xml:

    Не забудьте обновить Maven-проект.

    Шаг 3: Настройка Kafka в приложении

    Добавим настройки подключения в src/main/resources/application.properties:

    Шаг 4: Создание события (Event)

    В архитектуре, управляемой событиями (Event-Driven), сервисы общаются не сущностями базы данных, а специальными объектами-событиями (DTO). Это позволяет отвязать структуру БД от сообщений.

    Создайте пакет event и класс TaskCreatedEvent:

    Мы будем отправлять этот объект в Kafka каждый раз, когда создается новая задача.

    Шаг 5: Реализация Producer (Отправка сообщений)

    Теперь модифицируем наш TaskController. Мы внедрим в него KafkaTemplate — инструмент Spring для отправки сообщений.

    Откройте TaskController.java и внесите изменения:

    Теперь, когда пользователь создает задачу, контроллер сохраняет её в БД и «кидает» сообщение в Kafka. Контроллер не ждет, пока отправится email, он сразу возвращает ответ пользователю.

    Шаг 6: Реализация Consumer (Обработка сообщений)

    Кто-то должен прочитать это сообщение и выполнить работу. Создадим сервис-слушатель.

    Создайте пакет service и класс NotificationService:

    Аннотация @KafkaListener — это магия Spring. Она говорит: «Подпишись на топик task-created-topic и, как только там появится сообщение, преобразуй его в TaskCreatedEvent и запусти этот метод».

    !Поток данных: от HTTP запроса до фоновой обработки через Kafka.

    Проверка работы

  • Запустите приложение.
  • Отправьте POST-запрос на создание задачи (через Postman или curl, не забудьте про JWT токен из прошлой статьи).
  • Сразу же посмотрите на время ответа в Postman. Оно должно быть очень коротким (например, 50-100 мс), несмотря на то, что в коде мы написали Thread.sleep(3000).
  • Посмотрите в консоль (логи) вашего приложения.
  • Вы увидите примерно следующее:

    Это доказывает, что отправка email произошла в фоновом режиме и не заблокировала пользователя.

    Зачем нам это в Yandex Cloud?

    В облачной архитектуре сервисы часто разделены. Один микросервис отвечает за задачи, другой — за уведомления, третий — за отчеты. Kafka служит «клеем», который соединяет эти сервисы надежно. Если сервис уведомлений упадет, сообщения не пропадут — они останутся в Kafka и будут обработаны, как только сервис снова поднимется. Это называется Fault Tolerance (отказоустойчивость).

    Заключение

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

    В следующей, финальной статье, мы упакуем наше приложение в Docker-контейнер и выполним деплой на виртуальную машину в Yandex Cloud, сделав наш Task Tracker доступным всему миру.

    5. Подготовка к продакшену: контейнеризация в Docker и деплой приложения в Yandex Cloud

    Подготовка к продакшену: контейнеризация в Docker и деплой приложения в Yandex Cloud

    Поздравляю! Вы прошли долгий путь. Мы начали с пустой папки, создали REST API на Spring Boot, подключили базу данных PostgreSQL, настроили безопасность с JWT и внедрили асинхронную обработку задач через Kafka. У нас есть отличное приложение, но пока оно живет только на вашем локальном компьютере (localhost).

    В этой финальной статье курса мы выведем наш Task Tracker в большой мир. Мы упакуем приложение в Docker-контейнер и развернем его на виртуальной машине в Yandex Cloud.

    Проблема «It works on my machine»

    В старые времена деплой (развертывание) приложения выглядел как кошмар. Системный администратор должен был зайти на сервер, установить нужную версию Java, настроить переменные окружения, установить базу данных, убедиться, что версии библиотек совпадают... И часто случалось так, что код, работающий у разработчика, падал на сервере из-за разницы в настройках.

    Решение этой проблемы — Docker.

    Docker позволяет упаковать ваше приложение вместе со всем окружением (Java, библиотеки, настройки) в единый образ (Image). Если этот образ запускается у вас на ноутбуке, он гарантированно запустится и на сервере в облаке.

    !Иллюстрация принципа: один и тот же контейнер работает везде одинаково.

    Шаг 1: Создание Dockerfile

    Чтобы превратить наше Java-приложение в Docker-образ, нам нужно создать инструкцию — файл с именем Dockerfile (без расширения) в корне проекта.

    Мы будем использовать Multi-stage build (многоэтапную сборку). Это профессиональный подход, который позволяет:

  • На первом этапе использовать образ с Maven для сборки проекта (компиляции).
  • На втором этапе взять только готовую программу (JAR-файл) и положить её в легкий образ с Java, выбросив все лишние инструменты сборки.
  • Создайте файл Dockerfile со следующим содержимым:

    Разбор команд:

    * FROM ... AS build: Мы даем этому этапу имя build, чтобы ссылаться на него позже. * COPY . /app: Берет все файлы из текущей папки проекта и кладет их в папку /app внутри образа. * COPY --from=build ...: Ключевой момент. Мы берем файл не с вашего компьютера, а из предыдущего этапа сборки.

    Шаг 2: Обновление Docker Compose

    Ранее мы использовали docker-compose.yml только для базы данных и Kafka. Теперь добавим туда и наше приложение. Это позволит запустить всю инфраструктуру одной командой.

    Откройте docker-compose.yml и приведите его к следующему виду:

    Важное изменение: Обратите внимание на секцию environment в сервисе app. Мы используем имена сервисов (postgres, kafka) как хостнеймы. Внутри сети Docker контейнеры видят друг друга по именам сервисов. Нам больше не нужно использовать localhost для связи между ними.

    Шаг 3: Создание виртуальной машины в Yandex Cloud

    Теперь переходим к облачной части. Нам понадобится аккаунт в Yandex Cloud.

  • Регистрация и вход: Зайдите в консоль управления.
  • Создание каталога: Если у вас нет каталога, создайте его.
  • Compute Cloud: В меню слева выберите сервис Compute Cloud (Виртуальные машины).
  • Создать ВМ: Нажмите кнопку «Создать ВМ».
  • Настройки виртуальной машины:

    * Имя: tracker-server. * Зона доступности: Любая (например, ru-central1-a). * Операционная система: Выберите Ubuntu 22.04 или 20.04. * Диск: Оставьте стандартный (обычно 10-15 ГБ HDD/SSD достаточно). * Вычислительные ресурсы: Для нашего учебного проекта хватит минимальной конфигурации: * Платформа: Intel Ice Lake (или другая доступная). * vCPU: 2 (можно взять прерываемую/preemptible VM для экономии). * RAM: 2 ГБ или 4 ГБ (Java и Kafka любят память). * Сетевые настройки: Обязательно выберите «Публичный IP-адрес: Автоматически», чтобы мы могли подключиться к серверу из интернета. * Доступ: Введите логин (например, ubuntu) и вставьте свой SSH-ключ.

    > Если у вас нет SSH-ключа, сгенерируйте его на своем компьютере командой ssh-keygen -t rsa и скопируйте содержимое файла id_rsa.pub.

    Нажмите Создать ВМ. Через минуту машина запустится, и вы увидите её Public IP (например, 158.160.XX.XX).

    !Публичный IP — это адрес, по которому ваш сервер доступен из интернета.

    Шаг 4: Настройка сервера и Деплой

    Теперь нам нужно зайти на удаленный сервер и запустить там наше приложение.

    1. Подключение по SSH

    Откройте терминал на своем компьютере и введите:

    Согласитесь с добавлением хоста (напишите yes). Теперь вы внутри сервера Yandex Cloud.

    2. Установка Docker

    На чистой Ubuntu нет Docker. Установим его:

    После последней команды нужно перезайти на сервер (напишите exit и подключитесь снова через ssh).

    3. Перенос кода на сервер

    Самый простой способ — использовать Git. Загрузите ваш проект на GitHub/GitLab, а затем клонируйте его на сервере.

    Альтернатива: Если не хотите использовать Git, можно скопировать файлы с локальной машины через scp: scp -r . ubuntu@<IP>:/home/ubuntu/task-tracker

    4. Запуск приложения

    Находясь в папке проекта на сервере, запустите:

    * up: Поднять контейнеры. * -d: Detached mode (в фоновом режиме). * --build: Принудительно собрать образ приложения.

    Docker начнет скачивать образы Java, Postgres, Kafka, компилировать ваш проект и запускать его. Это может занять пару минут в первый раз.

    Проверьте, что все запустилось:

    Вы должны увидеть 4 запущенных контейнера со статусом Up.

    Шаг 5: Проверка работы

    Наше приложение настроено слушать порт 80 (в docker-compose.yml мы указали 80:8080). Это значит, что нам не нужно указывать порт в браузере.

    Откройте Postman или браузер и попробуйте обратиться к вашему API, используя публичный IP сервера:

    Запрос: GET http://<ВАШ_PUBLIC_IP>/hello

    Если вы видите приветственное сообщение — ПОБЕДА! Вы развернули свое приложение в облаке.

    Теперь вы можете:

  • Зарегистрироваться: POST http://<IP>/auth/signup
  • Получить токен: POST http://<IP>/auth/signin
  • Создавать задачи и проверять, как они сохраняются в БД и обрабатываются через Kafka.
  • Заключение курса

    Мы прошли огромный путь. Вы создали не просто «Hello World», а сложную распределенную систему с базой данных, безопасностью и очередями сообщений. Вы упаковали её в контейнеры и развернули на реальном сервере.

    Что изучать дальше? * CI/CD (GitLab CI, GitHub Actions): Чтобы деплой происходил автоматически при каждом коммите. * Kubernetes (K8s): Для управления сотнями контейнеров, если ваше приложение станет очень популярным. * Monitoring (Prometheus + Grafana): Чтобы видеть графики нагрузки и ошибки в реальном времени.

    Спасибо, что были с нами на этом курсе. Удачи в разработке на Java Spring!