1С в Docker: почему удалённый установщик остаётся в образе

12.10.26

Разработка - DevOps и автоматизация разработки

Исследуем, почему COPY и последующий rm оставляют установщик в слоях Docker. На Docker Engine 29.8.0 сравнила три сборки с фиктивным дистрибутивом: bind mount и отдельный завершающий этап исключили его слой. В статье — первичные размеры и границы проверки лицензирования 1С; в архиве — воспроизводитель и анализатор inspect/history.

Файлы

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование Скачано Купить файл
Проверка слоёв Docker: воспроизводимый опыт и анализатор
.zip 15,58Kb ver:1.0
0 2 500 руб. Купить

Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний

Оформите подписку на компанию для решения рабочих задач

Оформить подписку и скачать решение со скидкой

Вы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.
🐳 1С в Docker & DevOps
🎯 О чём это (в трёх тезисах)
🗸Команда rm не уменьшает размер образа: если дистрибутив 1С попал в образ через COPY, удаление в следующем RUN лишь скрывает файлы из ls, оставляя до 900 МБ мертвого груза в слоях.
🗸BuildKit bind mount исключает слой установщика: монтирование пакетов на лету через RUN --mount=type=bind решает проблему в одну строчку без раздувания истории и потери системных зависимостей.
🗸Экономия слоев не гарантирует привязку лицензии: уменьшение веса образа и стабильность программного лицензирования платформы 1С требуют раздельной приемочной проверки.
🧪 Отчёт о тестировании файла-компаньона
Архивdocker-layerlab.zip (1 SM): скрипт reproduce_lab.py, анализатор image_report.py, эталонные JSON/JSONL и протокол замеров
Где и когда11.10.2026, Windows 11 Pro (build 22631), Python 3.12.10, Docker Engine 29.8.0 с BuildKit, базовый образ debian:12
Что запускалосьpython reproduce_lab.py --base debian:12 --prefix layerlab --out run и последующий анализ через image_report.py
РезультатТри сборки подтвердили: bind mount и multi-stage устраняют 16 МиБ балласта, артефакт совпадает по SHA-256; зафиксирован оверхед containerd snapshotter
Не провереноПрограммные лицензии 1С и HASP (требуют отдельного стенда активации)
🧠 Суть статьи

Инженерное исследование для специалистов 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. Проблема: куда исчезают гигабайты в образе 1С
  2. Шпаргалка инженера: как правильно собирать образ
  3. Антипаттерн на практике: COPY и удаление в следующем RUN
  4. Решение 1 (Рекомендуемое): Временный дистрибутив через BuildKit bind mount
  5. Решение 2: Отдельный завершающий этап (Multi-stage)
  6. Парадокс размеров: почему history.Size и inspect.Size не совпадают
  7. Как проверить свой образ и воспроизвести эксперимент
  8. Приёмка платформы и лицензирования после оптимизации
  9. Итог и чек-лист для production

🚨 Проблема: куда исчезают гигабайты в образе 1С

В практике контейнеризации 1С регулярно встречается классический Dockerfile:

