Skip to main content

Як зробити образ з запущеного контейнера?

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.

Швидкий приклад

bash
$ 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.

Синтаксис

bash
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 для проду

bash
$ 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:

bash
$ 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 правильно:

bash
# 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-client

Commit це сходинка, не фінальний артефакт.

Disaster recovery

Prod-container має ручний фікс, що ще не Dockerfile-ized, і container зараз буде замінено. Commit його, щоб зберегти стан, поки Dockerfile оновлюється:

bash
$ docker commit prod-fix saved:before-redeploy # Відкрити Dockerfile PR з реальним фіксом # Як замерджено: deploy з нового Dockerfile, відправити 'saved:before-redeploy' на пенсію

Застосування Dockerfile-style змін через -c

bash
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 як механізм деплою

bash
# НЕПРАВИЛЬНО: прод-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

bash
$ 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-аналізу

bash
# На проді $ 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 з вивченого

bash
$ 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

bash
# Існуючий 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.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?