Современную инфраструктуру уже сложно представить без контейнеров, а умение применять Docker стало одним из важнейших профессиональных навыков DevOps-инженера.
Кратко напомню, почему Docker так популярен:
-
Он упрощает разработку и тестирование. Приложение со всеми библиотеками и зависимостями можно собрать в единый образ, чтобы многократно его переиспользовать: как для разных разработчиков, так и в контуре тестирования. Благодаря этому ускоряются процессы разработки и проверки изменений.
-
Docker обеспечивает переносимость приложений между разными операционными системами – Linux, MacOS и Windows. Есть небольшие нюансы, но в целом это работает.
-
Он позволяет изолировать приложения.
-
При этом достигается значительно более эффективное использование ресурсов по сравнению с классическими виртуальными машинами – что особенно полезно при построении микросервисных архитектур.
-
Также Docker упрощает работу с базами данных и различными приложениями. Вам не нужно настраивать окружение вручную и разбираться с зависимостями – можно просто взять готовые образы и быстро их развернуть.
-
Поддерживает микросервисную архитектуру – когда приложение состоит из множества компонентов. В случае, если они находятся на одном сервере, их нужно друг от друга изолировать. Поскольку Docker эффективно использует ресурсы, это удобно сделать с помощью контейнеризации.
-
Позволяет масштабироваться – вы можете увеличивать количество экземпляров приложений при росте нагрузки, а когда нагрузка падает, уменьшать их, чтобы экономить ресурсы.
-
Ускоряет процесс CI/CD. Если запускать пайплайны в контейнерах, это можно делать многопоточно, что дает ускорение развёртывания на продакшн.
Задача – сравнить эффективность работы сервера 1С в Docker и без него
Поняв все эти плюсы, мы решили перевести контуры разработки и тестирования на Docker – развернуть сервер приложений 1С в контейнере.

Но перед тем, как это сделать, мы решили провести нагрузочное тестирование, чтобы понять, не столкнемся ли мы после перехода в Docker с просадками производительности.
Мы взяли две виртуальные машины с одинаковыми характеристиками.
-
На одну из них установили Docker.
-
На второй машине сервер 1С запускался без контейнера.
И на обе машины дополнительно установили NetData в контейнере – чтобы отслеживать нагрузку на наши сервера.
Для тестов мы использовали:
-
всем хорошо известную конфигурацию Тест Гилева;
-
конфигурацию Тест Магнит – это синтетические тесты, которые выполняют различные арифметические операции, а также операции с временными таблицами и хранимыми процедурами на стороне СУБД;
-
и конфигурацию Тест Цепочки ЕРП – это создание и проведение документов прихода и расхода.
Dockerfile для сервера приложений 1С

Рассмотрим Dockerfile, который мы написали для запуска сервера приложений 1С в Docker.
Его первая инструкция показывает, что в качестве базового образа мы использовали Debian 12:
FROM dockerhub.repo.corp.tander.ru/debian:12
Затем происходит обновление списка пакетов, установка утилиты fontconfig для управления шрифтами и установка утилиты wget для получения данных из интернета:
RUN apt update && apt install -y fontconfig && apt install -y wget && \
Затем мы устанавливаем корневые сертификаты для работы HTTPS, а также архиватор пакетов:
apt install -y ca-certificates && apt install -y cabextract && \
И устанавливаем сами шрифты:
apt install -y xfonts-utils
Поскольку наш Dockerfile очень простенький, установочный файл платформы и файлы со шрифтами для корректного отображения интерфейса нужно скачивать самим. Файл платформы мы скачиваем с ИТС, а шрифты – с сайта debian. Скрипт только копирует их в контейнер:
COPY fonts/dejavu /usr/share/fonts/truetype/dejavu
COPY fonts/msttcorefonts /usr/share/fonts/truetype/msttcorefonts