Типичный любительский Dockerfile 1С (Антипаттерн) UTF-8
FROM debian:12
COPY ./dist /tmp/dist
RUN dpkg -i /tmp/dist/*.deb && rm -rf /tmp/dist

Логика автора кажется прозрачной: дистрибутив скопировали, пакеты сервера и клиента платформы установили, а затем удалили временную папку командой 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

Первый вариант моделирует ту самую распространенную ошибку: установщик копируется в образ отдельной инструкцией, а затем удаляется в шаге установки.

Dockerfile (Вариант 1 — Скрытый оверхед) UTF-8
1
2
3
4
5
FROM debian:12-base
COPY payload.dat /tmp/payload.dat
RUN mkdir -p /opt/demo     && head -c 4096 /tmp/payload.dat > /opt/demo/artifact.bin     && rm -f /tmp/payload.dat

После сборки проверяем запущенный контейнер: команда 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
Инженерный вывод по Варианту 1:
  • Слой COPY сохранил 16 785 408 байт (16.01 МиБ) исходного файла. Он навечно остался в образе.
  • Инструкция RUN ... rm не уменьшила предыдущий слой, а добавила ещё 20 480 байт метаданных (целевой артефакт + запись об удалении).
  • Объединение установки и очистки в один длинный RUN здесь бессильно: файл попал в отдельный слой на предыдущей строке COPY.

💻 Решение 1 (Рекомендуемое): Временный дистрибутив через BuildKit bind mount

Чтобы файл дистрибутива вообще не попадал в слои, современный сборщик BuildKit предоставляет механизм монтирования контекста сборки: RUN --mount=type=bind. Дистрибутив становится доступен контейнеру исключительно на время выполнения команды и только для чтения.

Dockerfile (Вариант 2 — Чистый BuildKit Mount) UTF-8
1
2
3
4
FROM debian:12-base
RUN --mount=type=bind,source=payload.dat,target=/tmp/payload.dat     mkdir -p /opt/demo     && head -c 4096 /tmp/payload.dat > /opt/demo/artifact.bin

Обратите внимание: здесь даже нет команды 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
Инженерный вывод по Варианту 2:
  • Слой установщика 16 МиБ полностью отсутствует в истории.
  • В образе появился ровно один рабочий слой размером 16 384 байта, содержащий готовый артефакт.
  • Экономия размера составила ровно 16 789 504 байта. Контрольная сумма артефакта полностью совпала с эталоном.

Готовый пример для сервера 1С:Предприятие 8.3

В реальном проекте с дистрибутивом платформы 1С это решение выглядит так:

Профессиональный Dockerfile: Сервер 1С без мусора в слоях BuildKit
# syntax=docker/dockerfile:1
FROM debian:12-slim

# Установка системных зависимостей платформы
RUN apt-get update && apt-get install -y --no-install-recommends     ca-certificates fontconfig locales libglib2.0-0     && rm -rf /var/lib/apt/lists/*

# Монтируем локальную папку с deb-пакетами 1С без копирования в образ
RUN --mount=type=bind,source=./dist_1c,target=/tmp/dist     dpkg -i /tmp/dist/1c-enterprise-8.3.*.deb     && rm -rf /var/lib/apt/lists/*

# Установщик исчезнет сразу после завершения RUN, в слое останется только /opt/1cv8

💻 Решение 2: Отдельный завершающий этап (Multi-stage)

Второй классический паттерн — многоэтапная сборка. Все грязные операции (копирование дистрибутива, распаковка, компиляция) выполняются на промежуточном этапе, а в финальный образ забирается только итоговый каталог через COPY --from=build.

Dockerfile (Вариант 3 — Multi-stage) UTF-8
1
2
3
4
5
6
7
8
FROM debian:12-base AS build
COPY payload.dat /tmp/payload.dat
RUN mkdir -p /opt/demo     && head -c 4096 /tmp/payload.dat > /opt/demo/artifact.bin     && rm -f /tmp/payload.dat

FROM debian:12-base
COPY --from=build /opt/demo/artifact.bin /opt/demo/artifact.bin

В истории итогового образа снова остаются ровно два слоя: базовый образ и слой COPY --from=build размером 16 384 байта. Слой с установщиком остался на этапе build и в финальный образ не попал.

🚨 Важное предостережение для сервера 1С:
Многоэтапная сборка отлично работает для утилит (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 Б) Чистый образ

Здесь внимательный инженер сразу обратит внимание на два момента:

  1. Разница в history.Size строго равна размеру файла: разница сумм между Вариантом 1 и оптимизированными вариантами составила ровно 16 789 504 байта (16 МиБ установщика + 4 КБ служебного оверхеда слоя). Чистая математика.
  2. Разница в 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С держите под рукой краткий чек-лист:

  1. Включите BuildKit: экспортируйте DOCKER_BUILDKIT=1 в CI/CD пайплайнах;
  2. Используйте RUN --mount=type=bind для тяжелых deb/rpm пакетов: это защищает слои от попадания дистрибутивов без усложнения Dockerfile;
  3. Контролируйте историю перед публикацией: проверяйте docker image history на наличие случайных слоев COPY размером более нескольких мегабайт;
  4. Разделяйте сервер и вспомогательные сервисы: многоэтапную сборку используйте для независимых утилит, а для сервера 1С сохраняйте целостность системных пакетов ОС.
 
Нинель Адольевна Щербакова
Нинель Адольевна Щербакова (Ninel_S)
Архитектор • SRE & DevOps инженер • HighLoad 1С
Автор технических публикаций на Infostart. Разработчик NOPik, SRE-Suite-for-1C и мультиагентных ассистентов для экосистемы 1С:Предприятие.

Вступайте в нашу телеграмм-группу Инфостарт

1С Docker BuildKit Dockerfile Linux лицензирование слои образа

См. также

DevOps и автоматизация разработки Групповая разработка (Git, хранилище) Разработчик 1С:Предприятие 8 Россия Бесплатно (free)

Практическое руководство для команд, которые хотят уйти с хранилища конфигурации на git, не переходя на новую среду разработки. Подойдёт разработчикам и тимлидам, которые настраивают командную разработку на типовых и собственных конфигурациях.

02.11.2026    414    vanya_gonchar    2    

4

DevOps и автоматизация разработки Групповая разработка (Git, хранилище) Файловый обмен (TXT, XML, DBF), FTP Системный администратор Разработчик 1С 8.5 Бесплатно (free)

Выгрузка типовой Бухгалтерии в XML через базу занимает больше четырёх минут. Я написал движок, который читает файл конфигурации напрямую и выгружает его за 35 секунд, совпадая с выгрузкой платформы байт в байт во всех 90 385 файлах. Загрузка обратно тоже работает: круг через платформу совпадает полностью. Рассказываю, как ускоряли, как проверяем и что при загрузке XML теряет сама платформа. А в конце спрашиваю, нужно ли это кому-то, кроме меня, и на какой конфигурации проверить следующей.

27.10.2026    845    oyti    20    

16

Linux Системный администратор 1С:Предприятие 8 Бесплатно (free)

Скрипт bash для корректного обновления серверной части платформы 1С Предприятия (сохраняет и восстанавливает настройки служб, даже если их несколько, изменяет версию платформы во всех веб-публикациях и делает еще много полезных мелочей не включенных в штатный инсталлятор) Иными словами "обновление под ключ" или "нажал и забыл"

21.10.2026    358    capitan    0    

5

DevOps и автоматизация разработки Разработчик Бесплатно (free)

Как поднять n8n в Docker и выполнить в нём код OneScript. Три сценария: простой, Осень и ветки схемы.

13.10.2026    542    johnnyshut23    7    

4

Управление проектом (PMO, EPM) Тестирование QA Разработчик Руководитель проекта 1С 8.3 Абонемент ($m)

Инженерный регламент для команд, разрабатывающих на платформе «1С:Предприятие» для зарубежного заказчика: правовые границы удалённого доступа (EDPB, регуляторные ограничения), построение строгого контракта данных (Data Contract) и независимая проверяемая приёмка выгрузок. В архиве-компаньоне — готовый офлайн-валидатор на Python с защитой от ошибок округления Decimal, эталонные наборы и криптографическая фиксация SHA-256.

1 стартмани

12.10.2026    283    Ninel_S    0    

1

Рефакторинг и качество кода Тестирование QA Разработчик 1С 8.3 Абонемент ($m)

Инженерный анализ влияния (Impact Analysis) при изменении общего метода в 1С:Предприятии: почему штатный поиск ссылок скрывает 99% зависимостей и как обратный обход графа вызовов выявляет 370 скрытых потребителей на глубине 3 уровней. В статье — верификация сквозной цепочки обмена с маркетплейсом; в архиве-компаньоне — автономный BFS-анализатор на Python, слепки графа и план регрессионного тестирования.

1 стартмани

12.10.2026    268    Ninel_S    0    

2

Нейросети DevOps и автоматизация разработки Разработчик Руководитель проекта 1С 8.3 1С 8.5 Бесплатно (free)

Полтора месяца ИИ-агенты писали мне коммерческое расширение 1С. Я поднял журналы всех сессий и сложил по прайсу: $13 365, из них 94 % — за то, что агент заново перечитывает уже известное. Разбор счёта, три дыры, правила, которые вчетверо удешевили шаг, и скрипт, чтобы посчитать свой.

08.10.2026    2356    deda    29    

16
Для отправки сообщения требуется регистрация/авторизация