В чем разница между docker run и docker exec?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между docker run и docker exec?
Это два кардинально разных способа запуска команд в Docker. Разберём их с примерами.
1. docker run — создание нового контейнера
docker run создаёт новый контейнер из образа и запускает команду внутри него.
# Создаёт новый контейнер с именем my-app, запускает Python приложение
docker run --name my-app python:3.11 python app.py
# Создаёт контейнер с маппингом портов и переменными окружения
docker run -d \
--name web-server \
-p 8000:5000 \
-e DEBUG=true \
my-python-app:latest
# Каждый запуск docker run создаёт новый контейнер
docker run python:3.11 echo "Hello" # Создан контейнер 1
docker run python:3.11 echo "Hello" # Создан контейнер 2 (другой!)
docker ps -a | grep python # Видны оба контейнера
Жизненный цикл:
- Образ скачивается (если нужно)
- Создаётся новый контейнер
- Запускается команда
- Контейнер может остановиться или работать дальше
2. docker exec — выполнение команды в существующем контейнере
docker exec выполняет команду внутри уже работающего контейнера. Контейнер уже существует и работает.
# Сначала запускаем контейнер
docker run -d --name my-app python:3.11 python app.py
# Теперь можем выполнить команду внутри него
docker exec my-app ls /app # Список файлов
docker exec my-app python -c "import sys; print(sys.version)"
# Интерактивное взаимодействие с оболочкой
docker exec -it my-app /bin/bash # Входим в оболочку контейнера
# Теперь ты внутри контейнера, можешь писать команды интерактивно
root@container:/app# ls
root@container:/app# python debug.py
root@container:/app# exit
3. Ключевые отличия в таблице
| Аспект | docker run | docker exec |
|---|---|---|
| Что делает | Создаёт новый контейнер | Выполняет в существующем |
| Требует | Только образ | Работающий контейнер |
| Состояние контейнера | Не важно | Должен быть запущен |
| Изоляция | Полная (новая ОС) | В том же контейнере |
| Данные | Новые файлы | Видит файлы контейнера |
| Переменные окружения | Задаются флагами -e | Уже заданы в контейнере |
4. Практические примеры
Сценарий 1: Локальная разработка
# Запускаем контейнер базы данных один раз
docker run -d \
--name postgres-db \
-e POSTGRES_PASSWORD=secret \
-p 5432:5432 \
postgres:15
# Выполняем миграции
docker exec postgres-db psql -U postgres -d myapp -f /migrations/001_init.sql
# Добавляем тестовые данные
docker exec postgres-db psql -U postgres -c "INSERT INTO users (name) VALUES (Alice)"
# Проверяем результат
docker exec postgres-db psql -U postgres -c "SELECT * FROM users"
Сценарий 2: Отладка production приложения
# Приложение уже работает (docker run выполнена ранее)
docker ps
# CONTAINER ID IMAGE NAMES
# abc123 myapp:1.0.0 production-app
# Нужно проверить логи и отладить
docker exec production-app tail -100 /var/log/app.log
docker exec production-app env | grep DEBUG
docker exec -it production-app /bin/bash # Интерактивная оболочка
# А если бы мы использовали docker run, создался бы второй контейнер!
docker run -it myapp:1.0.0 /bin/bash # НОВЫЙ контейнер, не тот что работает
Сценарий 3: Запуск Python скрипта
# Вариант 1: docker run — создаёт контейнер, выполняет скрипт, контейнер может остановиться
docker run --rm -v $(pwd):/app python:3.11 python /app/script.py
# --rm автоматически удаляет контейнер после выполнения
# Вариант 2: docker exec — контейнер должен быть запущен
docker run -d --name persistent-python python:3.11 tail -f /dev/null # Держим контейнер живым
docker exec persistent-python python /app/script.py
docker exec persistent-python python /app/another_script.py # Второй скрипт в том же контейнере
5. docker run с флагом -d (detached mode)
Часто люди путаются, потому что docker run -d запускает контейнер в фоне:
# Запускаем в фоне
docker run -d --name my-service python:3.11 python app.py
# Контейнер работает, но мы вернулись в терминал
docker ps # Видим мой контейнер
# Теперь можем использовать docker exec
docker exec my-service python test.py
docker exec -it my-service /bin/bash
Это часто используется вместо docker exec: сначала docker run -d, потом docker exec.
6. Когда что использовать?
Используй docker run, если:
- Нужно создать новый контейнер
- Запускаешь одноразовую задачу (скрипт, миграция)
- Нужна изоляция от других процессов
- Создаёшь новый сервис
# Миграция БД перед запуском приложения
docker run --rm \
--network app-network \
my-app:latest \
python migrate.py
Используй docker exec, если:
- Контейнер уже работает
- Нужно отладить или проверить состояние
- Выполняешь команду в контексте работающего приложения
- Нужна интерактивная оболочка
# Проверить логи работающего контейнера
docker exec production-app tail -f /var/log/app.log
# Интерактивная отладка
docker exec -it production-app /bin/bash
7. Практический пример: полный цикл
# 1. Создаём контейнер с приложением (docker run)
docker run -d \
--name myapp \
-p 8000:8000 \
-e DATABASE_URL=postgres://db:5432/myapp \
myapp:1.0.0
# 2. Проверяем, работает ли (docker exec)
docker exec myapp curl localhost:8000/health
# 3. Смотрим логи (docker exec)
docker exec myapp tail -100 /var/log/app.log
# 4. Отлаживаем через оболочку (docker exec)
docker exec -it myapp /bin/bash
# >>> python manage.py shell
# >>> from models import User
# >>> User.objects.all()
# 5. Когда всё готово, контейнер работает дальше
# docker run создал, docker exec помогает управлять
Итог
- docker run = создание и запуск нового контейнера
- docker exec = выполнение команды в уже работающем контейнере
В production обычно сначала делают docker run -d для запуска сервиса, а потом docker exec для отладки и управления. Это как создать процесс (docker run) и затем взаимодействовать с ним (docker exec).