Далее у нас обновляется кэш шрифтов:
RUN fc-cache -fv
И мы копируем в контейнер установочный файл платформы 1С, который мы скачали с ИТС заранее.
COPY *.run /tmp/
Сразу оговорюсь, что это не совсем оптимальный вариант создания Dockerfile. Но для нашего тестового прогона это было нормально, поэтому мы решили оставить так. Потом я расскажу, как сделать это более правильно, и приведу пример скрипта, который это делает многоступенчатой сборкой.
Далее мы с помощью команды RUN устанавливаем платформу, выбирая компоненты, которые нам необходимы – для нас было достаточно сервера приложений 1С.
RUN /tmp/*.run --mode unattended --disable-components client_full \
--enable-components server,server_admin,additional_admin_functions && \
Далее удаляем установочный файл.
rm /tmp/*.run && \
Затем создаём папки для хранения логов и конфигурационных файлов кластера 1С:
mkdir --parents /var/log/1C /home/usr1cv8/.1cv8/1C/1cv8/conf && \
И назначаем на них владельца:
chown --recursive usr1cv8:grp1cv8 /var/log/1C /home/usr1cv8

Затем копируем в наш контейнер скрипт docker-entrypoint.sh, который будет запускаться в самом начале – его листинг я продемонстрирую чуть позже:
COPY container/docker-entrypoint.sh /
Командой ENTRYPOINT устанавливаем этот скрипт в качестве точки входа:
ENTRYPOINT ["/docker-entrypoint.sh"]
Создаём volume – тома хранения для данных кластера и логов 1С.
VOLUME /home/usr1cv8
VOLUME /var/log/1C
Затем документируем открытие портов, на которых будет работать наше приложение.
EXPOSE 2540-2541 2560-2591
И командой CMD передаём в наш скрипт docker-entrypoint.sh параметр ragent.
CMD ["ragent"]

На слайде показан листинг скрипта docker-entrypoint.sh.
#!/bin/bash
if [ "$1" = "ragent" ]; then
exec /opt/1cv8/x86_64/8.3.22.1851/ragent \
-d /home/usr1cv8/.1cv8/1C/1cv8 \
-port 2540 \
-regport 2541 \
-range 2560:2591
fi
exec "$@"
Поскольку в скрипт docker-entrypoint.sh, который будет стартовать при запуске контейнера, передаётся параметр ragent, мы здесь проверяем – если первый параметр = ragent, то стартуем службу ragent, передавая в команду запуска определенный набор аргументов.

Хочу затронуть тему слоистой структуры файловой системы Docker.
Дело в том, что Docker формирует образ из набора слоев, причем каждый слой является неизменяемым. Например, когда мы при сборке образа копируем в него дистрибутив платформы, под него создается отдельный слой.
У такого подхода есть как недостатки, так и позитивные стороны. Из плюсов:
-
Ускорение повторной сборки образов. За счёт того, что Docker пересобирает только те слои, в которых произошли изменения, а остальные берет из кэша, повторная сборка выполняется значительно быстрее
-
Экономия дискового пространства. За счёт того, что слои неизменяемые, они могут переиспользоваться разными образами. Например, если у нас несколько образов построены на базе Debian 12, базовый слой с Debian будет создан один раз и переиспользоваться повторно.
-
Быстрый запуск контейнеров. За счёт того, что слои неизменяемые, они не копируются в контейнеры – в контейнере создаётся только небольшой изменяемый слой, в котором фиксируются изменения, возникающие во время работы приложения. За счет этого контейнеры стартуют быстрее, чем классические виртуальные машины.
Запуск контейнера с сервером 1С

После подготовки Dockerfile и сборки на основе него образа, мы запускаем контейнер командой docker run.
Сразу скажу, что в рамках нашего нагрузочного теста сервер лицензирования и сервер СУБД находились на отдельных машинах, поэтому контейнер подключался к ним по сети. Для этого мы передавали IP-адреса и параметры подключения к серверу лицензирования и серверу базы данных.
docker run \ – запуск контейнера
--add-host ServerName:IP \ – прописываем DNS сервера лицензирования
--add-host ServerName:IP \ – прописываем DNS СУБД
Далее через параметр --hostname задавалось имя контейнера, чтобы его можно было корректно зарегистрировать в кластере серверов 1С.
--hostname hostname \ – назначаем внутреннее имя контейнера
Параметр --name использовался для задания имени контейнера внутри Docker – оно нужно уже для управления контейнером средствам Docker.
--name 1c-server \ – назначаем имя контейнера
Также использовался параметр --detach, который означает, что мы запускаем контейнер в фоновом режиме без подключения к консоли.
--detach \ – флаг запуска контейнера без подключения к нему
Затем с помощью параметра -p мы открывали необходимые сетевые порты. Здесь важно помнить, что инструкция EXPOSE в Dockerfile только документирует используемые порты, а реально публикуются они именно через docker run:
-p 2540:2540 \ – открываем порты
-p 2541:2541 \ – открываем порты
-p 2560-2591:2560-2591 \ – открываем порты
Далее подключались тома хранения для данных кластера 1С и логов. Отдельно монтировался файл времени, чтобы время внутри контейнера совпадало со временем хостовой системы.
--volume 1c-server-home:/home/usr1cv8 \ – указываем том для данных кластера 1С
--volume 1c-server-logs:/var/log/1C \ – указываем том для логов
--volume /etc/localtime:/etc/localtime:ro \ – чтобы время совпадало с временем на хосте
Здесь стоит пояснить различие между volume, объявленными в Dockerfile, и volume, подключёнными при запуске контейнера. Неименованные volume внутри образа создаются и управляются самим Docker, при удалении контейнера они тоже удаляются. А вот volume, указанные при запуске контейнера, находятся под полным контролем администратора: они сохраняются после удаления контейнера и могут использоваться повторно.
Кроме того, при монтировании можно задавать режим доступа. Например, файл времени мы подключали в режиме ro (read only) – только для чтения.
Последним параметром указывался образ, на основе которого запускался контейнер – тот самый образ, который мы собрали ранее.
magnittech/1c-server – образ с которого запускается контейнер
Результаты тестирования
Как я уже сказал, мы проводили нагрузочное тестирование несколькими методами.
-
В первых двух методах – Тест Гилёва и Тест Магнит – результаты контейнера практически не отличались от результатов на виртуальной машине
-
Однако при проверке на базе «Тест Цепочки ERP» мы увидели деградацию производительности контейнера в четыре-пять раз.
Мы начали разбираться в причинах, и с помощью NetData обнаружили, что процессор внутри контейнера загружается почти под 100%.
Сначала предположили, что проблема связана с логированием Docker. Поэтому перенесли логи с диска в оперативную память, чтобы уменьшить нагрузку на диск и процессор. Для этого при запуске контейнера использовались параметры --mount с типом type=tmpfs и папками, которые нужно было поместить в оперативную память:
--mount type=tmpfs,destination=/var/cache \ – помещаем папку в RAM
--mount type=tmpfs,destination=/root/.1cv8 \ – помещаем папку в RAM
--mount type=tmpfs,destination=/tmp \ – помещаем папку в RAM
Но это, к сожалению, не помогло. Поэтому мы решили вообще отключить логирование с помощью параметра --log-driver none:
--log-driver none \ – отключаем логирование внутри контейнера
Но это также не сработало.
После дополнительного анализа и изучения обсуждений на форумах мы выяснили, что причиной может быть встроенная сеть Docker. Docker создаёт собственную подсеть и виртуальный сетевой слой, который в некоторых сценариях действительно способен влиять на производительность.
Поэтому мы добавили ещё один параметр – «--network host», который позволяет контейнеру использовать подсеть хостовой машины напрямую, без виртуальной сети Docker:
--network host \ – отключаем создание сети для контейнера
И это как раз-таки помогло.

После этого результаты тестирования показали, что производительность контейнера стала сопоставима с запуском без Docker. Цифры сами по себе, возможно, не слишком показательны, но по итогам тестов стало понятно, что существенной разницы между Docker и классическим развёртыванием в нашем случае нет.
Многоступенчатая сборка образа для сервера приложений 1С
Я обещал, что покажу пример Dockerfile и docker-entrypoint.sh для многоступенчатой сборки образа сервера 1С, позволяющий минимизировать размер образа – его подготовили наши коллеги из «Первого Бита».
Вкратце расскажу, чем эти файлы для формирования образа отличаются от наших:
-
Сначала в Dockerfile создаётся образ, в котором устанавливается платформа 1С – примерно так же, как делали мы.
-
Затем формируется второй, финальный образ, куда копируются только необходимые установленные файлы платформы. Благодаря этому в итоговом образе остается минимальный набор данных.
-
Кроме того, в скрипте docker-entrypoint.sh более гибко настраивается состав устанавливаемых компонентов, перечень скачиваемых файлов и другие параметры.
Рекомендую вам изучить этот пример подробнее самостоятельно.
Сервер взаимодействия в Docker. Особенности работы в контейнере

Отдельно хочу рассказать о переводе сервера взаимодействия 1С с Windows на Linux в Docker-контейнеры.
Сервер взаимодействия 1С отлично подходит для использования в контейнере, поскольку он изначально имеет микросервисную архитектуру – за что отдельное спасибо разработчикам 1С. В его состав входят следующие компоненты:
-
сам сервер взаимодействия;
-
распределённое хранилище Hazelcast;
-
поисковый кластер ElasticSearch.
Причем дистрибутивы этих компонентов предоставляет сама 1С – мы скачали их с сайта ИТС и запустили в контейнере.
Однако в процессе работы сервера взаимодействия в контейнере мы столкнулись с рядом проблем:
-
Первая проблема – это чрезмерное логирование Hazelcast. Он в процессе своей работы генерирует огромный объем служебных сообщений, а Docker всё это логирует, что приводит к перерасходу дискового пространства. Поэтому на части серверов мы полностью отключили логирование, а на других – ограничили размер лог-файлов.
-
Вторая проблема была связана с PID-файлами. Как вы знаете, приложения в Linux при начале работы создают PID-файл с идентификатором процесса, а по завершении работы удаляют его. По неизвестной причине компонента сервера взаимодействия при завершении работы в контейнере не удаляла PID-файл. Он после остановки контейнера оставался, и при следующем запуске приложение считало, что процесс уже работает.

В итоге нам пришлось добавить в наш скрипт docker-entrypoint.sh небольшой костыль: при старте контейнера мы принудительно очищаем PID-файл сервера взаимодействия.
Что касается контейнеров Hazelcast и OpenSearch – их можно скачать отдельно с Docker Hub, там такой проблемы быть не должно.
Docker-образ для сценарного тестирования Vanessa Automation

Ещё один инструмент, о котором я хочу рассказать – это Vanessa Automation. Для его использования мы собрали отдельный Docker-образ.
-
Поскольку Vanessa требует графический интерфейс, в контейнер были установлены GUI-библиотеки и необходимые зависимости.
-
Также мы выработали для себя важное правило – максимально подробное логирование. При запуске Vanessa Automation могут возникать нестандартные ситуации, которые не всегда очевидны, поэтому необходимо все тщательно фиксировать, чтобы потом разбираться, что могло пойти не так.
-
Еще одно обязательное требование – сохранение артефактов работы контейнера. Например, мы сохраняем DT-файл тестовой базы в Volume, чтобы при необходимости можно было восстановить состояние системы и разобраться, что именно пошло не так.
Отдельный вопрос – лицензирование.
Если для нагрузочного тестирования мы использовали отдельный сервис лицензирования, то для Vanessa Automation такой подход оказался неудобен, поскольку тесты нужно было запускать параллельно – иногда сразу на нескольких машинах. Здесь нам помог автономный сервер 1С, который предоставляет до трех лицензий и позволяет работать с файловыми базами.

Также расскажу, какие изменения мы добавили в наш Dockerfile для работы с клиентским интерфейсом 1С:
# Установка 1С
RUN chmod +x /tmp/setup-full.run && \
/tmp/setup-full.run --mode unattended \
--enable-components server,client_thin_fib,ru
# Графические библиотеки
RUN apt install -y novnc websockify libxt6 xvfb x11vnc
А в скрипте start-1c.sh, который запускает 1С внутри контейнера, дополнительно прописали отключение модальных окон:
# Отключаем запуск в безопасном режиме
echo "DisableUnsafeActionProtection=.*" > /opt/1cv8/conf/conf.cfg
# Отключаем вывод модального окна об аппаратной лицензии
echo "UseHwLicenses=0" > /root/.1C/1cestart/1cestart.cfg
Без этих настроек контейнер запускался, но всплывающие модальные окна об использовании аппаратной лицензии и необходимости разрешить запуск внешних обработок мешали старту самих сценарных тестов. Мы прописали в конфигурационные файлы 1С эти две строчки и отключили эти модальные окна.
Что еще можно использовать в Docker

Теперь хотелось бы ещё поговорить об инструментах, которые находятся около 1С и которые также у нас используются в контейнерах.
-
OpenSearch – служит для того, чтобы собирать технологический журнал и анализировать его.
-
Vector – собирает данные журнала регистрации и отправляет в базу данных для хранения логов. Об этом рассказывал мой коллега Александр Леонов.
-
Database Lab для создания полноразмерных копий – о его использовании рассказывал также мой коллега Александр Насонкин. Этот инструмент произвёл среди наших коллег буквально фурор – он позволяет разворачивать огромные базы-копии для разработчиков за несколько секунд.
-
Ollama – для проведения ревью кода 1С с помощью ИИ.

Также мы используем в Docker:
-
ClickHouse – для сбора журнала регистрации и для построения дашбордов. Об этом рассказывала моя коллега Юлия Даскаль.
-
Также в Docker у нас работает собственная шина, которую мы разработали на Java с использованием Kafka, Postgres и Kafka UI.
-
Еще в Docker у нас запускается JupyterLab – он используется для тестирования OneScript, тоже очень удобная вещь.
-
И NetData – как я уже говорил, он служит для мониторинга производительности и определения нагрузки на хост.

В дальнейшем мы также планируем перевести в Docker-контейнеры наши веб-серверы 1С. Хотим управлять ими с помощью Kubernetes, динамически масштабируя количество экземпляров в зависимости от нагрузки: увеличивать при росте трафика и уменьшать при снижении.

И напоследок хочу затронуть такие инструменты, как Jenkins, SonarQube и EDT. Исторически у нас эти системы пока работают под Windows, но мы их уже протестировали в Docker на Linux и хотим перевести в контейнеры, чтобы одновременно решить ряд проблем:
-
В частности, при эксплуатации Jenkins-нод на Windows у нас со временем накапливался кэш, который не очищался полностью, из-за чего появлялись различные ошибки. При некоторых ошибках было быстрее полностью пересоздать виртуальную машину, чем с этим разбираться. Но времени на такое пересоздание тратится гораздо больше, чем на запуск контейнера – и это такая болевая точка, которую хотелось исправить.
-
SonarQube у нас сейчас также находится на Windows. Но мы его тоже уже протестировали в контейнере – он отлично работает, и чтобы с этим разобраться, нам достаточно было только прочитать справку к образу.
-
EDT также в контейнере работает нормально – мы планируем его использовать, чтобы проводить статический анализ кода через проверки EDT, и для того, чтобы собирать поставки обновлений с GitLab. Тоже протестировали – все отлично работает.
Вопросы и ответы
Как вы сейчас управляете всеми этими контейнерами без Kubernetes?
Вручную, через Docker Compose.
Куда вы сохраняете результаты тестов после их прогона в контейнере?
У нас к контейнерам подключены локальные тома, где в процессе тестирования сохраняются промежуточные данные. А потом мы переливаем эти данные в Nexus – для этого используется отдельный Nexus-репозиторий.
А как смотрите результаты?
Мы сохраняем в Nexus DT-файл, который потом можно загрузить в тестовую базу и проанализировать.
Насколько я понял, у вас много разработчиков и каждый запускает свои раннеры вручную. Рассматривали ли вы использование Docker Swarm, чтобы задания распределялись по раннерам централизованно?
У нас пока нет такой нагрузки, мы справляемся обычным запуском контейнеров. У нас один сервер, на котором в Docker развернут сервер приложений, и вся команда разрабатывает на нем.
Docker используется только для тестовых контуров? Есть ли вообще какие-то ограничения для использования Docker на проде?
У нас архитектурный комитет не одобряет использование контейнеризации в проде. Там огромные базы и под сервер приложения выделен отдельный сервер. Нет смысла запихивать его в Docker.
Вы сказали, что отключили логирование у Hazelcast. А как вы тогда мониторите работу системы взаимодействия?
Узнаём о проблемах от пользователей. Но пока серьезных сбоев не было.
Чем Docker принципиально лучше, чем обычная виртуальная машина, которую можно развернуть по необходимости? Не станет ли Docker дополнительной точкой отказа, на которую надо будет тратить время, вместо того, чтобы просто работать на виртуалках?
Важно понимать: контейнеры и виртуальные машины – это разные уровни. Контейнер – это про приложение, а виртуальная машина – это про инфраструктуру. Многие, когда слышат «1С в контейнере», представляют, что внутри маленького контейнера лежит терабайтная база, сервер приложений и пользователи туда же ходят. Это не так. В контейнере лежит только приложение.
Где вы храните логины и пароли для их использования в файлах сценариев, чтобы соответствовать требованиям службы безопасности?
Мы передаем логины и пароли через механизм секретов. Применяем утилиту pass – стандартный Linux-инструмент для хранения паролей.
Если у вас используется Keycloak, вы можете интегрировать его с Vault и передавать учетные данные через переменные окружения – как на этапе сборки, так и при запуске контейнеров.
*************
Статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART TECH EVENT.
Вступайте в нашу телеграмм-группу Инфостарт