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

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

Коментарі

Ще немає коментарів