Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як зробити образ з запущеного контейнера?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`docker commit`** робить snapshot running (або stopped) container у новий image. Корисно для debug-snapshot і exploratory-роботи, але **не для проду**, бо image opaque (без Dockerfile, без reproducible-рецепта). ```bash docker commit -m "after manual fix" -a "alice" web myorg/web:hotfix docker images # myorg/web hotfix ... moments ago ``` **Головне:** для debug або захоплення стану нормально. Для прод-image пиши Dockerfile. Dockerfile це єдиний reproducible, reviewable, version-controlled спосіб шиппити image.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`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.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.