Главная/Containers и lifecycle/Урок

4.2. Режимы запуска

Цели

После этого материала вы сможете:

  • осознанно выбирать между foreground и detached режимом;
  • объяснить, что делает -i и что делает -t по отдельности;
  • предсказать поведение любой комбинации -i, -t, -d;
  • объяснить, почему Ctrl+C иногда останавливает container, а иногда нет;
  • работать со стандартными потоками container: передавать данные на stdin, разделять stdout и stderr;
  • объяснить, почему docker run в скрипте ведёт себя иначе, чем в терминале;
  • управлять именами containers и понимать, откуда берутся автогенерируемые.

Предварительные знания

Ключевые термины

ТерминОбъяснение
foregroundРежим, в котором CLI остаётся подключённым к потокам container и ждёт его завершения
detachedФоновый режим: CLI печатает ID container и завершается
stdinСтандартный поток ввода, дескриптор 0
stdoutСтандартный поток вывода, дескриптор 1
stderrСтандартный поток ошибок, дескриптор 2
TTYТерминальное устройство. Даёт эхо ввода, обработку Ctrl+C, размер окна, цвета
pseudo-TTYПрограммная эмуляция терминала — то, что создаёт флаг -t
attachПодключение к потокам уже работающего container

Теория

Два режима запуска

bash
docker run alpine sleep 5      # foreground: терминал занят 5 секунд
docker run -d alpine sleep 5   # detached: сразу вернулся ID
Foreground (по умолчанию)Detached (-d)
CLI ждёт завершенияДаНет
Потоки containerПодключены к терминалуНе подключены
Что печатаетсяВывод приложенияID container
Exit code командыExit code container0, если запуск удался
Как посмотреть выводОн на экранеdocker logs
Типичное применениеРазовые команды, отладка, CIСервисы, долгоживущие процессы

Важная деталь: в detached режиме exit code docker run не имеет отношения к приложению. Команда вернёт 0, даже если приложение упадёт через секунду. Проверять нужно отдельно — через docker wait или docker inspect.

-i и -t — два независимых флага

Их почти всегда пишут вместе как -it, из-за чего кажется, что это один флаг. Это не так.

-i (--interactive) — держать stdin открытым. Без него stdin container сразу закрывается: программа, читающая ввод, получает конец файла.

-t (--tty) — выделить pseudo-TTY. Это меняет поведение программ: появляется эхо символов, работают управляющие последовательности, программы включают цветной вывод и интерактивный режим.

Таблица всех комбинаций:

ФлагиstdinTTYЧто получится
нетзакрытнетПакетный запуск. Оболочка сразу завершится
-iоткрытнетМожно подавать данные на вход. Нет эха, нет промпта
-tзакрытестьTTY есть, но ввести ничего нельзя. Почти всегда ошибка
-itоткрытестьПолноценная интерактивная сессия

Строка -t без -i объясняет частое недоумение: терминал вроде выделен, промпт появился, а на нажатия клавиш реакции нет — потому что stdin закрыт.

Когда -t вреден

Флаг -t — не «сделать красивее». Он меняет структуру потоков.

При -t stdout и stderr объединяются. Терминал — одно устройство, у него нет двух отдельных каналов. Поэтому:

bash
docker run -t alpine sh -c 'echo OUT; echo ERR >&2' 2>/dev/null

выведет обе строки: перенаправление stderr не сработало, потому что stderr и не было — всё шло через TTY.

Практические следствия:

  • в скриптах и CI флаг -t использовать не нужно — он ломает разделение потоков и добавляет управляющие символы в вывод;
  • при парсинге вывода -t даёт \r\n вместо \n, из-за чего сравнение строк неожиданно не срабатывает;
  • Docker откажется выделять TTY, если стандартный ввод не является терминалом, — отсюда ошибка the input device is not a TTY в CI.

Правило: -t только для интерактивной работы человека. Для всего остального — без него.

Что делает Ctrl+C

Поведение зависит от режима, и это регулярно путают.

РежимЧто происходит при Ctrl+C
docker run (без -t)CLI получает SIGINT и отключается. Container продолжает работать
docker run -tSIGINT передаётся процессу в container через TTY. Обычно container останавливается
docker run --sig-proxy=falseСигнал не передаётся, CLI отключается
docker attachПо умолчанию сигнал передаётся; отключиться без остановки — Ctrl+P, Ctrl+Q

Первая строка — источник ситуации «нажал Ctrl+C, а он всё работает». Проверяется через docker ps.

