Learning Platform
Глоссарий Troubleshooting
Урок 05.01 · 22 мин
Начальный
dockerdocker-runcontainerscli

docker run: базовая команда

docker run — это основная команда. С неё начинается любой контейнер. И именно в её флагах больше всего «соли». Если ты понимаешь, что делает каждый из 7-8 основных флагов, ты понимаешь 80% того, что нужно для daily-работы.

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


Что делает docker run

Что физически происходит при docker run
docker run nginxКоманда от тебя. Просто HTTP-запрос к daemon
Образ есть локально?Daemon проверяет наличие image nginx:latest в локальном кеше. Если нет — переходит к pull
docker pull nginxЕсли образа нет — скачивает с Docker Hub. Слои тянутся параллельно, кеш-слои не повторно скачиваются
create containerСоздаётся writable layer поверх image, готовится rootfs через overlayfs, создаётся network namespace, готовятся cgroups
start containerrunc делает clone() с namespace-флагами, pivot_root, запускает главный процесс из CMD/ENTRYPOINT
attach to logsЕсли не -d, CLI подключается к stdout/stderr контейнера и выводит их. Контейнер живёт пока живёт его главный процесс

Простейший вызов:

docker run nginx

Делает шаги 1-5. Контейнер запускается на foreground, ты видишь логи nginx. Ctrl+C — посылает SIGTERM в nginx, контейнер останавливается. Сам контейнер остаётся в состоянии exited (не удалён).


Ключевые флаги

-d (detached) — фон

docker run -d nginx

Контейнер запускается в фоне, CLI сразу возвращает контроль (выводит ID контейнера). nginx работает в фоне. Чтобы посмотреть логи — docker logs <id>.

Это типичный режим для сервисов (Postgres, nginx, Redis), которые должны работать долго.

-it (interactive + tty) — интерактивный режим

docker run -it ubuntu bash

Флаг -i — сохраняет stdin открытым (можно вводить). Флаг -t — выделяет псевдо-tty (терминал). Вместе они дают интерактивную shell-сессию.

docker run -it python:3.12 python
# >>> 1 + 1
# 2
# >>> exit()

Без -it ты не сможешь набирать команды в контейнере. Это типично для:

  • Запуска shell для исследования (docker run -it alpine sh).
  • Запуска REPL (docker run -it python:3.12 python).
  • Любого случая, когда нужно интерактивно вводить.

—rm — автоудаление

docker run --rm hello-world

После завершения контейнера он автоматически удаляется. Если бы не было --rm, контейнер бы остался в состоянии exited, и потом ты бы собирал мусор через docker rm.

Полезно для:

  • Одноразовых задач: docker run --rm alpine sh -c 'echo hello'.
  • REPL: docker run --rm -it python:3.12 python.
  • Тестов: запустил, проверил, забыл.

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

-p host:container — порты

docker run -d -p 8080:80 nginx

Контейнер слушает порт 80 (это nginx default). Флаг -p пробрасывает порт 80 контейнера на порт 8080 хоста. Теперь curl http://localhost:8080 достучится до nginx.

Без -p контейнер слушает порт внутри своего network namespace, но снаружи не виден.

Вариации:

  • -p 8080:80 — конкретный порт хоста.
  • -p 80 — Docker сам подберёт случайный свободный порт. Узнать его через docker port <container>.
  • -p 127.0.0.1:8080:80 — слушать только на localhost (не доступно из сети).
  • -p 8080:80/udp — UDP вместо TCP.

-v host_path:container_path — volume / bind mount

docker run -d -p 5432:5432 \
  -v $(pwd)/pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:16.4

Папка ./pgdata на хосте монтируется внутрь контейнера в /var/lib/postgresql/data. Postgres пишет данные туда, на хосте они сохраняются между рестартами контейнера.

Это bind mount. Есть ещё named volumes — Docker сам управляет, где они лежат на хосте. Подробно в модуле 9.

—name

docker run -d --name pg postgres:16.4

Без --name Docker даёт случайное имя (вроде silly_einstein). С --name pg ты можешь дальше обращаться к контейнеру по имени:

docker logs pg
docker exec -it pg psql -U postgres
docker stop pg

В DE-сценариях ты почти всегда указываешь --name — это удобнее, чем запоминать ID контейнера.

Имя должно быть уникальным. Если контейнер с таким именем уже есть — run упадёт.

-e ENV_VAR=value — переменные окружения

docker run -d -e POSTGRES_PASSWORD=secret postgres:16.4

Переменные окружения часто используются для конфигурации образов. Например, образ Postgres ожидает POSTGRES_PASSWORD, POSTGRES_USER, POSTGRES_DB — это его конфиг.

Можно передать файл через --env-file:

