← назад к разделу

Образ есть — теперь нужно его запустить. В этой статье разберём команду docker run, основные флаги, которые используются каждый день, и то, что происходит с контейнером после старта: как смотреть логи, заходить внутрь и корректно останавливать.

Что происходит при запуске

Когда вы пишете docker run, Docker создаёт из образа контейнер — изолированный процесс со своей файловой системой, сетью и переменными окружения — и запускает его.

Короткая формула: образ — это рецепт, контейнер — это работающее блюдо.

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

docker run eclipse-temurin:21-jre java -version

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

Основные флаги docker run

Большинство реальных запусков используют несколько флагов вместе. Разберём каждый.

-p: проброс портов

Контейнер живёт в изолированной сети — снаружи до него не достучаться, пока вы явно не откроете порт.

docker run -p 8080:8080 my-spring-app
#              ^     ^
#         хост:контейнер

Левая часть — порт на вашей машине (хосте), правая — порт внутри контейнера. Можно использовать разные номера:

docker run -p 9090:8080 my-spring-app   # приложение слушает 8080, снаружи доступно на 9090

-e: переменные окружения

Это основной способ передавать конфигурацию в контейнер — пароли к базе данных, URL внешних сервисов, профили Spring Boot. Каждая переменная — отдельный флаг -e:

docker run \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e DB_URL=jdbc:postgresql://db:5432/myapp \
  -e DB_PASSWORD=secret \
  my-spring-app

Внутри Spring Boot эти переменные автоматически подхватываются как свойства приложения (через Environment).

-d: фоновый режим

По умолчанию docker run держит терминал занятым — вывод идёт прямо в консоль. Флаг -d (detached) запускает контейнер в фоне и сразу возвращает управление:

docker run -d -p 8080:8080 my-spring-app

Docker выведет идентификатор контейнера и всё. Логи смотреть отдельно — об этом ниже.

--name: имя контейнера

По умолчанию Docker придумывает имена вроде elegant_hopper — не очень удобно. Задайте своё:

docker run -d --name my-app -p 8080:8080 my-spring-app

Теперь к контейнеру можно обращаться по имени во всех командах: docker logs my-app, docker stop my-app.

--rm: автоудаление

Если контейнер нужен разово (прогнать тест, выполнить скрипт), флаг --rm удалит его автоматически при остановке:

docker run --rm my-spring-app java -jar app.jar --check-config

Без --rm остановленные контейнеры накапливаются и занимают место.

Всё вместе — типичный запуск

docker run -d \
  --name my-app \
  --rm \
  -p 8080:8080 \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e DB_URL=jdbc:postgresql://db:5432/myapp \
  my-spring-app:1.0

Передача конфигурации через переменные окружения

В мире контейнеров конфигурация не хранится внутри образа — она приходит снаружи при запуске. Это идея из методологии 12-factor app: один и тот же образ разворачивается в разных окружениях (разработка, тестирование, продакшн) с разными переменными.

Для Spring Boot это выглядит так: в application.yml вы пишете ${DB_URL}, а конкретное значение передаёте через -e DB_URL=... при запуске контейнера. Ни один секрет не попадает в образ.

Если переменных много, удобно вынести их в файл:

# .env
SPRING_PROFILES_ACTIVE=prod
DB_URL=jdbc:postgresql://db:5432/myapp
DB_PASSWORD=secret
docker run -d --env-file .env -p 8080:8080 my-spring-app

Только не коммитьте .env с реальными паролями в репозиторий.

Жизненный цикл контейнера

После запуска контейнер проходит через несколько состояний.

diagram

Команды для управления:

docker ps                  # список работающих контейнеров
docker ps -a               # все, включая остановленные
docker stop my-app         # мягкая остановка (SIGTERM, затем SIGKILL через 10 с)
docker start my-app        # запустить остановленный контейнер
docker rm my-app           # удалить остановленный контейнер
docker rm -f my-app        # остановить и удалить сразу

docker stop отправляет процессу сигнал SIGTERM — приложение может его перехватить и завершиться корректно (закрыть соединения с базой, дождаться текущих запросов). Через 10 секунд Docker принудительно убивает процесс через SIGKILL.

Логи: docker logs

Всё, что приложение пишет в stdout и stderr, Docker собирает автоматически.

docker logs my-app            # вывести все накопленные логи
docker logs -f my-app         # следить за логами в реальном времени (как tail -f)
docker logs --tail 100 my-app # последние 100 строк

Spring Boot по умолчанию пишет в stdout — ничего дополнительно настраивать не нужно. Если приложение пишет в файл внутри контейнера, docker logs этот файл не увидит.

Зайти внутрь: docker exec

Иногда нужно посмотреть, что происходит внутри работающего контейнера — проверить файловую систему, переменные окружения, сетевые соединения.

docker exec -it my-app sh     # запустить shell внутри контейнера
docker exec -it my-app bash   # если bash есть в образе

Флаги -it означают: -i — передавать ввод с клавиатуры, -t — подключить псевдотерминал. Вместе они дают интерактивную сессию.

Внутри можно проверить переменные:

env | grep SPRING

Или посмотреть, какие процессы запущены:

ps aux

docker exec не перезапускает приложение — команда выполняется рядом с уже работающим процессом.

Healthcheck: проверка работоспособности

Docker умеет периодически проверять, жив ли контейнер — не просто процесс запущен, а приложение реально отвечает. Это healthcheck.

Проще всего задать его в Dockerfile:

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

После старта контейнер некоторое время находится в состоянии starting — Docker ждёт, пока healthcheck пройдёт впервые. Потом переходит в healthy или unhealthy.

Посмотреть статус:

docker inspect --format='{{.State.Health.Status}}' my-app

В изолированном docker run healthcheck влияет только на статус — контейнер не перезапускается автоматически. Автоматический перезапуск — это уже задача для Docker Compose или оркестратора.

Коротко

  • docker run создаёт контейнер из образа и запускает его; при завершении процесса контейнер останавливается.
  • -p host:container — проброс порта; без него к контейнеру не подключиться снаружи.
  • -e KEY=VALUE — передать переменную окружения; это основной способ конфигурации по принципу 12-factor.
  • -d — фоновый режим; --name — удобное имя; --rm — удалить контейнер после остановки.
  • docker logs -f — следить за логами в реальном времени; docker exec -it ... sh — интерактивная сессия внутри.
  • docker stop посылает SIGTERM, даёт приложению 10 секунд на корректное завершение.
  • Healthcheck проверяет, что приложение не просто запущено, а реально отвечает.

Что почитать дальше

  • Что такое Docker и зачем он нужен — если ещё не читали: образы, слои, изоляция с нуля.
  • Тома и данные — как сохранить данные между перезапусками контейнера.
  • Сеть в Docker — как контейнеры общаются друг с другом и с внешним миром.