Стандартные потоки container

Процесс в container имеет те же три потока, что и обычный процесс. Разница в том, куда они ведут.

text
   foreground без -t:
     stdout ──► daemon ──► CLI ──► ваш stdout
     stderr ──► daemon ──► CLI ──► ваш stderr      (потоки раздельны)
     stdin  ◄── CLI ◄── ваш stdin   (только с -i)

   foreground с -t:
     stdout ─┐
             ├─► pseudo-TTY ──► CLI ──► ваш терминал   (потоки слиты)
     stderr ─┘

   detached:
     stdout ──┐
              ├─► logging driver ──► docker logs
     stderr ──┘
     stdin — закрыт (если не задан -i)

В detached режиме оба потока идут в logging driver. docker logs умеет их разделять, если драйвер сохраняет метку потока — json-file и local сохраняют.

Это объясняет, почему приложение должно писать логи в stdout и stderr, а не в файл: только так их увидит Docker. Тема разбирается в разделе 06.

Имена containers

Если имя не задано, Docker генерирует его из пары «прилагательное_фамилия»: nifty_lamarr, relaxed_hopper. Фамилии — известных учёных и инженеров.

Имя должно быть уникальным среди всех containers, включая остановленные. Отсюда частая ошибка:

text
docker: Error response from daemon: Conflict. The container name "/api" is
already in use by container "a1b2c3...". You have to remove (or rename)
that container to be able to reuse that name.

Container с таким именем существует, пусть и в состоянии exited. Варианты: удалить его, переименовать через docker rename или использовать --rm при запуске.

Имя работает как альтернатива ID во всех командах и как DNS-имя в user-defined сетях (раздел 08).


Внутренний механизм

Как передаются потоки

В detached режиме процесс container пишет в дескрипторы, которые держит shim (урок 2.6). Shim передаёт данные daemon, тот — в logging driver.

В foreground режиме CLI открывает соединение к эндпоинту API /containers/<id>/attach и получает поток данных. Если TTY не выделен, поток мультиплексирован: каждый фрагмент предваряется восьмибайтовым заголовком с указанием, к какому потоку он относится. CLI разбирает заголовки и раскладывает данные по своим stdout и stderr.

При выделенном TTY мультиплексирования нет — идёт сырой поток байтов. Именно поэтому разделение потоков теряется.

Почему docker run -t в CI падает

Флаг -t требует, чтобы стандартный ввод CLI был терминалом. В CI-раннере stdin обычно перенаправлен из файла или /dev/null, терминала нет.

text
the input device is not a TTY

Решение — убрать -t. Если команда используется и локально, и в CI, флаг добавляют условно:

bash
[ -t 0 ] && TTY_FLAG="-it" || TTY_FLAG="-i"
docker run --rm $TTY_FLAG alpine sh -c 'echo ok'

Конструкция [ -t 0 ] проверяет, является ли дескриптор 0 терминалом.


Команды и примеры

Foreground против detached

bash
echo "--- foreground: терминал занят ---"
time docker run --rm alpine sleep 3

echo "--- detached: сразу возвращается ---"
time docker run -d --rm --name bg alpine sleep 3
docker ps --filter name=bg --format '{{.Names}} {{.Status}}'
sleep 4
text
--- foreground: терминал занят ---
real	0m3.412s
--- detached: сразу возвращается ---
7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a
real	0m0.389s
bg Up Less than a second

Разница в поведении CLI, а не container: в обоих случаях процесс выполнялся три секунды.

Exit code в двух режимах

bash
echo "--- foreground: exit code приложения ---"
docker run --rm alpine sh -c 'exit 42'
echo "код: $?"

echo "--- detached: exit code запуска ---"
docker run -d --name failing alpine sh -c 'exit 42' > /dev/null
echo "код docker run: $?"
sleep 1
echo "код приложения: $(docker inspect failing --format '{{.State.ExitCode}}')"
docker rm failing > /dev/null
text
--- foreground: exit code приложения ---
код: 42
--- detached: exit code запуска ---
код docker run: 0
код приложения: 42

Вторая строка — ловушка для скриптов. В detached режиме docker run сообщает только об успехе запуска. Приложение может упасть немедленно, и скрипт этого не заметит.

Правильная проверка в скрипте:

bash
docker run -d --name svc alpine sh -c 'sleep 1; exit 3' > /dev/null
CODE="$(docker wait svc)"
echo "фактический код: $CODE"
docker rm svc > /dev/null
text
фактический код: 3

Комбинации -i и -t

