Як зробити образ з запущеного контейнера?
docker commit дозволяє перетворити running container на image, snapshot того стану, у якому container зараз. Спокусливо для shortcut, небезпечно для проду. Знання, коли це правильний tool, переважно про знання, коли це неправильний.
Теорія
TL;DR
docker commit <container> <image:tag>зберігає поточний стан container як новий image.- Захоплює writable-шар + base image-шари.
- Опційні флаги:
-mповідомлення,-aавтор,-cзастосувати Dockerfile-style зміни (CMD, ENV тощо). - Anti-pattern для проду. Без Dockerfile, без reproducibility, без review-сліду, без peer-review.
- Корисно для: debug-snapshot, захоплення exploratory-стану, врятувати fixed-up container перед перестворенням з Dockerfile.
Швидкий приклад
$ docker run -it --name explore alpine:3.21 sh
/ # apk add --no-cache curl
/ # echo 'custom config' > /etc/myconfig
/ # exit
$ docker commit -m 'added curl + custom config' explore my-explorer:0.1
sha256:abc123...
$ docker run --rm my-explorer:0.1 sh -c 'which curl && cat /etc/myconfig'
/usr/bin/curl
custom configЗміни інтерактивної сесії тепер запечено у новий image.
Синтаксис
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# Поширені опції
-m "message" # commit message (видно у docker history)
-a "author" # ім'я автора
-p / --pause=false # за замовчуванням container pause під час commit; --pause=false скіпає pause
-c "INSTRUCTION" # застосувати Dockerfile-інструкцію (CMD, ENV, EXPOSE, USER, WORKDIR, LABEL)Чому це anti-pattern для проду
$ docker commit web myorg/web:1.0Що саме це за image:
- Snapshot того, що container мав у цей момент.
- Включає усе у writable-шарі: встановлені пакети, config-tweaks, випадкові файли.
- Жодного запису, як його перестворити.
Проблеми:
- Не reproducible. Якщо втратиш image, не можеш перебудувати з source.
- Без code review. Зміна Dockerfile іде через PR;
docker commitні. - Приховані side-effect. Усе, що container робив у runtime (логи, scratch-файли), приземляється у image.
- Image bloat. Анонімні шари, без cache-переваг, без
.dockerignore. - Drift. Image це що людина набрала у container, не versioned-рецепт.
У проді: пиши Dockerfile, комітуй у git, збирай через CI. Завжди.
Легітимні use
Debug-snapshot
Prod container проблемний. Хочеш заморожену копію для розслідування пізніше без тримання живого container:
$ docker commit -m 'snapshot before restart' broken-prod debug:broken-2026-04-30
$ docker push myreg/debug:broken-2026-04-30 # поділитися з командоюТепер можеш docker run snapshot у sandbox для розслідування.
Захоплення exploratory-роботи
Ти з'ясовуєш, які пакети потрібні image. Ітеруй всередині container, тоді commit, коли запрацювало, і використай це, щоб написати Dockerfile правильно:
# Exploration
$ docker run -it --name explore alpine sh
/ # apk add --no-cache curl jq postgresql-client
/ # exit
# Захопити стан
$ docker commit explore exploration:scratch
# Тепер пиши Dockerfile з того, що дізнався:
# FROM alpine
# RUN apk add --no-cache curl jq postgresql-clientCommit це сходинка, не фінальний артефакт.
Disaster recovery
Prod-container має ручний фікс, що ще не Dockerfile-ized, і container зараз буде замінено. Commit його, щоб зберегти стан, поки Dockerfile оновлюється:
$ docker commit prod-fix saved:before-redeploy
# Відкрити Dockerfile PR з реальним фіксом
# Як замерджено: deploy з нового Dockerfile, відправити 'saved:before-redeploy' на пенсіюЗастосування Dockerfile-style змін через -c
docker commit -c 'CMD ["/bin/bash"]' -c 'ENV PATH=/app/bin:$PATH' explore my-tweaked:0.1-c приймає підмножину Dockerfile-інструкцій: CMD, ENTRYPOINT, ENV, EXPOSE, LABEL, USER, VOLUME, WORKDIR. Корисно для коригування метаданих без входу у shell.
Типові помилки
Сприймати docker commit як механізм деплою
# НЕПРАВИЛЬНО: прод-image через commit
$ docker exec api npm install some-package
$ docker commit api myreg/api:1.1
$ docker push myreg/api:1.1Через шість місяців ніхто не знає, що у myreg/api:1.1. Dockerfile каже одне, image інше. Бери Dockerfile + CI білд + push.
Забути, що pause за замовчуванням
docker commit за замовчуванням pause container, щоб забезпечити консистентність. Для довгих commit або high-throughput сервісів цей pause видно. Бери --pause=false, якщо толеруєш inconsistency.
Committing container з secret у env
$ docker run -e DB_PASSWORD=hunter2 myapp
$ docker commit myapp leaked:image
# `leaked:image` тепер має DB_PASSWORD=hunter2 у config
$ docker inspect leaked:image --format '{{json .Config.Env}}' | jq
["DB_PASSWORD=hunter2", ...]Committing запікає runtime-env у image. Push такого, і ти злив secret кожному, хто pull'ить.
Сприймати commit-image як immutable-історію
На відміну від Dockerfile-built image, не можеш легко diff два docker commit image. Втрата reproducibility накопичується: image A → tweak → commit → image B → tweak → commit → image C. Через три тижні ніхто не знає, що у будь-якому з них.
Реальне застосування
- Hotfix-snapshot: прод-container має ручний фікс; commit перед знесенням; пізніше перетвори фікс на зміну Dockerfile.
- Debug-image для support-команди: commit problem-container, push у приватний registry, поділись з тими, хто має розслідувати.
- Onboarding playground: commit customized dev-container з командними tools, тож нові деви
docker runраз і мають усе. - Migration freeze: під час multi-step міграції, де running container це source of truth; commit на milestone для rollback-опцій.
Питання для поглиблення
Q: Яка різниця між docker commit і docker save?
A: commit створює НОВИЙ image з container. save експортує існуючий image у tarball. Зовсім різні use case.
Q: Як побачити зміни, що commit захопив?
A: docker diff <container> ПЕРЕД commit показує, що змінилося у writable-шарі. Після commit docker history нового image перелічує це як один великий шар з твоїм повідомленням.
Q: Чи можна commit stopped container?
A: Так. Writable-шар ще там, поки не зробиш docker rm.
Q: Чи новий image успадковує оригінальну команду, env тощо?
A: Так, image-config успадковує від оригінального image. Бери -c флаги під час commit, щоб override конкретні частини (CMD, ENV тощо).
Q: (Senior) Коли docker commit активно небезпечний?
A: Коли стає механізмом деплою. Команди, що commit-tweak-commit, втрачають Dockerfile-дисципліну, провалюють аудити, не можуть reproduc'нути білди і накопичують «працює на сервері» магію. Перший знак: source-repo Dockerfile більше не відображає прод-image. Трактуй docker commit виключно як debugging-tool, ніколи як build-крок.
Приклади
Snapshot проблемного прод-container для offline-аналізу
# На проді
$ docker commit -m 'OOM-killing every 5 min - 2026-04-30' \
api debug-snapshots:api-oom-2026-04-30
$ docker tag debug-snapshots:api-oom-2026-04-30 myreg/debug:api-oom-2026-04-30
$ docker push myreg/debug:api-oom-2026-04-30
# У dev
$ docker pull myreg/debug:api-oom-2026-04-30
$ docker run -it --rm --entrypoint sh myreg/debug:api-oom-2026-04-30
# Тепер копай у тому ж стані, у якому був прод.Ітерація, commit, написання Dockerfile з вивченого
$ docker run -it --name lab python:3.13-slim bash
root@lab:/# pip install --no-cache-dir requests pyyaml psycopg2-binary
root@lab:/# echo 'export FOO=bar' >> /root/.bashrc
root@lab:/# exit
$ docker commit lab my-lab:0.1
# Написав еквівалентний Dockerfile на основі того, що спрацювало:
# FROM python:3.13-slim
# RUN pip install --no-cache-dir requests pyyaml psycopg2-binary
# ENV FOO=barВикористовуй commit, щоб захопити стан під час exploration; потім переклади у Dockerfile для проду.
Застосувати config-зміни через -c
# Існуючий image, додати labels і змінити дефолтний CMD
$ docker commit \
-c 'LABEL maintainer="team@example.com"' \
-c 'CMD ["/bin/bash"]' \
-c 'ENV TZ=UTC' \
explore tweaked:0.1Дешевше, ніж перебудовувати, коли просто хочеш скоригувати метадані на snapshot існуючого image.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів