docker run: базовая команда
docker run — это основная команда. С неё начинается любой контейнер. И именно в её флагах больше всего «соли». Если ты понимаешь, что делает каждый из 7-8 основных флагов, ты понимаешь 80% того, что нужно для daily-работы.
В этом уроке разберём базовый синтаксис, ключевые флаги, что физически происходит при docker run, и важное концептуальное различие — run это не одна команда, а две: create + start.
Что делает docker run
Простейший вызов:
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— образ.
После этого 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> для стартовых уже существующих контейнеров (например, после рестарта системы).
Что важно из «грабель»
Если ты запускаешь docker run -it postgres:16.4 без -d, и потом нажимаешь Ctrl+C — ты убиваешь Postgres главный процесс. Контейнер останавливается с кодом 130 (SIGINT). Для долгоживущих сервисов всегда используй -d.
Если ты случайно запустил контейнер без --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.