Без флагов:

bash
docker run --rm alpine sh
echo "код: $?"
text
код: 0

Мгновенно завершилось, ничего не выведя. Оболочка запустилась, обнаружила закрытый stdin, прочитала конец файла и вышла.

Только -i:

bash
echo -e 'echo "команда из stdin"\nid -u\nexit' | docker run --rm -i alpine sh
text
команда из stdin
0

Оболочка приняла команды со стандартного ввода и выполнила их. Промпта нет — TTY не выделен, оболочка работает в неинтерактивном режиме.

Только -t:

bash
timeout 3 docker run --rm -t alpine sh
echo "завершено по таймауту: $?"
text
/ # 
завершено по таймауту: 124`

Промпт появился — TTY есть. Но ввести ничего нельзя: stdin закрыт. Пришлось прерывать по таймауту. Практического применения у этой комбинации нет.

-it:

bash
docker run --rm -it alpine sh
text
/ # echo "работает"
работает
/ # exit

Полноценная сессия: промпт, эхо, история, Ctrl+C.

Разделение потоков и влияние -t

bash
echo "=== без -t: потоки раздельны ==="
echo "-- только stdout --"
docker run --rm alpine sh -c 'echo "в stdout"; echo "в stderr" >&2' 2>/dev/null
echo "-- только stderr --"
docker run --rm alpine sh -c 'echo "в stdout"; echo "в stderr" >&2' 1>/dev/null

echo
echo "=== с -t: потоки слиты ==="
echo "-- пытаемся отбросить stderr --"
docker run --rm -t alpine sh -c 'echo "в stdout"; echo "в stderr" >&2' 2>/dev/null
text
=== без -t: потоки раздельны ===
-- только stdout --
в stdout
-- только stderr --
в stderr

=== с -t: потоки слиты ===
-- пытаемся отбросить stderr --
в stdout
в stderr

В последнем случае обе строки прошли, хотя stderr перенаправлен в /dev/null. Разделения потоков больше нет.

Второе следствие — символы возврата каретки:

bash
echo "=== без -t ==="
docker run --rm alpine echo "строка" | od -c | head -1
echo "=== с -t ==="
docker run --rm -t alpine echo "строка" | od -c | head -1
text
=== без -t ===
0000000    с   т   р   о   к   а  \n
=== с -t ===
0000000    с   т   р   о   к   а  \r  \n

С -t в конце \r\n. Именно из-за этого сравнение вывода со строкой в скрипте не срабатывает:

bash
OUT="$(docker run --rm -t alpine echo ok)"
[ "$OUT" = "ok" ] && echo "совпало" || echo "НЕ совпало (виноват \\r)"

OUT="$(docker run --rm alpine echo ok)"
[ "$OUT" = "ok" ] && echo "совпало" || echo "не совпало"
text
НЕ совпало (виноват \r)
совпало

Вывод: в скриптах -t не использовать.

Передача данных на stdin

bash
# файл на вход
echo "строка 1
строка 2
строка 3" | docker run --rm -i alpine wc -l
text
3

Практический пример — обработка данных Python-скриптом без создания файлов:

bash
cat > /tmp/sum.py <<'PY'
import sys

total = 0
for line in sys.stdin:
    line = line.strip()
    if line:
        total += int(line)
print(f"сумма: {total}")
PY

printf '10\n20\n30\n' | docker run --rm -i \
    -v /tmp/sum.py:/sum.py:ro \
    python:3.13-slim python /sum.py
text
сумма: 60

Обратите внимание: -i есть, -t нет. Данные приходят из конвейера, терминал не нужен.

Обработка целого файла:

bash
docker run --rm -i alpine sh -c 'grep -c "" ' < /etc/services

Ctrl+C и --sig-proxy

Демонстрация того, что без -t container переживает Ctrl+C. Воспроизведём это программно, послав SIGINT самому CLI:

bash
docker run --name sigtest -d alpine sleep 120 > /dev/null
docker attach --sig-proxy=false sigtest &
ATTACH_PID=$!
sleep 1
kill -INT "$ATTACH_PID" 2>/dev/null
wait "$ATTACH_PID" 2>/dev/null
echo "после прерывания attach:"
docker ps --filter name=sigtest --format '{{.Names}} {{.Status}}'
docker rm -f sigtest > /dev/null
text
после прерывания attach:
sigtest Up 2 seconds

Container продолжает работать. Флаг --sig-proxy=false явно указывает не передавать сигналы в container — это поведение по умолчанию для docker run без TTY и удобный способ отсоединиться, ничего не сломав.

Для отсоединения от интерактивного attach без остановки container используется последовательность Ctrl+P, Ctrl+Q.

attach против exec

bash
docker run -d --name att alpine sh -c 'while true; do echo "тик $(date +%T)"; sleep 2; done' > /dev/null
sleep 1

echo "--- attach: подключаемся к ОСНОВНОМУ процессу ---"
timeout 5 docker attach --sig-proxy=false att

echo
echo "--- exec: запускаем НОВЫЙ процесс ---"
docker exec att ps -o pid,comm

docker rm -f att > /dev/null
text
--- attach: подключаемся к ОСНОВНОМУ процессу ---
тик 17:42:11
тик 17:42:13

--- exec: запускаем НОВЫЙ процесс ---
PID   COMMAND
    1 sh
   14 sleep
   19 ps

Различие:

attachexec
Что делаетПодключается к потокам PID 1Запускает новый процесс
Влияние на containerМожет остановить его сигналомНе влияет
Видит прошлый выводНет, только новыйНе применимо
Безопасность в productionОпасноБезопасно

docker attach в production применять не стоит: случайный Ctrl+C останавливает сервис. Для входа в работающий container используйте docker exec — разбирается в уроке 4.3.

Именование

bash
# автогенерируемое имя
CID="$(docker run -d alpine sleep 60)"
docker inspect "$CID" --format 'сгенерировано: {{.Name}}'

# явное имя
docker run -d --name my-service alpine sleep 60 > /dev/null
docker ps --filter name=my-service --format '{{.Names}}'
text
сгенерировано: /wizardly_hopper
my-service

Конфликт имён:

bash
# head -1, а не tail: Docker 29 печатает после ошибки пустую строку
# и подсказку «Run 'docker run --help'», и tail забирает именно их
docker run -d --name my-service alpine sleep 60 2>&1 | head -1
text
docker: Error response from daemon: Conflict. The container name "/my-service"
is already in use by container "b3c4d5e6f7a8...".

Три способа решения:

bash
# 1. удалить старый
docker rm -f my-service > /dev/null

# 2. переименовать
docker run -d --name my-service alpine sleep 60 > /dev/null
docker rename my-service my-service-old
docker run -d --name my-service alpine sleep 60 > /dev/null
docker ps --filter 'name=my-service' --format '{{.Names}}'

# 3. --rm, чтобы имя освобождалось автоматически
docker rm -f my-service my-service-old > /dev/null
docker run --rm --name tmp-task alpine echo "готово"
docker ps -a --filter name=tmp-task --format '{{.Names}}' | wc -l
text
my-service
my-service-old
готово
0

Уборка:

bash
docker rm -f "$CID" 2>/dev/null || true
rm -f /tmp/sum.py

Флаг --rm и его ограничения

bash
# работает с foreground
docker run --rm alpine echo ok

# работает с detached
docker run -d --rm --name auto alpine sleep 2 > /dev/null
sleep 4
docker ps -a --filter name=auto --format '{{.Names}}' | wc -l
text
ok
0

Несовместимость с restart policy:

bash
docker run -d --rm --restart=always alpine sleep 10 2>&1 | head -1
text
docker: conflicting options: cannot specify both --restart and --rm

Сообщение печатает клиент, а не демон: несовместимость флагов видна ещё до обращения к API — потому и нет Error response from daemon.

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


Практическое упражнение

Задание. Напишите скрипт run-modes-matrix.sh, который экспериментально заполняет таблицу поведения для всех четырёх комбинаций -i и -t.

Для каждой комбинации проверьте:

  1. Завершается ли sh немедленно.
  2. Принимает ли команды со stdin.
  3. Разделены ли stdout и stderr.
  4. Есть ли \r в конце строк вывода.

Дополнительно напишите функцию docker_run_safe, которая подставляет -t только когда stdin является терминалом, — чтобы одна и та же команда работала и локально, и в CI.

Подсказки

Подсказка 1

Проверить разделение потоков: выполнить команду, пишущую в оба потока, с перенаправлением 2>/dev/null. Если строка из stderr всё равно появилась — потоки слиты.

Подсказка 2

Наличие \r определяется так:

bash
out="$(docker run --rm -t alpine echo x | od -c | head -1)"
case "$out" in *'\r'*) echo "есть" ;; *) echo "нет" ;; esac
Подсказка 3

Комбинация -t без -i зависает — оборачивайте её в timeout.

Решение

Сначала выполните задание самостоятельно.

Показать решение
bash
#!/usr/bin/env bash
# run-modes-matrix.sh — экспериментальная матрица поведения -i и -t.
set -uo pipefail

IMG=alpine:3.21
docker pull -q "$IMG" > /dev/null

# 1. Завершается ли sh немедленно
test_immediate_exit() {
    local flags="$1"
    if timeout 3 docker run --rm $flags "$IMG" sh < /dev/null > /dev/null 2>&1; then
        echo "да"
    else
        [ $? -eq 124 ] && echo "нет (зависает)" || echo "да"
    fi
}

# 2. Принимает ли команды со stdin
test_stdin() {
    local flags="$1" out
    out="$(printf 'echo ПРИНЯТО\n' | timeout 3 docker run --rm $flags "$IMG" sh 2>/dev/null)"
    case "$out" in *ПРИНЯТО*) echo "да" ;; *) echo "нет" ;; esac
}

# 3. Разделены ли stdout и stderr
test_streams() {
    local flags="$1" out
    out="$(timeout 3 docker run --rm $flags "$IMG" \
           sh -c 'echo OUT; echo ERR >&2' 2>/dev/null < /dev/null)"
    case "$out" in
        *ERR*) echo "слиты" ;;
        *OUT*) echo "раздельны" ;;
        *)     echo "?" ;;
    esac
}

# 4. Есть ли \r
test_cr() {
    local flags="$1" dump
    dump="$(timeout 3 docker run --rm $flags "$IMG" echo x < /dev/null 2>/dev/null | od -c | head -1)"
    case "$dump" in *'\r'*) echo "да" ;; *) echo "нет" ;; esac
}

printf '%-8s %-16s %-14s %-12s %s\n' ФЛАГИ 'sh выходит' 'stdin' 'потоки' '\\r'
printf '%s\n' "--------------------------------------------------------------------"

for flags in "" "-i" "-t" "-it"; do
    label="${flags:-(нет)}"
    printf '%-8s %-16s %-14s %-12s %s\n' \
        "$label" \
        "$(test_immediate_exit "$flags")" \
        "$(test_stdin "$flags")" \
        "$(test_streams "$flags")" \
        "$(test_cr "$flags")"
done

echo
echo "=== Безопасный запуск для скриптов и CI ==="

docker_run_safe() {
    local tty_flags="-i"
    # -t только если и stdin, и stdout — терминалы
    if [ -t 0 ] && [ -t 1 ]; then
        tty_flags="-it"
    fi
    docker run --rm $tty_flags "$@"
}

echo -n "  stdin терминал: "; [ -t 0 ] && echo "да" || echo "нет"
echo -n "  выбранные флаги: "; { [ -t 0 ] && [ -t 1 ] && echo "-it"; } || echo "-i"
echo -n "  результат: "
docker_run_safe "$IMG" echo "команда выполнена"

Запуск:

bash
chmod +x run-modes-matrix.sh
./run-modes-matrix.sh

Ожидаемый вывод при запуске из терминала:

text
ФЛАГИ    sh выходит       stdin          потоки       \r
--------------------------------------------------------------------
(нет)    да               нет            раздельны    нет
-i       да               да             раздельны    нет
-t       нет (зависает)   нет            слиты        да
-it      нет (зависает)   да             слиты        да

=== Безопасный запуск для скриптов и CI ===
  stdin терминал: да
  выбранные флаги: -it
  результат: команда выполнена

Разбор таблицы по строкам.

Без флагов. stdin закрыт, TTY нет. Оболочка читает конец файла и завершается — отсюда «container сразу упал» при docker run alpine sh. Потоки раздельны, \r нет. Это правильный режим для пакетного выполнения.

-i. stdin открыт, TTY нет. Команды из конвейера принимаются, промпта нет. Потоки по-прежнему раздельны, \r нет. Это правильный режим для скриптов, которым нужно что-то подать на вход.

-t. TTY есть, stdin закрыт. Оболочка не завершается (терминал считается интерактивным), но ввести ничего нельзя — зависает. Потоки слиты, появился \r. Комбинация без практического применения.

-it. Полноценная интерактивная сессия. Потоки слиты и \r присутствует — но для человека за терминалом это не важно, потому что вывод не парсится.

Ключевой вывод. Слитые потоки и \r — не побочный дефект, а прямое следствие того, что TTY является одним символьным устройством. Поэтому -t уместен ровно там, где по ту сторону человек, и не уместен нигде больше.

Функция docker_run_safe проверяет оба дескриптора. Проверки только [ -t 0 ] недостаточно: при ./script.sh > out.txt стандартный ввод остаётся терминалом, а вывод уже нет, и -t испортит содержимое файла символами \r.

Проверка результата

bash
docker run --rm alpine echo test | od -c | head -1
docker run --rm -t alpine echo test | od -c | head -1

Первая строка должна заканчиваться \n, вторая — \r \n. Если вы понимаете, почему, материал усвоен.

Типичные ошибки

ОшибкаПричинаИсправление
-it в скриптах и CIСкопировано из интерактивных примеровИспользовать -i или ничего; -t только для человека
the input device is not a TTY в CIФлаг -t при отсутствии терминалаУбрать -t или добавлять его условно через [ -t 0 ]
Сравнение вывода не срабатывает-t добавил \r в конец строкУбрать -t
2>/dev/null не отбрасывает stderrПри -t потоки слитыУбрать -t
Скрипт не замечает падения сервисаВ detached режиме docker run возвращает 0Проверять через docker wait или docker inspect
«Нажал Ctrl+C, а он работает»Без -t сигнал получает CLI, а не containerdocker stop
docker attach в productionСлучайный Ctrl+C останавливает сервисИспользовать docker exec
Конфликт имёнИмя занято остановленным containerdocker rm, docker rename или --rm
--rm вместе с --restartКажется, что флаги независимыВзаимоисключающие: нельзя перезапустить удалённое

Контрольные вопросы

На понимание:

  1. Что делает -i и что делает -t по отдельности?
  2. Почему docker run alpine sh завершается мгновенно?
  3. Почему при -t перенаправление 2>/dev/null перестаёт работать?
  4. Откуда берётся \r в выводе и почему это ломает скрипты?
  5. Почему в detached режиме docker run возвращает 0, даже если приложение упало?

На применение:

  1. Как передать содержимое файла на стандартный вход процесса в container?
  2. Как написать команду, работающую и в терминале, и в CI без изменений?
  3. Как получить реальный exit code приложения, запущенного в detached режиме?

На диагностику:

  1. Один и тот же скрипт работает локально и падает в CI с the input device is not a TTY. Причина и исправление?
  2. Проверка [ "$(docker run --rm -t img cmd)" = "ok" ] не срабатывает, хотя команда выводит именно ok. Что происходит?

Краткое резюме

  1. Foreground подключает потоки container к терминалу и ждёт завершения; detached возвращает ID и завершается.
  2. В detached режиме exit code docker run относится к запуску, а не к приложению.
  3. -i открывает stdin, -t выделяет pseudo-TTY — это независимые флаги.
  4. Без флагов оболочка завершается сразу: stdin закрыт.
  5. -t без -i даёт терминал без возможности ввода — практического смысла нет.
  6. При -t stdout и stderr сливаются, а в конец строк добавляется \r.
  7. В скриптах и CI -t использовать нельзя; условная подстановка — через [ -t 0 ] && [ -t 1 ].
  8. Без -t Ctrl+C прерывает CLI, но не container.
  9. attach подключается к главному процессу и опасен в production; exec запускает новый процесс.
  10. Имя уникально среди всех containers, включая остановленные; --rm освобождает его автоматически.

Официальные источники

ИсточникСсылкаЧто подтверждает
docker run referencehttps://docs.docker.com/reference/cli/docker/container/run/Флаги -d, -i, -t, --rm, --name, --sig-proxy, конфликт --rm и --restart
docker attach referencehttps://docs.docker.com/reference/cli/docker/container/attach/Подключение к главному процессу, Ctrl+P Ctrl+Q, --sig-proxy
docker rename referencehttps://docs.docker.com/reference/cli/docker/container/rename/Переименование container
docker wait referencehttps://docs.docker.com/reference/cli/docker/container/wait/Получение exit code для detached container
Docker Engine API: attachhttps://docs.docker.com/reference/api/engine/version/v1.53/#tag/Container/operation/ContainerAttachМультиплексирование потоков и его отсутствие при выделенном TTY
tty(4) man pagehttps://man7.org/linux/man-pages/man4/tty.4.htmlПоведение терминального устройства, единый канал вывода
test(1) man pagehttps://man7.org/linux/man-pages/man1/test.1.htmlПроверка -t для файлового дескриптора

Навигация

← Предыдущий материал
Вернуться к разделу
Следующий материал → Exec, logs, inspect
Главное оглавление

Markdown на GitHub ↗