docker run -d --env-file .env postgres:16.4

Полный пример

Запуск Postgres со всеми типичными флагами:

docker run -d \
  --name pg \
  --restart=unless-stopped \
  -p 5432:5432 \
  -v $(pwd)/pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=mydb \
  --memory=512m \
  --cpus=1 \
  postgres:16.4

Разбор:

  • -d — в фоне.
  • --name pg — обращаться к контейнеру по имени.
  • --restart=unless-stopped — авто-рестарт, если упадёт. Подробно в уроке 03.5.
  • -p 5432:5432 — Postgres слушает 5432 внутри, доступен на 5432 хоста.
  • -v ./pgdata:/var/lib/postgresql/data — данные на хосте, сохраняются между рестартами.
  • -e POSTGRES_PASSWORD=secret — обязательная переменная для образа Postgres.
  • --memory=512m, --cpus=1 — лимиты через cgroups.
  • postgres:16.4 — образ.
Swap, overcommit, OOM killer — что делать когда RAM не хватает

После этого psql -h localhost -U postgres -W подключится к этому Postgres’у.


docker run vs docker create + docker start

docker run — это shortcut. На самом деле это две операции:

docker create --name pg postgres:16.4
# создан контейнер, но не запущен
docker start pg
# запущен

Эквивалентно:

docker run -d --name pg postgres:16.4

Когда полезно делать create + start отдельно:

  • Подготовить контейнер заранее с правильной конфигурацией, запустить позже.
  • Скриптинг: создать N контейнеров, потом стартовать их пачкой.
  • Отладка: создать контейнер, посмотреть его inspect, потом запустить.

В daily-работе обычно используют run. Но знание разницы помогает понимать, что run это не «одна неделимая команда».

Есть ещё docker container start <name> для стартовых уже существующих контейнеров (например, после рестарта системы).


Что важно из «грабель»

WARNING

Если ты запускаешь docker run -it postgres:16.4 без -d, и потом нажимаешь Ctrl+C — ты убиваешь Postgres главный процесс. Контейнер останавливается с кодом 130 (SIGINT). Для долгоживущих сервисов всегда используй -d.

TIP

Если ты случайно запустил контейнер без --name и теперь не помнишь его ID — docker ps покажет последний запущенный контейнер. Или docker ps -lq (last container, только ID).

Типичные ошибки junior’а:

  • Запускают docker run nginx без -d, видят логи, не понимают, что делать дальше. Решение: -d или открыть второй терминал.
  • Запускают сервис на порту, который уже занят. bind: address already in use — выбери другой порт через -p.
  • Используют -v ./data:/data с относительным путём. Часто работает, но иногда docker daemon не понимает относительный путь, лучше $(pwd)/data или абсолют.

Попробуй сам

# 1. Простой запуск
docker run --rm hello-world

# 2. Интерактивный shell
docker run --rm -it alpine sh
# внутри: ls /, exit

# 3. Сервис в фоне
docker run -d --name webby -p 8080:80 nginx
curl http://localhost:8080
# должен ответить html

# 4. Postgres с volumes и env
mkdir -p ./pgdata
docker run -d --name pg \
  -p 5432:5432 \
  -v $(pwd)/pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:16.4
sleep 5
docker exec -it pg psql -U postgres -c 'select version();'

# 5. Прибраться
docker rm -f webby pg
rm -rf ./pgdata

Обрати внимание: после docker run -d тебе сразу возвращается prompt — контейнер ушёл в фон. docker ps покажет его как Up.


Проверка знанийKnowledge check
Что произойдёт, если ты запустишь docker run без -d (detached), и потом нажмёшь Ctrl+C? И в каких случаях это нормально, а когда плохо?
ОтветAnswer
Без флага -d контейнер запускается в режиме foreground: CLI остаётся подключённым к stdout/stderr контейнера, ты видишь его логи. Ctrl+C посылает SIGINT главному процессу контейнера через CLI, главный процесс получает сигнал и завершается, контейнер останавливается с кодом 130. Это нормально и желательно для одноразовых интерактивных задач — запуск REPL (docker run --rm -it python:3.12 python), отладочный shell (docker run --rm -it alpine sh), скрипт типа docker run --rm alpine echo hello, где ты хочешь увидеть вывод и сразу выйти. Это плохо для долгоживущих сервисов — Postgres, nginx, Airflow worker. Если ты случайно закроешь терминал или нажмёшь Ctrl+C — сервис умрёт. Для таких контейнеров используют -d: docker run -d --name pg postgres:16.4, CLI сразу возвращает ID и prompt, контейнер живёт в фоне, ты управляешь им через docker logs, docker exec, docker stop. Это и есть стандартный режим для daily DE-работы.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Что делает флаг -d в docker run -d nginx?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5