1С в Docker: почему удалённый установщик остаётся в образе
Разработка - DevOps и автоматизация разработки
Файлы
ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.
Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний
Оформите подписку на компанию для решения рабочих задач
Оформить подписку и скачать решение со скидкойВы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
docker-layerlab.zip (1 SM): скрипт reproduce_lab.py, анализатор image_report.py, эталонные JSON/JSONL и протокол замеровpython reproduce_lab.py --base debian:12 --prefix layerlab --out run и последующий анализ через image_report.pyИнженерное исследование для специалистов 1С и DevOps: как устроены слои Docker на самом деле и почему популярная инструкция «скопировать deb-пакеты платформы, установить и сделать rm» раздувает образ сервера на 500–900 МБ. Мы препарируем устройство union-файловой системы на детерминированном микро-стенде, сравниваем два правильных способа сборки (Bind Mount vs Multi-stage) и даем готовые шаблоны Dockerfile для производственного (production) сервера 1С:Предприятие.
- Слои Docker неизменяемы (immutable / copy-on-write): любая операция rm в отдельной инструкции RUN не удаляет данные из нижнего слоя, а лишь пишет метку whiteout в верхний.
- BuildKit bind mount (
RUN --mount=type=bind) — золотой стандарт для 1С: пакеты монтируются только на время установки и вообще не попадают в историю слоев. - Многоэтапная сборка (multi-stage) подходит для переноса готовых каталогов (например, клиента или утилит), но для сервера требует осторожности из-за системных зависимостей.
- Парадокс размеров: в containerd image store поле inspect.Size может быть вдвое больше суммы слоев history.Size из-за одновременного учета сжатых и распакованных данных.
Чистый образ сервера 1С достигается не удалением временных файлов через rm, а исключением дистрибутива из промежуточных слоев сборки.
1С в Docker: почему удалённый установщик остаётся в образе
Исследуем иллюзию очистки слоев через rm, препарируем файловую систему Docker на цифрах и переводим сборку контейнеров 1С:Предприятие на современные механизмы BuildKit.
Для кого: 1С-разработчики, DevOps-инженеры и системные администраторы, собирающие и оптимизирующие Docker-образы для серверов, фоновых заданий и сборочных агентов 1С.
- Проблема: куда исчезают гигабайты в образе 1С
- Шпаргалка инженера: как правильно собирать образ
- Антипаттерн на практике: COPY и удаление в следующем RUN
- Решение 1 (Рекомендуемое): Временный дистрибутив через BuildKit bind mount
- Решение 2: Отдельный завершающий этап (Multi-stage)
- Парадокс размеров: почему history.Size и inspect.Size не совпадают
- Как проверить свой образ и воспроизвести эксперимент
- Приёмка платформы и лицензирования после оптимизации
- Итог и чек-лист для production
🚨 Проблема: куда исчезают гигабайты в образе 1С
В практике контейнеризации 1С регулярно встречается классический Dockerfile:
Логика автора кажется прозрачной: дистрибутив скопировали, пакеты сервера и клиента платформы установили, а затем удалили временную папку командой rm -rf, рассчитывая, что итоговый образ уменьшится.
Но на практике происходит неприятный сюрприз: образ сервера 1С весит 2.5–3.0 ГБ вместо ожидаемых 1.2–1.5 ГБ. Заглядывая внутрь запущенного контейнера через docker exec, администратор видит, что каталога /tmp/dist действительно нет. Куда же делись сотни мегабайт?
Причина кроется в базовой архитектуре Docker: слои неизменяемы (immutable, Copy-on-Write). Инструкция COPY создала отдельный read-only слой, куда намертво записала 800 МБ дистрибутива. Следующая инструкция RUN при удалении файла не может переписать нижний слой — она лишь создает специальную whiteout-запись в новом слое оверлея, помечая файлы удаленными для видимой файловой системы.
Цена этой иллюзии в продакшене высока:
- Раздутый CI/CD трафик: при каждой сборке и доставке раннеры выгружают и скачивают лишний почти гигабайт неизвлекаемого балласта;
- Забитый реестр образов: хранилища Harbor / Nexus быстро переполняются мертвыми слоями;
- Медленный холодный старт: развертывание новых подов в Kubernetes или нод в Swarm задерживается на время передачи неиспользуемых байтов.
💡 Шпаргалка инженера: как правильно собирать образ
Прежде чем погружаться в детальные побайтовые замеры, зафиксируем практическую матрицу выбора архитектуры сборки:
| Подход | Влияние на размер | Сложность | Вердикт для экосистемы 1С |
|---|---|---|---|
| 1. COPY + последующий rm | +100% веса дистрибутива в слоях (балласт) | Простая | Антипаттерн. Дистрибутив скрыт из файловой системы, но навсегда запечен в нижнем слое. |
2. BuildKit Bind Mount (--mount=type=bind) |
0 байт оверхеда (дистрибутив не пишется в слои) | Одна опция в RUN |
Основной выбор для сервера 1С. Пакеты монтируются на лету, зависимости ОС ставятся штатно, образ минимален. |
| 3. Многоэтапная сборка (Multi-stage) | 0 байт оверхеда (в финал переносится только результат) | Средняя (два этапа FROM) |
Выбор для утилит и автономных бинарников (OneScript, EDT CLI, тонкий клиент). Для сервера 1С требует аккуратного переноса системных библиотек. |
Чтобы доказать эти выводы математически точно и исключить погрешности закрытого коммерческого кода, мы построили детерминированный микро-стенд.
payload.dat строго фиксированного размера 16 777 216 байт (ровно 16 МиБ), сгенерированный скриптом на Python (seed=1801). Установка имитируется извлечением первых 4096 байт в целевой артефакт /opt/demo/artifact.bin. Тесты выполнены на Docker Engine 29.8.0 с BuildKit на базе образа Debian 12 (sha256:f37a335e...).📂 Антипаттерн на практике: COPY и удаление в следующем RUN
Первый вариант моделирует ту самую распространенную ошибку: установщик копируется в образ отдельной инструкцией, а затем удаляется в шаге установки.
После сборки проверяем запущенный контейнер: команда test ! -e /tmp/payload.dat возвращает успех — файла в файловой системе нет. Однако команда инспекции истории образа docker image history вскрывает реальную картину:
IMAGE CREATED BY SIZE <missing> RUN /bin/sh -c mkdir -p /opt/demo && head -c... 20.5kB <missing> COPY payload.dat /tmp/payload.dat # buildkit 16.8MB <missing> /bin/sh -c #(nop) ADD file:... in / 133MB
- Слой
COPYсохранил 16 785 408 байт (16.01 МиБ) исходного файла. Он навечно остался в образе. - Инструкция
RUN ... rmне уменьшила предыдущий слой, а добавила ещё 20 480 байт метаданных (целевой артефакт + запись об удалении). - Объединение установки и очистки в один длинный
RUNздесь бессильно: файл попал в отдельный слой на предыдущей строкеCOPY.
💻 Решение 1 (Рекомендуемое): Временный дистрибутив через BuildKit bind mount
Чтобы файл дистрибутива вообще не попадал в слои, современный сборщик BuildKit предоставляет механизм монтирования контекста сборки: RUN --mount=type=bind. Дистрибутив становится доступен контейнеру исключительно на время выполнения команды и только для чтения.
Обратите внимание: здесь даже нет команды rm. Источник подключен временно. Всё, что прочитано из /tmp/payload.dat, используется процессом установки, а в итоговый слой попадает только созданный файл /opt/demo/artifact.bin.
История образа docker image history:
IMAGE CREATED BY SIZE <missing> RUN --mount=type=bind,source=payload.dat,tar... 16.4kB <missing> /bin/sh -c #(nop) ADD file:... in / 133MB
- Слой установщика 16 МиБ полностью отсутствует в истории.
- В образе появился ровно один рабочий слой размером 16 384 байта, содержащий готовый артефакт.
- Экономия размера составила ровно 16 789 504 байта. Контрольная сумма артефакта полностью совпала с эталоном.
Готовый пример для сервера 1С:Предприятие 8.3
В реальном проекте с дистрибутивом платформы 1С это решение выглядит так:
💻 Решение 2: Отдельный завершающий этап (Multi-stage)
Второй классический паттерн — многоэтапная сборка. Все грязные операции (копирование дистрибутива, распаковка, компиляция) выполняются на промежуточном этапе, а в финальный образ забирается только итоговый каталог через COPY --from=build.
В истории итогового образа снова остаются ровно два слоя: базовый образ и слой COPY --from=build размером 16 384 байта. Слой с установщиком остался на этапе build и в финальный образ не попал.
Многоэтапная сборка отлично работает для утилит (OneScript, EDT CLI, gitsync), но опасна при установке полноценного сервера 1С простым копированием папки
/opt/1cv8. Пакетная установка через dpkg регистрирует системных пользователей (usr1cv8), настраивает службы systemd/init, прописывает пути библиотек в /etc/ld.so.conf.d/ и ставит зависимости. Простое копирование файлов оставляет сервер без системного окружения. Поэтому для сервера 1С приоритетом является Решение 1 (Bind Mount).📊 Парадокс размеров: почему history.Size и inspect.Size не совпадают
Сравним первичные данные всех трех сборок, зафиксированные тестовым раннером:
| Вариант сборки | Слоев RootFS | Сумма history.Size | Размер inspect.Size | Результат |
|---|---|---|---|---|
| 1. COPY + rm (Антипаттерн) | 3 | 149.6 МБ (149 647 360 Б) | 214.9 МБ (214 939 565 Б) | Балласт +16 МиБ |
| 2. RUN с bind mount | 2 | 132.8 МБ (132 857 856 Б) | 181.3 МБ (181 367 031 Б) | Чистый образ |
| 3. Multi-stage этап | 2 | 132.8 МБ (132 857 856 Б) | 181.3 МБ (181 366 974 Б) | Чистый образ |
Здесь внимательный инженер сразу обратит внимание на два момента:
- Разница в
history.Sizeстрого равна размеру файла: разница сумм между Вариантом 1 и оптимизированными вариантами составила ровно 16 789 504 байта (16 МиБ установщика + 4 КБ служебного оверхеда слоя). Чистая математика. - Разница в
inspect.Sizeвнезапно составила 33 572 534 байта (33.5 МБ) — вдвое больше! Почему?
Разгадка парадокса: на современных версиях Docker Desktop и серверных движках по умолчанию активирован containerd image store (io.containerd.snapshotter.v1). В отличие от старого драйвера overlay2, containerd хранит в метаданных inspect.Size суммарное дисковое пространство: и сжатые tar-архивы слоев, и их распакованные снапшоты. Поэтому «забытый» в слое файл на диске сборщика раздувает потребление пространства в двойном размере.
🔍 Как проверить свой образ и воспроизвести эксперимент
1. Экспресс-аудит рабочего образа 1С
Чтобы прямо сейчас узнать, не прячутся ли в вашем образе старые дистрибутивы, выполните две команды:
# Посмотреть все слои и команды сборщика без обрезания
docker image history --no-trunc --human=true YOUR_IMAGE_NAME
# Найти подозрительно тяжелые промежуточные слои COPY
docker image history --format "{{.CreatedBy}}: {{.Size}}" YOUR_IMAGE_NAME | grep -E "COPY|ADD"
Если среди строк вы видите COPY dist или ADD server64.tar.gz с размером в сотни мегабайт — ваш образ страдает от антипаттерна, и перевод сборки на bind mount моментально сбросит лишний вес.
2. Воспроизведение лабораторного эксперимента (архив-компаньон)
Для автономной проверки без необходимости скачивать гигабайты 1С в архиве за 1 SM приложен воспроизводимый раннер:
# Запуск сквозного прогона трех сборок (требует Docker с BuildKit): python reproduce_lab.py --base debian:12 --prefix my-lab --out my-run # Запуск анализатора первичных JSON-логов (работает автономно без Docker): python image_report.py examples/split.inspect.json examples/bind.inspect.json examples/staged.inspect.json --history examples/split.history.jsonl examples/bind.history.jsonl examples/staged.history.jsonl
🔒 Приёмка платформы и лицензирования после оптимизации
Успешная оптимизация веса образа — это только половина задачи. В экосистеме «1С:Предприятие» ключевым барьером контейнеризации остается программное лицензирование.
Иногда в погоне за компактностью инженеры вырезают зависимости или переходят на alpine/минималистичные дистрибутивы, после чего ломается механизм формирования аппаратного хэша (.lic) или перестает запускаться служба лицензирования. Важно помнить:
- Официальный список ОС: на текущий момент вендор официально поддерживает сервер x86-64 на дистрибутивах Debian 12 и Ubuntu 22.04 LTS. Сборка на их slim-версиях безопасна с точки зрения ядра и библиотек glibc;
- Программные лицензии привязаны к окружению: одного монтирования каталога с файлами
.licнедостаточно. Изменение MAC-адреса, hostname, параметров виртуализации или состава оборудования хоста аннулирует программную лицензию; - Разделение контуров проверки: проверка веса образа и проверка привязки лицензий должны идти раздельными этапами.
| Сценарий приемки | Что фиксировать в журнале |
|---|---|
| 1. Первый запуск оптимизированного образа | Версии платформы, наличие библиотек ldd /opt/1cv8/..., источник лицензирования (HASP / программная), успешный вход тестового клиента. |
2. Перезапуск контейнера (docker restart) |
Повторный вход клиентов, отсутствие запроса повторной активации пин-кода. |
3. Пересоздание контейнера (docker rm && docker run) |
Корректность сохранения данных в persistent volumes (/home/usr1cv8/.1cv8), сохранение hostname и сетевых идентификаторов. |
| 4. Обновление минорного релиза 1С | Контроль чистоты слоев в history нового релиза, корректный запуск кластера серверов. |
🏁 Итог и чек-лист для production
Проведенное исследование дает однозначный ответ: попытка удалить установщик через rm после COPY не работает. На синтетическом тесте в 16 МиБ мы увидели ровно 16 МиБ балласта, а на реальном дистрибутиве 1С это выливается в 500–900 МБ паразитного веса.
Для производственных конвейеров доставки 1С держите под рукой краткий чек-лист:
- Включите BuildKit: экспортируйте
DOCKER_BUILDKIT=1в CI/CD пайплайнах; - Используйте
RUN --mount=type=bindдля тяжелых deb/rpm пакетов: это защищает слои от попадания дистрибутивов без усложнения Dockerfile; - Контролируйте историю перед публикацией: проверяйте
docker image historyна наличие случайных слоевCOPYразмером более нескольких мегабайт; - Разделяйте сервер и вспомогательные сервисы: многоэтапную сборку используйте для независимых утилит, а для сервера 1С сохраняйте целостность системных пакетов ОС.
Вступайте в нашу телеграмм-группу Инфостарт
См. также
5000 руб.
05.05.2026 1649 1 4
02.11.2026 414 vanya_gonchar 2
21.10.2026 358 capitan 0
1 стартмани
12.10.2026 283 Ninel_S 0
1 стартмани
12.10.2026 268 Ninel_S 0
08.10.2026 2356 deda 29