Спокуса знайома: зайти в контейнер (docker exec -it app bash), встановити пакет, виправити конфіг - «і все запрацювало». А потім зберегти результат як образ:
docker commit app myapp:fixed
Чому це погана практика:
- зміни зникнуть: записуваний шар контейнера знищується разом з контейнером. Наступний деплой, перезапуск оркестратором, масштабування - і ручні виправлення втрачено;
- невідтворюваність: образ з
docker commit- «чорна скринька». Ніхто не знає, які саме команди виконано, в якому порядку, з якими версіями. Повторити збирання неможливо; - немає історії в Git: зміни не проходять рев'ю, не прив'язані до коміту, їх не відкотити;
- сміття в образі: кеш менеджерів пакетів, логи, тимчасові файли, історія команд - усе, що було в контейнері, потрапляє в образ;
- секрети: якщо в контейнері були токени чи ключі - вони тепер в образі.
Принцип незмінної інфраструктури: контейнери не «лагодять», а замінюють. Виправлення - у Dockerfile чи конфігурації, новий образ, новий деплой.
Як правильно розслідувати й виправляти:
- зайти в контейнер, щоб з'ясувати проблему (це нормально);
- перенести виправлення в Dockerfile, конфіг у репозиторії чи змінні оточення;
- зібрати новий образ і задеплоїти.
Що бачити, що змінено в контейнері:
docker diff app
# A /var/www/html/storage/logs/laravel.log (додано)
# C /usr/local/etc/php/conf.d (змінено)
# D /tmp/cache (видалено)
Корисно для розслідування: що саме записує застосунок у файлову систему контейнера (і чи не варто це винести в том чи tmpfs).
Коли docker commit доречний:
- зберегти стан для розслідування інциденту чи криміналістики - заморозити контейнер, щоб вивчити пізніше;
- разові експерименти локально, які не підуть у продакшен.
Захист від спокуси в продакшені: файлова система лише для читання (read_only: true) - ручні зміни просто неможливі, а помилки конфігурації виявляються одразу.