Короткий ответ
Образ — это неизменяемый шаблон (файловая система и метаданные), а контейнер — это запущенный на его основе процесс со своим тонким writable-слоем и изоляцией через namespaces/cgroups.
Как это работает подробнее
образ Docker собирается из последовательности read-only слоёв по инструкциям Dockerfile. При запуске (docker run) Docker добавляет сверху тонкий writable-слой и создаёт для процесса изолированные Linux namespaces (PID, network, mount и др.) и ограничения через cgroups — это и есть контейнер.
Пример кода
Пример конфигурации
$ docker images
REPOSITORY TAG IMAGE ID SIZE
ubuntu 22.04 3b418d7b466a 77.8MB
$ docker run -d --name test1 ubuntu:22.04 sleep 300
$ docker run -d --name test2 ubuntu:22.04 sleep 300
$ docker ps
CONTAINER ID IMAGE NAMESЧто использовать на практике
- Практика. один и тот же образ можно запустить сколько угодно раз — каждый запуск создаёт отдельный контейнер со своим состоянием и ID. Удаление контейнера (
docker rm) не удаляет образ, из которого он был создан; а образ нельзя удалить (docker rmi), пока существует хотя бы один контейнер (даже остановленный), созданный из него.
Подводные камни
- Риск. путают ID образа и ID контейнера при чтении вывода команд; ожидают, что изменения файлов внутри контейнера автоматически попадут в образ — это не так, нужен либо
docker commit(редко применяется в проде), либо правильный путь — пересобрать образ через обновлённый Dockerfile.