Обе команды запускают процесс рядом с сервисом, поэтому их легко перепутать. Но работают они с разными контейнерами.
docker compose exec выполняет команду внутри уже запущенного контейнера. Это удобно, когда нужно открыть shell, посмотреть переменные окружения или запустить миграцию в работающем приложении.
docker compose exec api sh
Команда использует тот же контейнер, его сеть, тома и текущее состояние. Если сервис не запущен, exec не сможет подключиться.
docker compose run создаёт отдельный одноразовый контейнер на основе сервиса.
docker compose run --rm api python manage.py migrate
Такой запуск хорош для задач, которые не должны трогать основной процесс. После --rm временный контейнер будет удалён.
Важно помнить, что run по умолчанию не публикует порты сервиса. Если нужно открыть порт для отладки, его надо указать отдельно.
docker compose run --rm --service-ports api
Для проверки живого контейнера выбирай exec. Для отдельной команды, миграции или одноразового job выбирай run.
➡️ DevOps Ready | #совет
