Оглавление
- Введение
- Глава первая, в которой мы уходим от черных окон в удобный интерфейс
- Глава вторая, в которой мы создаем основу для сборки образов в разных операционных системах
- Глава третья, в которой мы рассматриваем способы установки 1С в разных операционных системах
- Глава четвертая, в которой мы полностью автоматизируем процесс сборки образа
- Глава пятая, в которой мы подготавливаем запуск сервера 1С в контейнере из образа
- Глава шестая, в которой мы разворачиваем контейнер в нашей инфраструктуре
- Глава седьмая, в которой мы знакомимся с различными комбинациями приложений стека 1С
- Заключение
Введение
Здравствуйте, друзья. В предыдущей статье мы описали основы основ работы с docker. Рассказали об истории возникновения контейнеризации, о самой технологии, как строить образы, как запускать контейнеры, как описывать инфраструктуру с помощью docker-compose. Основной вопрос, который чаще всего задавался при прочтении первой части: «А где же здесь 1С? Дайте нам 1С!» — требовали читатели и стучали кулаком по письменному столу. Поэтому в этой статье мы подробно остановимся на прикладном применении docker для 1С.
Хочется отметить, что в этой статье рассматриваются все возможность docker версии 29.1.5. Более старые версии могут не иметь описываемого функционала. Также с более старыми версиями могут конфликтовать приложении, о которых будет рассказано далее.
Глава первая, в которой мы уходим от черных окон в удобный интерфейс
Для продуктивной работы с контейнерами очень важным аспектом является хорошо подготовленное рабочее место.
Ранее мы с вами работали с docker через консоль. Знание консольных команд является важным моментом для понимания механизмов docker. Однако, для более быстрой и эффективной работы, когда уже понимаешь, что делаешь, гораздо удобней пользоваться специальными клиентами для взаимодействия с docker.
Docker desktop для Windows
Для Windows компания Docker предоставляет довольно простой в установке и использовании инструмент — Docker Desktop.
Его можно скачать с официального сайта Docker, или из Windows Store:
Перед установкой клиента необходимо активировать в системе опции Hyper-V и Containers:
Enable-WindowsOptionalFeature -Online -FeatureName $("Microsoft-Hyper-V", "Containers") -All
После чего перезапустить систему.
Далее при установке данное приложение установит платформу docker, а также активирует в системе WSL 2:
После установки можно определить 2 режима работы клиента:
- Работа с Windows-контейнерами.
- Работа с WSL-контейнерами.
Что означают данные режимы? Это контексты, в которых будут подниматься docker-контейнеры:
- Контекст исполнения Windows, для работы именно с Windows-контейнерами.
- Контекст исполнения Linux, для работы с Linux-контейнерами
Одновременно работать в двух контекстах нельзя. Но можно переключаться между ними без потери данных контейнеров:
Также с помощью Docker Desktop можно управлять:
- Образами:
- Сборка.
- Получение из репозитория.
- Отправка в репозиторий.
- Контейнерами:
- Запуск.
- Остановка.
- Просмотр логов.
- Обращение к файловой системе контейнера.
- Томами:
- Создание.
- Удаление.
- Просмотр.
- Так же в Docker Desktop доступна консоль.
Таким образом, в приложении доступны все те необходимые команды, которые мы изучали ранее в консоли в первой части статьи.
Данный инструмент довольно прост, что является большим преимуществом, когда только начинаешь изучать контейнеризацию. Им очень удобно пользоваться для работы с контейнерами в повседневной деятельности: для разработки или для отладки, используя уже готовые образы.
Для продуктивной среды Docker Desktop не совсем подходит. Основное его ограничение — это то, что он предназначен для работы в контексте пользовательской сессии и обычно запускается при входе пользователя в систему. Для автоматического его запуска на сервере нужно создавать дополнительные скрипты, что, конечно, влияет на стабильность системы. Также Docker Desktop предназначен только для Windows. Мы же будем рассматривать работу в разных ОС.
На рабочих серверах правильно устанавливать отдельно платформу и службу docker, не зависящие от каких-либо приложений. И как раз для взаимодействия с этими компонентами подходит следующее приложение.
Visual Studio Code
Основным из преимуществ этого редактора является обширная библиотека расширений, которая позволяет взаимодействовать VSCode с различной инфраструктурой в рамках работы над проектами.
Какие есть расширения в VSCode для наших целей:
- Container Tools — для работы с docker.
- Docker DX — для отладки сборки docker.
- Hadolint — для работы с dockerfile.
- PowerShell — для работы с PowerShell-скриптами в случае Windows-контейнеров.
- ShellCheck — для работы с bash-скриптами в случае Linux-контейнеров.
- Bush debug — для отладки bash-скриптов.
- WSL — для работы с подсистемой Linux для Windows.
- Remote SSH — для удаленной работы с любой системой по SSH-протоколу.
- Неимоверное количество других расширений, если перечисленных мало.
Помимо перечисленного есть еще встроенная поддержка:
- Git.
- Работы с терминалом.
Что позволяет нам организовать целый контур по разработке и отладке контейнеров.
Также Microsoft предоставляет довольно простой формат для создания своих собственных расширений.
Исходя из всех перечисленных преимуществ давайте настроим свое рабочее место на основе Visual Studio Code.
Настройка рабочего места
В первую очередь, давайте договоримся, что наше основное рабочее место находится на компьютере с Windows. Из него мы хотим подключаться:
- К локальным Windows-контейнерам.
- К локальным WSL-контейнерам.
Для начала мы подготовим программное окружение:
Активируем Hyper-V и компоненту контейнеризации:
Enable-WindowsOptionalFeature -Online -FeatureName $("Microsoft-Hyper-V", "Containers") -AllУстановим менеджер пакетов choco для Windows (подробней об этом инструменте мы расскажем ниже):
Set-ExecutionPolicy Bypass -Scope Process -Force;
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))Установим PowerShell 7 версии, VSCode, Git, 7zip, пакет утилит sysinternals suite:
choco install -y powershell-core vscode git 7zip sysinternalsУстановим инфраструктуру docker:
choco install -y docker-cli docker-compose docker-engine
Все эти инструменты нам понадобятся для работы.
Если зайти в VSCode, то перед нами откроется знакомый всем интерфейс, состоящий из 5 панелек:
Работа с файлами.
Поиск.
Работа с репозиторием.
Отладка.
Расширения.
Давайте зайдем в расширения и установим следующие инструменты:
- PowerShell.
- GitLens.
- Container Tools.
- Docker DX.
- Remote Development.
- Hadolint.
Данное расширение не работает самостоятельно, необходимо поставить дополнительно в Windows приложение hadolint:
choco install -y hadolint
Просто копируйте имена расширений и через поиск находите необходимые.
После установки всех перечисленных расширений они появятся в списке установленных. Число панелек и различных ссылок увеличится. Вы начнете замечать в файлах различные подсказки, гиперссылки, контекстные меню. Интерфейс преобразится. Главное не переусердствовать с расширениями, иначе наш легкий редактор превратится в неповоротливого монстра.
Если открыть командную панель, то сразу подхватится оболочка PowerShell 7. При наборе команд, при нажатии Ctrl + Пробел, будет выходить контекстная подсказка.
Если зайти в панель Containers, то мы увидим списки контейнеров, образов, томов, которые пока пустые для нашей системы. Текущая панель контейнеров подключилась к текущей службе docker и отображает данные контейнеров Windows. Из этой панели мы сможем управлять всеми элементами контейнеризации. Функционал расширения работы с контейнерами также подхватывается в dockerfile, в docker-compose.yml, но давайте обо всем по порядку.
Теперь настроим доступ к контейнерам Linux в подсистеме WSL. Для этого прямо в терминале VSCode выполним команду:
Установка «Подсистема Windows для Linux 2.6.3» выполнена.
Операция успешно завершена.
Скачивание: Ubuntu
Установка: Ubuntu
Дистрибутив успешно установлен. Его можно запустить с помощью "wsl.exe -d Ubuntu"
Запуск Ubuntu...
IProvisioning the new WSL instance Ubuntu
This might take a while…
Create a default Unix user account: agibalov
New password:
Retype new password:
passwd: password updated successfully
Данная команда не только обновит WSL до последней версии, но и скачает дистрибутив Ubuntu, задаст для него пользователя и пароль. Терминал сразу зайдет в оболочку WSL:
Этот немного не тот режим, который нам нужен. Выйдем из WSL в терминале, набрав команду exit, и подключимся к ней из интерфейса VSCode, выбрав пункты меню «Open remote Window» — «Connect to WSL»:
Что принципиально поменяется? А поменяется то, что мы начнем работать не в контексте Windows, а в контексте Linux, и абсолютно все инструменты будут работать в данном контексте:
Важно. Для дальнейшей работы важно знать, что к WSL можно подключиться из терминала powershell или cmd. Достаточно выполнить команду:
Вернемся в VSCode. Установленные нами ранее расширения работают только локально. Для работы в контексте WSL их нужно пробросить дополнительно вручную. Для этого перейдем в панель расширений и для каждого нужного нажмем команду «Install in WSL».
Для расширения Hadolint также нужно установить отдельное приложение для Linux, используя следующий скрипт:
sudo chmod +x /usr/local/bin/hadolint;
Расширение также можно устанавливать в WSL отдельно, без установки в локальной ОС. Например, для работы с bash-скриптами. Поставим расширения:
- ShellCheck.
- Bush Debug.
Оно установится сразу в WSL.
Если зайти в панель «Containers», то там выйдет ошибка «Failed to connect». Все верно. Мы docker установили для Windows, а для Linux нужно установить отдельно, следуя инструкции docs.docker.com/engine/install/.
После установки docker в панели «Containers» выйдет другая ошибка «Permissions denied». Чтобы ее решить, нужно текущего пользователя добавить в группу «docker», выполнив команду в WSL:
В итоге мы настроили начальную инфраструктуру, в которой можем разрабатывать образы и управлять контейнерами. Данную инфраструктуру можно использовать как в тестовой среде, так и в рабочей. Далее в повествовании будем держать в уме, что WSL на Windows равнозначен любому другому Linux-серверу.
Отдельно хочется подчеркнуть, что в отличие от Docker Desktop мы настроили 2 одновременно работающие среды с контейнерами. В Docker Desktop же можно одновременно работать только в одной среде.
Глава вторая, в которой мы создаем основу для сборки образов в разных операционных системах
Инициализация проекта
В данной главе мы разберем создание образов для операционных систем Linux и Windows, создадим 2 проекта.
На локальной машине Windows:
Создадим каталог, например, C:\repo\oc_server через Explorer или с помощью команды в PowerShell терминале:
New-Item -Path "C:\repo\oc_server" -ItemType "Directory"
Второй в WSL:
Создадим каталог, например, /srv/oc_server с помощью команды в терминале:
sudo mkdir -p "/srv/oc_server"Для того, чтобы можно было работать с проектом под текущем пользователем из VSCode необходимо сменить владельца каталога (под sudo каталог создается под владельцем root):
sudo chown vasia:vasia "/srv/oc_server"Чтобы узнать своего пользователя (и подставить его вместо vasia) нужно выполнить:
whoami
Откроем 2 экземпляра VSCode:
- В одном откроем проект из каталога C:\repo\oc_server.
- В другом экземпляре присоединимся к WLS, как было описано выше, и откроем проект /srv/oc_server:
В панели «Проводник» создадим новые файлы:
- dockerfile,
- docker-compose.yml,
- для Windows:
- docker-build.ps1,
- docker-compose-up.ps1,
- docker-compose-down.ps1.
- для Linux:
- docker-build.sh,
- docker-compose-up.sh,
- docker-compose-down.sh.
Начальный образ для Windows
Для Windows начальный dockerfile давайте опишем следующим образом:
FROM mcr.microsoft.com/windows/servercore:ltsc2022
SHELL [ "powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';" ]
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; \
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 ; \
Invoke-Expression ( (New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1') ); \
choco install powershell-core -y; \
choco install nano -y; \
choco install liberica8jre -y; \
choco install sql2012.nativeclient -y; \
choco install 7zip -y
ENTRYPOINT [ "pwsh" ]
Опишем его структуру:
- В качестве базовой операционной системы выбрана windows servercore.
- В качестве оболочки выполнения выбирается PowerShell.
- Для удобной и корректной работы устанавливаются дополнительные утилиты:
- Менеджер пакетов choco (о котором мы расскажем позже).
- PowerShell 7 версии.
- Java 8 версии (новая реструктуризация 1С до сих пор требует 8 версию).
- Клиент для интеграции с MSSQL.
- 7Zip — программа для работы с rar-архивами.
- После установки PowerShell 7, его можно выбрать в качестве точки входа.
Опишем файл docker-build.ps1 — просто вносим команду сборки образа:
docker build -t oc/server:8.3.27.1989 .
Запустить файл можно из терминала VSCode с помощью команды:
После сборки контейнера в панели «Containers» появится новый образ.
Через контекстное меню образа можно запустить контейнер в интерактивном режиме, и проверить, что он работает:
Начальный образ для WSL
Для Linux начальный dockerfile давайте опишем следующим образом:
FROM debian:bookworm-slim
ARG DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update \
&& apt-get install -yq --no-install-recommends locales procps curl ca-certificates gnupg wget unzip; \
apt-get clean \
&& rm -rf /var/lib/apt/lists/*; \
install -m 0755 -d /etc/apt/keyrings; \
sed -i -e "s/# ru_RU.UTF-8.*/ru_RU.UTF-8 UTF-8/" /etc/locale.gen \
&& dpkg-reconfigure --frontend=noninteractive locales \
&& update-locale LANG=ru_RU.UTF-8;
ENTRYPOINT [ "bash" ]
Опишем его структуру:
- В качестве базовой операционной системы выбрана debian bookworm-slim.
- В качестве оболочки выполнения выбирается bash.
- Для удобной и корректной работы устанавливаются дополнительные утилиты:
- locales — для установки русского языка.
- ca-certificates, gnupg — для работы с сертификатами.
- curl, wget — для работами с http-запросами.
- unzip — для работы с zip-архивами.
- Настраивается русский язык в системе.
- В конце bash выбирается в качестве точки входа.
Также опишем файл docker-build.sh:
docker build -t oc/server:8.3.27.1989 .
И запустим сборку из терминала VSCode с помощью команды:
У нас также в панели «Containers» появится новый образ, который можно в качестве теста запустить интерактивно:
В итоге мы подготовили основу для начала сборки образа под 1С.
Перенос кода в модули
Когда в dockerfile в секцию RUN вносится много кода, то он перестает быть понятным, логика теряется в точках, запятых, скобках, кавычках и другой невообразимой пунктуации, которой славятся скриптовые языки.
Поэтому для упрощения dockerfile рекомендуется всю логику переносить в модульные файлы.
Создадим в проектах файл pre_install в каталоге context, в который поместим код из секции RUN:
Файл pre_install для Windows
Стоит обратить внимание, что для Windows файл должен быть с расширением ps1, т. е. pre_install.ps1. Иначе его нельзя будет подключить как библиотечный. Добавим в файл следующее содержание:
function Install-Packs
{
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
Invoke-Expression ( (New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1') )
choco install powershell-core -y
choco install nano -y
choco install liberica8jre -y
choco install sql2012.nativeclient -y
choco install 7zip -y
}
Исправим dockerfile:
FROM mcr.microsoft.com/windows/servercore:ltsc2022
SHELL [ "powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';" ]
COPY [ "context/pre_install.ps1", "/context/pre_install.ps1" ]
RUN . /context/pre_install.ps1 ; \
Install-Packs ; \
Remove-Item /context/pre_install.ps1 -Force ;
ENTRYPOINT [ "pwsh" ]
Запустим пересборку с помощью docker-build.ps1, проверим, что контейнер запускается в интерактивном режиме и работает.
После проведенных действий сразу бросается в глаза, на сколько легче (в плане восприятия) стал dockerfile. Однако есть и минус в том, что приходится копировать скрипт в образ в секции COPY, и в итоговом образе остаются слои с ненужными данными. Даже если эти данные удаляются в следующей секции RUN. В некоторых случаях этот момент может привести к нарушению безопасности.
Файл pre_install для WSL
Однако docker Linux имеет некоторые дополнительные опции, которых нет в docker для Windows.
Перенесем скрипт предустановки в файл context/pre_install для проекта WSL:
install_packs() {
apt-get update \
&& apt-get install -yq --no-install-recommends locales procps curl ca-certificates gnupg wget unzip less;
apt-get clean \
&& rm -rf /var/lib/apt/lists/*;
install -m 0755 -d /etc/apt/keyrings;
sed -i -e "s/# ru_RU.UTF-8.*/ru_RU.UTF-8 UTF-8/" /etc/locale.gen \
&& dpkg-reconfigure --frontend=noninteractive locales \
&& update-locale LANG=ru_RU.UTF-8;
}
Соответственно поправим dockerfile:
FROM debian:bookworm-slim
ARG DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN --mount=from=context,source=pre_install,target=/context/pre_install \
set -eux; \
. /context/pre_install; \
install_packs
ENTRYPOINT [ "bash" ]
Здесь можно увидеть первое принципиальное отличие от сборки образа в Windows. Мы скрипт передали не в секции COPY, а примонтировали с каталогом «context», как внешний диск с помощью ключа --mount=from. Таким образом после выполнения секции RUN никаких артефактов сборки в образе не остается.
Для успешной сборки нам необходимо поправить docker-build.sh:
docker build \
--build-context context=context \
-t oc/server:8.3.27.1989 \
.
С помощью параметра --build-context монтируется каталог с контекстом сборки, чтобы были видны файлы скриптов.
Глава третья, в которой мы рассматриваем способы установки 1С в разных операционных системах
Установка приложений в Windows
Многие из вас наверняка помнят, что установка приложений запускается при помощи exe файла. Например, Setup.exe. Однако, это не всегда подходит для установки из командной строки. Более стандартизированный способ установки — это установка через msi.
Все MSI‑пакеты поддерживают единые команды установки через утилиту msiexec, что больше всего и подходит для автоматизации.
Общая строка запуска установки через msiexec выглядит следующим образом:
Где:
- /i app.msi — ключ для указания пути к устанавливаемому приложению.
- /qn — ключи тихой установки в полностью автоматическом режиме, без интерфейса.
Дистрибутив 1С для Windows распространяется в виде rar-архива, в котором можно найти 2 исполняемых файла: setup.exe и 1CEnterprise 8 (x86-64).msi. Как раз второй файл подходит для наших целей.
Помимо ключей по умолчанию, можно указать еще дополнительные ключи, которые относятся к устанавливаемым приложениям. Для 1С доступны следующие ключи:
- TRANSFORMS="adminstallrelogon.mst;1049.mst" — обязательные системные файлы трансформации.
- DESIGNERALLCLIENTS=1 — установка конфигуратора и все виды клиентов.
- THICKCLIENT=1 — установка толстого клиента.
- THINCLIENTFILE=1 — установка тонкого клиента, файловый вариант.
- THINCLIENT=1 — установка тонкого клиента.
- SERVER=1 — установка сервера «1С:Предприятие».
- WEBSERVEREXT=1 — установка модулей расширения веб-сервера.
- SERVERCLIENT=1 — установка средств администрирования сервера «1С:Предприятие».
- LANGUAGES=RU — установка интерфейса на различных языках.
- CONFREPOSSERVER=1 — установка сервера хранилища конфигураций «1С:Предприятие».
- ADMINISTRATIONFUNC=1 — установка дополнительных функций администрирования.
- CONVERTER77=1 — установка конвертора ИБ 1С:Предприятия 7.7.
- INSTALLSRVRASSRVC=1 — установка сервера 1С:Предприятие, как службы Windows.
- SRVCUSERSELECTMODE="new|existing" — режим создания пользователя службы.
- USER1CV82SERVER=«" — имя пользователя для режима «existing».
- PASSWORD1CV82SERVER="" — пароль пользователя для режима.
- INSTALLDIR="" — каталог, куда будет происходить установка.
Если составлять команду установки для 1С в режиме сервера, то будет получаться примерно следующая строка:
Давайте оформим итоговый скрипт установки в файле context/install.ps1 в проекте Windows с полным описанием всех параметров установки.
function Install-OC-Msi
{
param(
[Parameter(Mandatory)][string]$ArchivePath,
[string]$OCPath="C:\Program Files\1cv8",
[int]$Server=1,
[int]$WS=0,
[int]$CRS=0,
[int]$Client=0,
[string]$User="USER1CV8",
[string]$Password="USER1CV8"
)
process
{
Write-Host "Install 1C begining"
$DistrPath="C:\temp\distr"
New-Item -ItemType "Directory" -Path "${DistrPath}" -Force
7z x "${ArchivePath}" -o"${DistrPath}"
$PackageName = Get-Content "${DistrPath}\Setup.ini" |
Where-Object { $_ -match '^\s*PackageName\s*=\s*(.*)' } |
ForEach-Object { ($_ -split '=', 2)[1].Trim() }
$ProductVersion = Get-Content "${DistrPath}\Setup.ini" |
Where-Object { $_ -match '^\s*ProductVersion\s*=\s*(.*)' } |
ForEach-Object { ($_ -split '=', 2)[1].Trim() }
$DistrMsiPath = "${DistrPath}\${PackageName}"
if ( !(Test-Path "${DistrMsiPath}") )
{
Write-Error -Message "File not found: ${DistrMsiPath}" -ErrorAction 'Stop'
}
$ArgumentList = @(
"/l*"
'"' + "${DistrPath}" + '\Msi_Install.log"'
"/i"
'"' + "${DistrMsiPath}" + '"'
"/qn"
'TRANSFORMS="adminstallrelogon.mst;1049.mst"'
"DESIGNERALLCLIENTS=1" # Конфигуратор и все виды клиентов
"THICKCLIENT=$( ${Client} -gt 0 ? 1 : 0 )" # Толстый клиент
"THINCLIENTFILE=$( ${Client} -gt 0 ? 1 : 0 )" # Тонкий клиент, файловый вариант
"THINCLIENT=$( ${Client} -gt 0 ? 1 : 0 )" # Тонкий клиент
"SERVER=$( ${Server} -gt 0 ? 1 : 0 )" # Сервер 1С:Предприятие
"WEBSERVEREXT=$( ${WS} -gt 0 ? 1 : 0 )" # Модули расширения веб-сервера
"SERVERCLIENT=$( ${Server} -gt 0 ? 1 : 0 )" # Администрирование сервера 1С:Предприятие
"LANGUAGES=RU" # Интерфейсы на различных языках
"CONFREPOSSERVER=$( ${CRS} -gt 0 ? 1 : 0 )" # Сервер хранилища конфигураций 1С:Предприятие
"ADMINISTRATIONFUNC=$( ${Server} -gt 0 ? 1 : 0 )" # Дополнительные функции администрирования
"CONVERTER77=0" # Конвертор ИБ 1С:Предприятия 7.7
"INSTALLSRVRASSRVC=$( ${Server} -gt 1 ? 1 : 0 )" # Установить сервер 1С:Предприятие как службу Windows
"SRVCUSERSELECTMODE=$( ${Server} -gt 1 ? ( "${User}" -eq "${OC_DEF_USER}" ? "new" : "existing") : '`"`"' )" # new(Создать пользователя USER1CV8)|existing(Существующий пользователь)
"USER1CV82SERVER=$( ${Server} -gt 1 ? "${User}" : '`"`"' )" # Имя пользователя
"PASSWORD1CV82SERVER=$( ${Server} -gt 1 ? "${Password}" : '`"`"' )" # Пароль пользователя
"INSTALLDIR=`"${OCPath}\${ProductVersion}`"" # Папка
)
Start-Process -FilePath "msiexec.exe" -ArgumentList ${ArgumentList} -Wait -NoNewWindow
Remove-Item -r "${DistrPath}"
# Редактирование переменной среды PATH
$Include = "${OCPath}\${ProductVersion}\bin\"
$OldPath = [System.Environment]::GetEnvironmentVariable('PATH','machine')
$NewPath = "${OldPath};${Include}"
[Environment]::SetEnvironmentVariable("PATH", "${NewPath}", "Machine")
Write-Host "Install 1C finished"
}
}
Запуск установки приложения выполняется с помощью командлета powershell Start-Process, в который передаются параметры установки через описание массива. Данный метод описания установки более удобный и наглядный. Процедура установки описана максимально универсально, чтобы можно было задавать состав устанавливаемых компонент через параметры.
Поменяем dockerfile:
FROM mcr.microsoft.com/windows/servercore:ltsc2022
SHELL [ "powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';" ]
COPY [ "context/pre_install.ps1", "/context/pre_install.ps1" ]
RUN . /context/pre_install.ps1 ; \
Install-Packs ; \
Remove-Item "/context/pre_install.ps1" -Force ;
COPY [ "context/distr", "/context/distr" ]
COPY [ "context/install.ps1", "/context/install.ps1" ]
ARG OC_VERSION \
OC_PATH="C:\Program Files\1cv8" \
OC_MODE_SERVER=1 \
OC_MODE_WS=0 \
OC_MODE_CRS=0 \
OC_MODE_CLIENT=0 \
OC_USER="USER1CV8" \
OC_PASSWORD="USER1CV8"
SHELL [ "pwsh", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';" ]
RUN . ./context/install.ps1 ; \
Install-OC-Msi "/context/distr/windows64full_$($Env:OC_VERSION.Replace('.', '_')).rar" ` \
"${Env:OC_PATH}" ` \
${Env:OC_MODE_SERVER} ` \
${Env:OC_MODE_WS} ` \
${Env:OC_MODE_CRS} ` \
${Env:OC_MODE_CLIENT} ` \
${Env:OC_USER}" ` \
${Env:OC_PASSWORD}"; \
Remove-Item "/context" -Recurse -Force ;
ENTRYPOINT [ "pwsh" ]
Теперь видно, что параметры в метод установки передаются через переменные среды, установленные с помощью секции ARG. Данные переменные временные и действуют на момент сборки. Однако их значения фиксируются в образе через историю установки в слоях. Поэтому нужно быть осторожным с передачей чувствительной информации через эти переменные, такой как пароли, ключи доступа и прочее.
Для части переменных среды установлены значения по умолчанию, что нам позволяет менять их выборочно. Также присутствует обязательная переменная — OC_VERSION, ее необходимо задать в скрипте docker-build.ps1.
docker build `
--build-arg "OC_VERSION=8.3.27.1989" `
-t oc/server:8.3.27.1989 `
.
Теперь для запуска сборки достаточно положить в каталог context/distr архив дистрибутива, который можно получить с сайта releases.1c.ru. В текущей реализации dockerfile заточен именно под название файлов, как они получаются с сайта без переименований.
Стоит отметить, что данный метод установки приложения очень неэффективный:
- Нужно вручную скачать дистрибутив.
- Нужно передать дистрибутив в каталог нужной хостовой машины.
- При запуске сборки тратится некоторое время для расчета контекста установки.
- Дистрибутив из контекста передается в сам образ с помощью секции COPY.
- Секция COPY формирует лишний слой с архивом дистрибутива, что увеличивает размер образа на целый 1ГБ.
Способы преодоления этих проблем будут рассмотрены ниже, а сейчас рассмотрим установку приложений в WSL.
Установка приложений в WSL
Мы установили в WSL дистрибутив Ubuntu, который построен на базе ОС Debian. Для установки приложений в этих системах используются deb-пакеты, которые, подобно msi-пакетам в Windows, содержат в себе файлы приложений, а также информацию, по размещению этих файлов, и по настройке ОС для работы с устанавливаемыми приложениями.
Однако, если в Windows помимо msi-пакетов очень распространена установка через exe-инсталляторы, то для ОС семейства debian deb-пакеты являются основным методом установки приложений.
Для установки deb-пакетов используется утилита dpkg, и в отличие от msiexec, команда запуска приложения довольно тривиальна:
Никаких дополнительных параметров именно для настройки установки приложения нет. Соответственно, 1С распространяет платформу не в виде одного общего пакета, а в виде нескольких пакетов:
- common,
- server,
- ws,
- crs,
- client.
Опишем скрипт установки в файле context/install в проекте WSL с полным описанием всех параметров установки:
install_packs() {
local archivePath="${1}"
local distrPath="/tmp/install"
mkdir -p "${distrPath}"
unzip "${archivePath}" -d "${distrPath}"
suffix="_${OC_VERSION%.*}-${OC_VERSION##*.}_amd64"
installFiles="1c-enterprise-${OC_VERSION}-common${suffix}.deb"
[[ "${OC_MODE_SERVER}" = "1" ]] && installFiles="${installFiles} 1c-enterprise-${OC_VERSION}-server${suffix}.deb" || :
[[ "${OC_MODE_WS}" = "1" ]] && installFiles="${installFiles} 1c-enterprise-${OC_VERSION}-ws${suffix}.deb" || :
[[ "${OC_MODE_CRS}" = "1" ]] && installFiles="${installFiles} 1c-enterprise-${OC_VERSION}-crs${suffix}.deb" || :
[[ "${OC_MODE_CLIENT}" = "1" ]] && installFiles="${installFiles} 1c-enterprise-${OC_VERSION}-client${suffix}.deb" || :
for installFile in ${installFiles}; do
dpkg -i "${distrPath}/${installFile}";
done;
if [ "${OC_MODE_SERVER}" -eq "1" ]; then
ln -s "${OC_PATH}/ragent" /usr/local/bin;
ln -s "${OC_PATH}/ras" /usr/local/bin;
ln -s "${OC_PATH}/rac" /usr/local/bin;
ln -s "${OC_PATH}/ibcmd" /usr/local/bin;
ln -s "${OC_PATH}/ibsrv" /usr/local/bin;
fi;
}
В bash-скриптах, в отличие от PowerShell, параметры в методах не описываются. Они передаются либо в безымянном виде, и к ним можно обращаться по номерам $1, $2 и т. д. Либо можно передавать требуемые значения через глобальные параметры. В нашем случае более удобный способ — передача значений через глобальные параметры и переменные среды.
Соответственно dockerfile будет выглядеть следующим образом:
FROM debian:bookworm-slim
ARG DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN --mount=from=context,source=pre_install,target=/context/pre_install \
set -eux; \
. /context/pre_install; \
install_packs
ARG OC_VERSION \
OC_MODE_SERVER=1 \
OC_MODE_WS=0 \
OC_MODE_CRS=0 \
OC_MODE_CLIENT=0
ENV OC_VERSION=${OC_VERSION} \
OC_PATH="/opt/1cv8/x86_64/${OC_VERSION}"
RUN --mount=from=context,source=install,target=/context/install \
--mount=from=context,source=distr,target=/context/distr \
set -eux; \
. /context/install; \
install_packs "/context/distr/deb64_${OC_VERSION//./_}.zip"
ENTRYPOINT [ "bash" ]
Вносим в скрипт запуска сборки дополнительные параметры:
docker build \
--build-context context=context \
--build-arg "OC_VERSION=8.3.27.1989" \
-t oc/server:8.3.27.1989 \
.
Если нам захочется добавить в образ компоненты для веб-сервиса или для хранилища конфигурации или клиента, то можно будет описать дополнительные параметры --build-arg:
--build-context context=context \
--build-arg "OC_VERSION=8.3.27.1989" \
--build-arg "OC_MODE_SERVER=0" \
--build-arg "OC_MODE_CLIENT=1" \
По умолчанию эти компоненты выключены, и сейчас указывать их не имеет смысла.
Для запуска сборки также положим в каталог context/distr архивный файл, который можно получить с сайта releases.1c.ru.
В целом dockerfile WSL очень похож на dockerfile для Windows, но мы не передаем дистрибутив через секцию COPY, вместо этого мы пробрасываем каталог с дистрибутивом в контекст установки с помощью ключа --build-context.
Тем самым можно вычеркнуть сразу несколько проблем:
- Нужно вручную скачать дистрибутив.
- Нужно передать дистрибутив в каталог нужной хостовой машины.
При запуске сборки тратится некоторое время для расчета контекста установки.Дистрибутив из контекста передается в сам образ с помощью секции COPY.Секция COPY формирует лишний слой с архивом дистрибутива, что увеличивает размер образа на целый 1ГБ.
Давайте разберем способ решения проблемы ручной передачи файлов в инфраструктуру сборки образов.
Глава четвертая, в которой мы полностью автоматизируем процесс сборки образа
Для продуктивного контура важным является процесс автоматизации сборки образов. Неправильно каждый раз вручную доставлять какие-нибудь важные системные компоненты. Скорость сборки и повторяемые процессы установки являются основой устойчивости процесса поддержки инфраструктуры.
Команда получения файла по гиперссылке не сложная и часто решается одной строчкой кода. В случае продуктов 1С получение нужных файлов усложняется процедурой авторизации на сайте releases.1c, а также сложной структурой самого сайта.
Для автоматизации данного процесса был спроектирован специальный скрипт.
Скрипт получения дистрибутива с сайта 1С в PowerShell
Рассмотрим метод для PowerShell и добавим его в файл context/install.ps1:
function Get-OC-MSI-RAR
{
param(
[Parameter(Mandatory)][string]$SavePath,
[Parameter(Mandatory)][string]$Version,
[Parameter(Mandatory)][string]$User,
[Parameter(Mandatory)][string]$Password
)
process
{
$Disk = Get-PSDrive $((Split-Path -Path "${SavePath}" -Qualifier).Substring(0, 1))
if ( $Disk.Free -lt 3GB )
{
Write-Error "Not enough space on the C drive:"
return
}
echo $Disk
if ( ! ( Test-Path "${SavePath}" ) )
{
New-Item -ItemType Directory -Path "${SavePath}"
}
Write-Host "1. Authorization on login.1c.ru..." -ForegroundColor Cyan
# Getting cookies and tokens
$Headers = @{ "User-Agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" }
$LoginUrl = "https://login.1c.ru/login"
$LoginPage = Invoke-WebRequest -Uri ${LoginUrl} -SessionVariable Session1C -Headers ${Headers} -TimeoutSec 30
# Logging on login.1c.ru
$Body = @{
"inviteCode" = ""
"inviteType" = ""
"username" = ${User}
"password" = ${Password}
"anotherComputer" = $false
"rememberMe" = $false
"execution" = $LoginPage.InputFields[6].value
"_eventId" = "submit"
}
$AuthResponse = Invoke-WebRequest -Uri ${LoginUrl} -Method Post -Body ${Body} -WebSession $Session1C -Headers ${Headers} -TimeoutSec 30
if ( $AuthResponse.BaseResponse.RequestMessage.RequestUri -notmatch "https://login.1c.ru/user/profile" )
{
Write-Error "Failed to log in. Check your username and password"
return
}
Write-Host "2. Searching for a link to the version ${Version}..." -ForegroundColor Cyan
# Searching links
$VersionsUrl = "https://releases.1c.ru/project/Platform83?allUpdates=true#updates"
$VersionsPage = Invoke-WebRequest -Uri ${VersionsUrl} -WebSession ${Session1C} -Headers ${Headers} -TimeoutSec 30
$VersionUrl = $VersionsPage.Links | Where-Object { $_.outerHTML -match "/version_files\?nick=Platform83&ver=${Version}" } | Select-Object -First 1 -ExpandProperty href
if ( $VersionUrl -match '[?&]ver=(?<version>[^&]+)' )
{
$Version = $matches['version']
Write-Host "Version $Version found" -ForegroundColor Green
}
else
{
Write-Error "Version ${Version} not found"
return
}
$FileName = "windows64full_$($Version.Replace(".","_")).rar"
$FileUrl = "https://releases.1c.ru/version_file?nick=Platform83&ver=${Version}&path=Platform%5c$($Version.Replace(".","_"))%5c${FileName}"
$FilePage = Invoke-WebRequest -Uri ${FileUrl} -WebSession ${Session1C} -Headers ${Headers} -TimeoutSec 30
$DownloadUrl = $FilePage.Links | Where-Object { $_.outerHTML -match "https://dl03.1c.ru/public/file/get/" } | Select-Object -First 1 -ExpandProperty href
if ( ! $DownloadUrl )
{
Write-Error "Windows 64-bit link not found"
return
}
Write-Host "3. Downloading a file..." -ForegroundColor Yellow
# Downloading
try
{
Invoke-WebRequest -Uri ${DownloadUrl} -OutFile "${SavePath}\${FileName}" -WebSession ${Session1C} -Headers ${Headers}
Write-Host "The file ${SavePath}\${FileName} is saved" -ForegroundColor Green
}
catch
{
Write-Error ("Error when downloading: {0}`nDetails: {1}" -f $_.Exception.Message, $_.Exception.InnerException)
}
}
}
Основным методом общения с интернет-ресурсом является командлет Invoke-WebRequest. Процесс получения дистрибутива с сайта содержит следующие шаги:
- Описываем заголовки, что мы как будто работаем из браузера.
- Получаем куки (специальные переменные, идентифицирующие нашу сессию), которые будем использовать на всех шагах взаимодействия с интернет-ресурсом 1С.
- Выполняем запрос авторизации, после чего наша сессия может получить доступ к нужным файлам.
- Переходим на страницу со списком релизов для платформы 8.3, и проверяем, что запрашиваемая версия присутствует в этом списке.
- Переходим на страницу со ссылками для скачивания нужной версии продукта и получаем ссылку к дистрибутиву.
- Скачиваем файл дистрибутива по полученной ссылке.
Для того, чтобы прошла авторизация на сайте 1С:ИТС необходимо передать в параметры метода логин и пароль. Соответственно эти параметры нужно передать сначала в dockerfile.
Для Windows-контейнеров это можно сделать только двумя способами: через секцию ARG или через секцию COPY. Оба способа являются небезопасными, так как эти пароли фиксируются либо в слое образа, либо в истории образа.
Однако, есть один способ, который частично решит эту проблему. Можно использовать поэтапную сборку образа. Для этого изменим dockerfile следующим образом:
FROM mcr.microsoft.com/windows/servercore:ltsc2022 AS pre_build
SHELL [ "powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';" ]
COPY [ "context/pre_install.ps1", "/context/pre_install.ps1" ]
RUN . /context/pre_install.ps1 ; \
Install-Packs ; \
Remove-Item "/context/pre_install.ps1" -Force ;
FROM pre_build AS download
ARG OC_VERSION \
ITS_LOGIN \
ITS_PASSWORD
SHELL [ "pwsh", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';" ]
COPY [ "context/install.ps1", "/context/install.ps1" ]
RUN . /context/install.ps1 ; \
$DistrPath='C:\context\distr' ; \
Get-OC-MSI-RAR "${DistrPath}" "${Env:OC_VERSION}" "${Env:ITS_LOGIN}" "${Env:ITS_PASSWORD}"
FROM pre_build
ARG OC_VERSION \
OC_MODE_SERVER=1 \
OC_MODE_WS=0 \
OC_MODE_CRS=0 \
OC_MODE_CLIENT=0 \
OC_USER="USER1CV8" \
OC_PASSWORD="USER1CV8"
ENV OC_VERSION=${OC_VERSION} \
OC_PATH="C:\Program Files\1cv8"
SHELL [ "pwsh", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';" ]
COPY --from=download "/context/distr" "/context/distr"
COPY [ "context/install.ps1", "/context/install.ps1" ]
RUN . ./context/install.ps1 ; \
$DistrPath='C:\context\distr' ; \
Install-OC-Msi "${DistrPath}\windows64full_$($Env:OC_VERSION.Replace('.', '_')).rar" ` \
"${Env:OC_PATH}" ` \
${Env:OC_MODE_SERVER} ` \
${Env:OC_MODE_WS} ` \
${Env:OC_MODE_CRS} ` \
${Env:OC_MODE_CLIENT} ` \
"${Env:OC_USER}" ` \
"${Env:OC_PASSWORD}"; \
Remove-Item "/context" -Recurse -Force ;
ENTRYPOINT [ "pwsh" ]
Давайте разберем, какие произошли изменения:
- Сначала первая секция RUN выделяется в этап pre_build.
- Дальше запускается этап download, в котором как раз светятся наши учетные данные в секции ARG. На данном этапе скачивается дистрибутив.
- Дальше запускается этап установки 1С, но он запускается на основе этапа pre_build, и поэтому в его истории не фиксируется этап download с секретными аргументами.
- При этом из слоя этапа download можно получить скаченный дистрибутив в секции COPY.
Это способ получения файлов в образ, который довольно часто используется. Например, можно на одном этапе компилировать приложения, например, из git-репозитория, а на другом этапе забирать результат сборки без различных артефактов компиляции.
После сборки, важно не забыть удалить слой этапа download с помощью команды очистки кэшей:
Для запуска сборки необходимо изменить docker-build.ps1:
$Secrets = Get-Content -Path "its_secret" -TotalCount 2
$ITS_LOGIN = $Secrets[0]
$ITS_PASSWORD = $Secrets[1]
docker build `
--build-arg "OC_VERSION=8.3.27.1989" `
--build-arg "ITS_LOGIN=${ITS_LOGIN}" `
--build-arg "ITS_PASSWORD=${ITS_PASSWORD}" `
-t oc/server:8.3.27.1989 `
.
Здесь мы секретные данные также не указываем на прямую, а обращаемся к файлу, поэтому в папке проекта необходимо еще создать файл its_secret со следующим содержимым:
login
password
Т. е. в первую строчку указываем логин, во вторую строчку — пароль.
После сборки файл следует удалить. Этим мы добиваемся, что логин и пароль доступны только на время сборки образа.
В итоге мы получили сборку образа с установленным 1С без передачи дистрибутивов вручную.
Однако, всё ещё остался ряд проблем:
Нужно вручную скачать дистрибутив.Нужно передать дистрибутив в каталог нужной хостовой машины.При запуске сборки тратится некоторое время для расчета контекста установки.- Дистрибутив из образа загрузки передается в основной образ с помощью секции COPY.
- Секция COPY формирует лишний слой с архивом дистрибутива, что увеличивает размер образа на целый 1ГБ.
Скрипт получения дистрибутива с сайта 1С в bash
Добавим следующий скрипт в файл context/install проекта WSL:
local savePath="${1:-/tmp/install_deb}"
local Version="$2"
local Login="$3"
local Password="$4"
freeSpace=$(df -k / | awk 'NR==2 {print $4}')
if [ "${freeSpace}" -lt 3145728 ]; then
echo "Error: Not enough space on drive" >&2
return 1
fi
mkdir -p "${savePath}"
cookieFile=$(mktemp)
headers="User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36"
echo "1. Authorization on login.1c.ru..."
# Getting cookies and tokens
loginPage=$(curl -sL -c "${cookieFile}" -H "${headers}" "https://login.1c.ru/login")
execution=$(echo "${loginPage}" | grep -oP 'name="execution" value="\K[^"]+')
# Logging on login.1c.ru
authCheck=$(curl -sL -b "${cookieFile}" -c "${cookieFile}" -H "${headers}" \
-d "username=$Login" \
-d "password=$Password" \
-d "execution=$execution" \
-d "_eventId=submit" \
-d "rememberMe=false" \
"https://login.1c.ru/login")
if [[ ! "${authCheck}" =~ "user/profile" ]]; then
echo "Error: Failed to log in. Check credentials" >&2
rm "${cookieFile}"
return 1
fi
echo "2. Searching for a link to version ${Version}..."
versionsPage=$(curl -sL -b "${cookieFile}" -H "${headers}" "https://releases.1c.ru/project/Platform83?allUpdates=true")
versionPath=$(echo "${versionsPage}" | grep -oP "/version_files\?nick=Platform83&ver=${Version}" | head -n 1)
if [ -z "${versionPath}" ]; then
echo "Error: Version ${Version} not found" >&2
return 1
fi
fileName="deb64_${Version//./_}.zip"
filePageUrl="https://releases.1c.ru/version_file?nick=Platform83&ver=${Version}&path=Platform%5c${Version//./_}%5c${fileName}"
downloadUrl=$(curl -sL -b "${cookieFile}" -H "${headers}" "${filePageUrl}" | grep -oP 'https://dl03.1c.ru/public/file/get/[^"]+')
if [ -z "${downloadUrl}" ]; then
echo "Error: Linux deb 64-bit link not found" >&2
return 1
fi
echo "3. Downloading file..."
curl -L -b "${cookieFile}" -H "${headers}" "${downloadUrl}" -o "${savePath}/${fileName}"
rm "${cookieFile}"
echo "Done. File saved to ${savePath}"
Процесс получения файлов дистрибутива ровно такой же, как и в предыдущем скрипте. Единственное отличие, что для взаимодействия с информационным ресурсом используется утилита curl.
Исправим dockerfile:
FROM debian:bookworm-slim
ARG DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN --mount=from=context,source=pre_install,target=/context/pre_install \
set -eux; \
. /context/pre_install; \
install_packs
ARG OC_VERSION \
OC_MODE_SERVER=1 \
OC_MODE_WS=0 \
OC_MODE_CRS=0 \
OC_MODE_CLIENT=0
ENV OC_VERSION=${OC_VERSION} \
OC_PATH="/opt/1cv8/x86_64/${OC_VERSION}"
RUN --mount=from=context,source=install,target=/context/install \
--mount=type=secret,id=its-login,env=ITS_LOGIN \
--mount=type=secret,id=its-password,env=ITS_PASSWORD \
set -eux; \
. /context/install; \
savePath="/tmp/install_deb"; \
get_deb_from_url "${savePath}" "${OC_VERSION}" "${ITS_LOGIN}" "${ITS_PASSWORD}" ; \
install_packs "${savePath}/deb64_${OC_VERSION//./_}.zip"
ENTRYPOINT [ "bash" ]
И тут сразу бросается в глаза, что мы не используем поэтапную сборку. И пароли у нас не передаются ни в секции ARG, ни в секции COPY.
В этом еще одно преимущество контейнеров Linux над контейнерами Windows: для Linux используется подсистема docker buildx, которая предоставляет различные мощные фишечки. В данном случае это передача паролей через инструмент секретов, а именно, в секции RUN прописывается монтирование секрета в переменную среды.
Изменим наш файл docker-build.sh:
export ITS_LOGIN=$(sed -n '1p' its_secret)
export ITS_PASSWORD=$(sed -n '2p' its_secret)
docker build \
--build-context context=context \
--build-arg "OC_VERSION=8.3.27.1989" \
--secret id=its-login,env=ITS_LOGIN \
--secret id=its-password,env=ITS_PASSWORD \
-t oc/server:8.3.27.1989 \
.
И создадим файл its_secret в корне проекта с нашими секретами:
login
password
Мы его удалим сразу после построения докер-образа.
Сборка выполняется с помощью команды:
Глава пятая, в которой мы подготавливаем запуск сервера 1С в контейнере из образа
Друзья, поздравляю вас, мы прошли экватор и научились устанавливать приложение 1С в docker-образе. Скажем честно, это была самая сложная часть статьи, можно похвалить себя, что мы ее осилили. Вторая часть нашей статьи будет посвящена тому, как запускать это приложение.
Чтобы при запуске контейнера из созданного нами образа запускалось само приложение, в образе необходимо описать точку входа, т. е. команды, которые будут выполнятся. Как вы знаете по первой статье из цикла про контейнеризацию, эти команды указываются в секции ENTRYPOINT.
Однако, важно понимать, что помимо самого запуска приложения, нам важно определить пользователя, под которым эти команды будут выполняться.
Поэтому сначала давайте разберемся с работой с пользователями внутри контейнера.
Пользователи в Windows
Запустим созданный нами образ в интерактивном режиме:
А на хостовой машине запустим утилиту для просмотра процессов — procexp. Она поставляется в рамках пакета sysinternals suite.
Как видно, все системные процессы внутри контейнера Windows выполняются под системным пользователем NT AUTHORITY\СИСТЕМА хостовой машины:
Однако, при подключении к контейнеру, вход происходит под пользователем «Администратор контейнера», из хостовой системы он не виден и помечается как «unknown owner». Это сделано для того, чтобы пользователь внутри контейнера не смог получить управление над компонентами хостовой машины.
Давайте рассмотрим этого пользователя подробней и выполним команду внутри нашего запущенного контейнера:
Name Enabled Description
---- ------- -----------
Administrator True Built-in account for administering the computer/domain
DefaultAccount False A user account managed by the system.
Guest False Built-in account for guest access to the computer/domain
WDAGUtilityAccount False A user account managed and used by the system for Windows Defender Application Guard scenarios.
Среди локальных пользователей его нет.
USER INFORMATION
----------------
User Name SID
=================================== ============
user manager\containeradministrator S-1-5-93-2-1
Данный пользователь не виден среди локальным, потому что он не является пользователем, этот объект является виртуальной сервис-группой, которая существует в рамках подсистемы изоляции Windows.
Одним из важнейших свойств пользователя в Windows является параметр SID — его уникальный идентификатор, и, что самое важное, данный идентификатор нельзя указать при создании пользователя. Что это значит? Если мы создадим файл под пользователем, который определен только внутри контейнера, то доступ к нему смогут получить только системный пользователь и владелец файла — т. е. тот, кто его создал.
Если создать файл под локальным пользователем, удалить его и создать нового с тем же именем, то он потеряет доступ к созданному ранее файлу. Для containeradministrator SID постоянен. Даже если удалить образы и создать заново, SID останется тем же. Соответственно доступ к файлам из контейнера теряться не будет.
Выполним внутри контейнера следующие команды:
Owner : User Manager\ContainerAdministrator
Group : User Manager\ContainerAdministrator
Access : NT AUTHORITY\SYSTEM Allow FullControl
BUILTIN\Administrators Allow FullControl
User Manager\ContainerAdministrator Allow FullControl
Audit :
Sddl : O:S-1-5-93-2-1G:S-1-5-93-2-1D:(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;FA;;;S-1-5-93-2-1)
Здесь можно увидеть владельца файла в поле Owner и права в поле Sddl, которые выданы для доступа к файлу. Sddl — это один из важнейших параметров файла и является закодированной формой доступов.
Давайте разберем Sddl созданного нами файла:
- O — это владелец файла.
- S-1-5-93-2-1 — это идентификатор владельца файла.
- G — это группа доступа к файлу.
- S-1-5-93-2-1 — это идентификатор группы доступа к файлу.
- D — это DACL, список управления доступом.
- Далее идет код списка DACL.
- A;ID;FA;;;SY
- A;ID;FA — это означает что от каталога унаследован полный доступ.
- SY — это сокращенный идентификатор системного пользователя.
- A;ID;FA;;;BA
- BA — сокращенный идентификатор группы администраторов (BUILTIN\Administrators).
- A;ID;FA;;;S-1-5-93-2-1
- S-1-5-93-2-1 — это идентификатор владельца файла.
Более понятную расшифровку можно получить, выполнив команду:
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited : True
InheritanceFlags : None
PropagationFlags : None
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited : True
InheritanceFlags : None
PropagationFlags : None
FileSystemRights : FullControl
AccessControlType : Allow
IdentityReference : User Manager\ContainerAdministrator
IsInherited : True
InheritanceFlags : None
PropagationFlags : None
Также есть другой способ получения информации о доступе к файлу:
BUILTIN\Administrators:(I)(F)
User Manager\ContainerAdministrator:(I)(F)
Свой набор прав можно задать командой:
Где:
- /grant — ключ назначения прав.
- :r — сброс текущих прав.
- ИмяПользователя — можно получить с помощью команды Get-LocalUser.
- :F — полный доступ.
- Другие доступы:
- N — без доступа.
- F — полный доступ.
- M — изменение.
- RX — чтение и исполнение.
- R — чтение.
- W — запись.
- D — удаление.
- Буквы можно совмещать вместе, например, RW.
- /t — применить рекурсивно.
- /c — продолжать выполнение при ошибках.
- /q — не выводить сообщения об успешном выполнении.
Сокращения всех доступов можно получить, вызвав icacls без параметров.
Описание запуска приложения в Windows
В Linux-контейнерах принято создавать пользователей под запускаемые процессы, как видно, в Windows-контейнерах обслуживать вручную создаваемого пользователя намного сложнее.
Для запуска приложения под определенным пользователем в dockerfile нужно прописать примерно следующие строчки:
RUN New-LocalUser –Name Application
USER [ "Application" ]
ENTRYPOINT ["./StartAplication" ]
Для Windows такой метод запуска контейнеров не подходит, так как в нем реализована довольно сложная система авторизации и контроля прав. Простая смена пользователя через секцию USER часто приводит к ошибкам. Поэтому лучший способ запуска приложение под определенным пользователем, это установка его в качестве службы, с указанием нужного пользователя.
В итоге к каким выводам можно прийти:
- В Windows-контейнеры всегда заходим под сервис-группой «Администратор контейнера».
- Управление правами в Windows довольно сложная задача и требует больших знаний.
- Для работы приложения под локальными пользователями его нужно устанавливать только в виде службы. Данный подход не для всех приложений полезен.
- Нужно постоянно следить за правами к файлам во внешних томах, если они созданы под локальным пользователем. Если образ будет пересоздан, и пользователь также будет пересоздан, то необходимо также переназначать права для файлов.
Поэтому самым простым решением кажется, что приложения нужно запускать всегда под пользователем «Администратор контейнера», и не мучиться. Это общая рекомендация для работы с Windows-контейнерами. Давайте мы её и будем придерживаться.
Соответственно поменяем в dockerfile одну строчку:
ENTRYPOINT [ "ragent" ]
На текущий момент этой команды будет достаточно. Пересоберем образ и запустим контейнер с помощью следующей команды:
Параметр -t — это не указание тэга, как может показаться по образу и подобию команды docker build, этот параметр выделяет контейнеру псевдо-терминал (TTY), благодаря чему в лог контейнера будут выводиться сообщения процессов ragnet, rmngr, rphost.
Параметр -d — запуск контейнера в фоне.
Доступ к 1С в контейнере мы организуем в рамках среды compose чуть ниже.
Пользователи в Linux
В Linux-контейнерах с пользователями все намного проще. Так же как и в Windows у пользователя есть свой идентификатор и владелец файла определяется по идентификатору. Однако пользователя можно создавать и удалять с одним и тем же определённым идентификатором, при этом даже с разными именами. Доступы к файлам из-за этого не поменяются.
Посмотреть пользователей можно с помощью команды:
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
usr1cv8:x:999:1000:1C Enterprise 8 server launcher:/home/usr1cv8:/bin/sh
Права на чтение, запись, исполнение файлов в Linux задаются отдельно от пользователей, что в контейнеризации также становится преимуществом. Можно отдельно задать права на доступ к файлам и отдельно владельцев файлов.
Выполним команду создания файла и посмотрим права на него:
drwxr-xr-x 1 root root 4096 Feb 20 13:18 .
drwxr-xr-x 1 root root 4096 Feb 20 13:18 ..
-rw-r--r-- 1 root root 5 Feb 20 13:18 test
Здесь:
- Первый символ:
- «-» – признак файла;
- d — директория;
- l — символическая ссылка;
- c или b — специальные файлы устройств;
- p — именованный канал (pipe);
- s — сокет.
- Затем первые 3 буквы права доступа владельца к файлу.
- Вторые 3 буквы права доступа группы к файлу.
- Третьи 3 буквы права доступа всех остальных к файлу.
- Буквы для прав доступа обозначают:
- r — чтение;
- w — запись;
- x — исполнение.
- Первый root — пользователь root.
- Второй root — группа пользователя root.
Запустим интерактивно наш контейнер и выполним в нем команду:
1C:Enterprise 8.3 (x86-64) (8.3.27.1989) Cluster Manager started. Ctrl+C to exit.
1C:Enterprise 8.3 (x86-64) (8.3.27.1989) Working Process started. Ctrl+C to exit.
В контейнере запустится 1С.
Не завершая работы контейнера запустим команду top в терминале WSL (чтобы выйти из режима top нажмите q):
Видно, что ragent, rphost работают под правами root. Это неправильно.
Существует 2 варианта ограничения процессов 1С:
Разделения пользователей root хоста и root контейнера.
Для этого необходимо:
На хосте поменять файл /etc/docker/daemon.json:
sudo nano /etc/docker/daemon.json
{
"userns-remap": "default"
}- Перезапустить службу docker.
При этом все текущие контейнеры и образы пропадут, потому что произойдет переназначение пространств. Поэтому эту настройку нужно делать в самом начале настройки инфраструктуры. И мы ее сейчас применять не будем.
- Смена пользователя с помощью секции USER.
Выполним смену пользователя, для этого внесем в dockerfile строчку перед секцией ENTRYPOINT:
USER usr1cv8
После чего пересоберем образ и запустим контейнер интерактивно:
Сразу видно, что в командной строке появился другой пользователь. Запустим ragent, а на хосте также запустим команду top:
Теперь напротив процессов отображаются идентификаторы вместо пользователей, это означает, что хостовая машина ничего не знает о существовании пользователей из контейнера.
Описание запуска приложения в Linux
Поменяем секцию ENTRYPOINT также как для dockerfile Windows:
ENTRYPOINT [ "ragent" ]
Пересоберем образ и запустим контейнер с помощью команды:
Контейнер запустится в фоне и его можно проинспектировать с помощью команды:
Где oc — имя, которое мы задали при запуске контейнера:
UID PID PPID C STIME TTY TIME CMD
999 17191 17168 1 21:44 pts/0 00:00:00 ragent
999 17270 17191 1 21:44 pts/0 00:00:00 /opt/1cv8/x86_64/8.3.27.1989/rmngr -port 1541 -host a6ce1fadac43 -range 1560:1591 -clstid 62cfdd93-f673-44f9-8df8-b8586b8ebacf
999 17401 17191 2 21:44 pts/0 00:00:00 /opt/1cv8/x86_64/8.3.27.1989/rphost -range 1560:1591 -reghost a6ce1fadac43 -regport 1541 -pid 9fbfc332-084b-4188-85d3-f30bf94b5ddb
999 17465 17191 88 21:44 pts/0 00:00:05 /opt/1cv8/x86_64/8.3.27.1989/dbda 0.0.0.0,:: 1561 --http-port 1562 --init-config /tmp/v8_6HafnR_2.tmp --data /home/usr1cv8/.1cv8/1C/1cv8/1Cv8DbDA/45bd82a1-2eb2-4289-a88f-d9237d0d50c8
Видно, что все процессы работают под одним пользователем.
Также каждому процессу задан свой PID. В данном режиме отображается PID хостовой операционной системы.
Если присоединиться к контейнеру (через панель расширения VSCode) и вызвать top внутри контейнера то ragent будет иметь PID = 1:
Это очень важная деталь. Фактически запускаемая нами программа является корневой в дереве процессов контейнера Linux. Благодаря чему при остановке контейнера на этот процесс посылается специальный сигнал, что позволяет ему корректно завершиться.
Если вспомнить дерево процессов контейнера Windows, то оно перегружено системными службами. В этом состоит разность архитектур между ядрами Windows и Linux.
Теперь у нас основной пользователь в контейнере usr1cv8. Для того, чтобы подключиться к контейнеру под root пользователем, необходимо выполнить команду:
Где oc — имя, которое мы задали при запуске контейнера.
Глава шестая, в которой мы разворачиваем контейнер в нашей инфраструктуре
Теперь у нас все готово, чтобы развернуть Сервер 1С. Дальнейшие действия будут практически одинаковыми в обоих проектах и для Windows, и для Linux.
Docker compose для Windows
Подготовим файл docker-compose.yml:
name: ${OC_GROUP_SERVER_NAME:-oc_server}
services:
oc_server:
image: ${OC_SERVER_TAG}
container_name: ${OC_SERVER_NAME:-oc_server}
restart: always
hostname: ${OC_SERVER_HOSTNAME}
command: -port 1540 -regport 1541 -range 1560:1591 -d "C:\Program Files\1cv8\srvinfo"
environment:
TZ: ${TZ}
ports:
- "${OC_RAGENT_PORT:-1540}:1540"
- "${OC_RMNGR_PORT:-1541}:1541"
- "${OC_RAS_PORT:-1545}:1545"
- "${OC_RPHOST_PORT:-1560-1591}:1560-1591"
volumes:
- oc_srvinfo:C:\Program Files\1cv8\srvinfo
- oc_lic:C:\ProgramData\1C\licenses
- oc_conf:C:\Program Files\1cv8\conf
tty: true
volumes:
oc_srvinfo:
name: ${OC_SRVIFO_VOL:-oc_srvinfo}
oc_lic:
name: ${OC_LIC_VOL:-oc_lic}
oc_conf:
name: ${OC_CONF_VOL:-oc_conf}
Не будем подробно останавливаться на структуре файла, подробно о ней описано в предыдущей статье. Что сразу бросается в глаза — у нас в файле все параметры заданы через переменные. Для задания значения этих переменных нужно создать файл «.env» со следующим содержимым:
TZ="Europe/Moscow"
OC_GROUP_SERVER_NAME="oc_server_1740"
OC_SERVER_NAME="oc_server_1740"
OC_SERVER_TAG="oc/server:8.3.27.1989"
OC_SERVER_HOSTNAME="${OC_SERVER_HOSTNAME}"
OC_RAGENT_PORT="1740"
OC_RMNGR_PORT="1741"
OC_RAS_PORT="1745"
OC_RPHOST_PORT="1760-1791"
OC_SRVIFO_VOL="oc_srvinfo_1740"
OC_LIC_VOL="oc_lic_1740"
OC_CONF_VOL="oc_conf_1740"
Такой способ задания переменных очень удобен, мы можем использовать один шаблонный docker-compose.yml и множество различных env файлов, чтобы разворачивать различные экземпляры 1С.
Поясним некоторые параметры из docker-compose.yml.
${OC_SERVER_HOSTNAME} — значение данной переменной вы должны указать сами, и внести туда доменное имя вашей хостовой машины. Это значительное ограничение сервера 1С. Если мы не зададим корректное доменное имя контейнера, то будут возникать следующие ошибки:
- При обращении к кластеру по доменному имени хоста и указанным портам, кластер внутри себя будет обращаться по доменному имени контейнера, а не localhost, что вызовет сбой
- При создании нового контейнера, он будет каждый раз генерировать новое доменное имя, однако в файле кластера будет указано доменное имя, при котором он инициализировался в первый раз, соответственно, это приведет к ошибке запуска сервера 1С.
Command — здесь мы указываем параметры работы ragent. Они будут присоединяться к команде, указанной в ENTRYPOINT в dockerfile.
Name — данный параметр формирует удобное название группы compose.
Заполним файл docker-compose-up.ps1:
И запустим его:
И порадуемся нашей инфраструктуре.
Теперь к кластеру можно обратиться из внешней консоли на любой другой машине в общей сети с хостовой машиной, указав в качестве адреса подключения доменное имя хостовой машины и указанный нами порт в env файле:
Если нужно развернуть экземпляр 1С, то просто копируем файл «.env», задаем в нем другие параметры, например:
TZ="Europe/Moscow"
OC_GROUP_SERVER_NAME="oc_server_1840"
OC_SERVER_NAME="oc_server_1840"
OC_SERVER_TAG="oc/server:8.3.27.1989"
OC_SERVER_HOSTNAME="${OC_SERVER_HOSTNAME}"
OC_RAGENT_PORT="1840"
OC_RMNGR_PORT="1841"
OC_RAS_PORT="1845"
OC_RPHOST_PORT="1860-1891"
OC_SRVIFO_VOL="oc_srvinfo_1840"
OC_LIC_VOL="oc_lic_1840"
OC_CONF_VOL="oc_conf_1840"
Копируем файл docker-compose-up.ps1, и указываем в нем обращение к новому env файлу. Например:
Для того, чтобы завершить работу контейнера, необходимо правильно описать процедуру down, для этого заполним файл docker-compose-down.ps1 следующим содержимым:
Запустим его:
Контейнер удалится, однако указанные тома останутся. Что позволит при новом поднятии контейнера восстановить значимые параметры инфраструктуры.
Docker compose для WSL
Заполним в docker-compose.yml проекта WSL подобным образом:
name: ${OC_GROUP_SERVER_NAME:-oc_server}
services:
oc_server:
image: ${OC_SERVER_TAG}
hostname: ${OC_SERVER_HOSTNAME}
command: -port 1540 -regport 1541 -range 1560:1591 -d "/home/usr1cv8/.1cv8/1C/1cv8"
environment:
TZ: ${TZ}
ports:
- "${OC_RAGENT_PORT:-1540}:1540"
- "${OC_RMNGR_PORT:-1541}:1541"
- "${OC_RAS_PORT:-1545}:1545"
- "${OC_DEBAGER_PORT:-1549}:1549"
- "${OC_RPHOST_PORT:-1560-1591}:1560-1591"
volumes:
- oc_srvinfo:/home/usr1cv8/.1cv8/1C/1cv8
- oc_lic:/var/1C/licenses
- oc_conf:/opt/1cv8/conf
cap_add:
- SYS_NICE
tty: true
volumes:
oc_srvinfo:
name: ${OC_SRVIFO_VOL:-oc_srvinfo}
external: true
oc_lic:
name: ${OC_LIC_VOL:-oc_lic}
external: true
oc_conf:
name: ${OC_CONF_VOL:-oc_conf}
external: true
Этот файл отличается от файла для Windows в основном путями к 1С внутри контейнера.
Важное отличие в том, что тома заданы внешними. Это сделано специально, чтобы мы создали тома вручную и задали им доступ для пользователя из контейнера.
Опишем env файл:
OC_GROUP_SERVER_NAME="oc_server_1740"
OC_SERVER_NAME="oc_server_1740"
OC_SERVER_TAG="oc/server:8.3.27.1989"
OC_SERVER_HOSTNAME="${OC_SERVER_HOSTNAME}"
OC_RAGENT_PORT="1740"
OC_RMNGR_PORT="1741"
OC_RAS_PORT="1745"
OC_RPHOST_PORT="1760-1791"
OC_SRVIFO_VOL="oc_srvinfo_1740"
OC_LIC_VOL="oc_lic_1740"
OC_CONF_VOL="oc_conf_1740"
Создадим 3 тома:
docker volume create oc_lic_1740
docker volume create oc_conf_1740
Проверим, куда ссылается один из томов:
[0.1s
{
"CreatedAt": "2026-02-20T18:13:17+04:00",
"Driver": "local",
"Labels": {
"com.docker.compose.config-hash": "d6fe9b453692b79fc014158a0a6eb659ca99c7dc50be9297269d1ad07c933599",
"com.docker.compose.project": "oc_server_1740",
"com.docker.compose.version": "5.0.0",
"com.docker.compose.volume": "oc_srvinfo"
},
"Mountpoint": "/var/lib/docker/volumes/oc_srvinfo_1740/_data",
"Name": "oc_srvinfo_1740",
"Options": null,
"Scope": "local"
}
]
Зададим владельца для всех 3-х томов:
Где 999 — это идентификатор пользователя 1С, а 1000 — это идентификатор группы 1С.
Заполним docker-compose-up.sh:
docker compose --env-file=.env -f docker-compose.yml up
Заполним docker-compose-down.sh:
docker compose --env-file=.env -f docker-compose.yml down
Проверим, что инфраструктура стартует и останавливается:
Глава седьмая, в которой мы знакомимся с различными комбинациями приложений стека 1С
Друзья, вот мы и добрались до финала статьи. Информации получилось очень много, чтобы ее синхронизировать с практикой на проекте, представим вам несколько стеков, которые используются в реальной деятельности.
Перед началом разворачивания инфраструктуры по примеру очистите систему от создаваемых нами ранее образов, контейнеров, томов.
Для этого нужно остановить все контейнеры и выполнить команды:
Внимание! Эти команды очистят ВСЕ, не применяйте ее на продуктивном контуре, где работают важные сервисы. Для примера мы будем использовать готовые dockerfile из открытого репозитория https://github.com/agibalovsa/-1C_DevOps.git.
1C + MSSQL
На хостовой машине с Windows скопируем репозиторий 1C_DevOps:
git clone https://github.com/agibalovsa/-1C_DevOps.git oc_devops- Перейдем в каталог docker\os\windows\build.
Создадим файл .arg и наполним его содержимым:
OS_EXT_TAG=mcr.microsoft.com/windows/servercore:ltsc2022
OS_TAG=os/windows/servercore:2022Запустим сборку образа командой:
& ./docker-build.ps1
Внимание! Из-за замедления работы интернета сборка может зависать или завершаться ошибкой обращения к интернет-ресурсу. В этом случае ее нужно перезапускать. Обычно при повторном обращение к ресурсу данные начинают ходить.- После окончания сборки перейдем в каталог docker\mssql\build.
Создадим файл .arg и наполним его содержимым:
OS_TAG=os/windows/servercore:2022
MSSQL_TAG=mssql:2022.CU23
MSSQL_VERSION=2022
DISTR_URL=https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/
DISTR_NAME=SQLServer2022-x64-ENU
UPD_URL=https://download.microsoft.com/download/a89001cb-9c99-48d3-9f14-ded054b35fe4/SQLServer2022-KB5078297-x64.exe-
Запустим сборку образа командой:
& ./docker-build.ps1 -
После окончания сборки перейдем в каталог docker\1c\build\windows.
-
Создадим файл .arg и наполним его содержимым:
OS_TAG="mssql:2022.CU23"
OC_VERSION="8.3.27.1989"
VER_SM="2.0.1.10"
OC_MODE="mssql2022-server"
OC_MODE_SERVER="1"
OC_MODE_WS="0"
OC_MODE_CRS="0"
OC_MODE_CLIENT="0"
OC_TAG="1c/windows-${OC_MODE}:${OC_VERSION}"
INSTALL_MODE="Install-From-File"
INSTALL_FILES="windows64full_$($OC_VERSION.Replace('.', '_')).rar" -
Создадим файл .secret и наполним его содержимым:
ITS_LOGIN=
ITS_PASSWORD=Нужно здесь указать логин и пароль для доступа к 1С ИТС.
-
Запустим сборку образа командой:
& ./docker-build.ps1 -
Если все сборки прошли успешно, выполним очистку без ключа -a:
docker system prune -
После окончания сборки перейдем в каталог docker/1c/compose/server и создадим в нем файл .env. Наполним его содержимым:
OC_SERVER_NAME="oc_server"
OC_SERVER_TAG="1c/windows-mssql2022-server:8.3.27. 1989"
OC_SERVER_HOSTNAME="${OC_SERVER_HOSTNAME}"
HTTP_PORT="80"
OC_RAGENT_PORT="1540"
OC_RMNGR_PORT="1541"
OC_RAS_PORT="1545"
OC_DEBAGER_PORT="1549"
MSSQL_PORT="1433"
OC_RPHOST_PORT="1560-1591"
OC_SRVIFO_VOL="oc_srvinfo"
OC_LIC_VOL="oc_lic"
OC_LOG_VOL="oc_log"
MSSQL_DATA_VOL="mssql_data"
MSSQL_TEMP_VOL="mssql_conf"
OC_CONF_VOL="oc_conf"Здесь переменную ${OC_SERVER_HOSTNAME} вам нужно задать самим.
-
Запустим контейнер командой:
& ./docker-compose-up.ps1В итоге у нас должен стартовать готовый кластер с 1С и MSSQL, готовый к использованию.
-
Пробуем подключиться к 1С через консоль и создать информационную базу:
1С + Postgres
- Подключимся к WSL на хостовой машине.
Скопируем репозиторий 1C_DevOps:
git clone https://github.com/agibalovsa/-1C_DevOps.git oc_devops- В VSCode откроем папку oc_devops через «Файл открыть папку».
Установим программу envsubst:
sudo curl -L https://github.com/a8m/envsubst/releases/download/v1.2.0/envsubst-`uname -s`-`uname -m` -o envsubst;sudo chmod +x envsubst;sudo mv envsubst /usr/local/bin;sudo envsubstЗапустим скрипт:
sudo bash docker/init.shУкажем имя debian:
Укажем раздел build:
Выберем раздел OS System:
В каталоге docker/users/builds/debian зададим значения в файле .arg:
OS_EXT_TAG="debian:bookworm-slim"
OS_TAG="os/debian:bookworm-slim"Здесь путь задан относительно головной папки.
Соберется образ базовой операционной системы:
sudo bash docker/users/builds/debian/docker-build.shЗапустим снова init:
sudo bash docker/init.sh- Внесем имя «jre».
- Укажем «build».
Выберем тип JDK:
В каталоге docker/users/builds/jre зададим значения в файле .arg:
OS_TAG="os/debian:bookworm-slim"
JDK_AZUL_KIT="jre"
AZUL_VERSION="8.92.0.21"
JDK_AZUL_VERSION="8.0.482"
JDK_AXIOM_TYPE="runtime-pro-full"
JDK_AXIOM_VERSION="8u482+10"
[[ "${JDK_AXIOM_TYPE:0:3}" = "pro" ]] && JDK_AXIOM_KIT="jdk" || JDK_AXIOM_KIT="jre"
[[ "${JDK_AXIOM_TYPE: -4}" = "full" ]] && JDK_AXIOM_FULL="-full" || JDK_AXIOM_FULL=""
JDK_PROD="Axiom"
JDK_MAJOR_VERSION="8"
[[ "${JDK_PROD}" = "Axiom" ]] && {
JDK_VERSION="${JDK_AXIOM_VERSION}";
JDK_KIT="${JDK_AXIOM_KIT}${JDK_AXIOM_FULL}";
JDK_PATH="/usr/lib/jvm/axiomjdk-java${JDK_MAJOR_VERSION}-${JDK_AXIOM_TYPE}-amd64";
JDK_TAG="axiom/${JDK_KIT}:${JDK_VERSION/+/.}";
} || { [[ "${JDK_PROD}" = "AzulZulu" ]] && {
JDK_VERSION="${JDK_AZUL_VERSION}";
JDK_KIT="${JDK_AZUL_KIT}";
JDK_PATH="/usr/lib/jvm/zre-${JDK_MAJOR_VERSION}-amd64";
JDK_TAG="azulzulu/${JDK_KIT}:${JDK_VERSION/+/.}";
} }
INSTALL_MODE="install_from_url"
[[ "${JDK_PROD}" = "Axiom" ]] && {
INSTALL_FILES="axiomjdk-${JDK_AXIOM_KIT}-pro${JDK_VERSION}-linux-amd64${JDK_AXIOM_FULL}.deb"
} || { [[ "${JDK_PROD}" = "AzulZulu" ]] && {
INSTALL_FILES="zulu${AZUL_VERSION}-ca-${JDK_KIT}${JDK_VERSION}-linux_amd64.deb"
} }
INSTALL_PACKS="axiomjdk-java${JDK_VERSION:0:2}-${JDK_AXIOM_TYPE}=${JDK_VERSION}"
APTLY_REPO_COMPONENTS="axiom-jdk main"
[[ "${JDK_PROD}" = "Axiom" ]] && {
# > https://download.axiomjdk.ru/axiomjdk-pro/<version>/axiomjdk-<jdk|jre>-pro<version>-linux-amd64<|full|lite>.deb
INSTALL_URLS="https://download.axiomjdk.ru/axiomjdk-pro/${JDK_VERSION}/${INSTALL_FILES}"
} || { [[ "${JDK_PROD}" = "AzulZulu" ]] && {
INSTALL_URLS="https://cdn.azul.com/zulu/bin/${INSTALL_FILES}"
} }Довольно нетривиальный файл, через него можно создать образ с установленными JDK разных версий и от 2-х производителей: Axiom, Azul Zulu.
В текущем примере устанавливается 8 версия JRE от Axiom.
Запустим скрипт сборки:
sudo bash ./docker/users/builds/jre/docker-build.sh- Соберется образ с установленной платформой JRE.
Запустим снова init:
sudo bash docker/init.sh- Укажем имя os-server.
- Укажем “build”.
Выберем тип «1C Platform»:
В каталоге docker/users/builds/oc-server зададим значения в файле .arg:
OS_TAG="axiom/jre-full:8u462.11"
OC_VERSION="8.3.27.1989"
OC_MODE="server" # server, ibsrv, crserver, client, other
OC_MODE_SERVER="1"
OC_MODE_WS="0"
OC_MODE_CRS="0"
OC_MODE_CLIENT="0"
OC_TAG="1c/${OC_MODE}:${OC_VERSION}"
INSTALL_MODE="install_from_url"
SUFFIX="_${OC_VERSION%.*}-${OC_VERSION##*.}_amd64"
INSTALL_FILES="1c-enterprise-${OC_VERSION}-common${SUFFIX}.deb"
[[ "${OC_MODE_SERVER}" = "1" ]] && INSTALL_FILES="${INSTALL_FILES} 1c-enterprise-${OC_VERSION}-server${SUFFIX}.deb" || :
[[ "${OC_MODE_WS}" = "1" ]] && INSTALL_FILES="${INSTALL_FILES} 1c-enterprise-${OC_VERSION}-ws${SUFFIX}.deb" || :
[[ "${OC_MODE_CRS}" = "1" ]] && INSTALL_FILES="${INSTALL_FILES} 1c-enterprise-${OC_VERSION}-crs${SUFFIX}.deb" || :
[[ "${OC_MODE_CLIENT}" = "1" ]] && INSTALL_FILES="${INSTALL_FILES} 1c-enterprise-${OC_VERSION}-client${SUFFIX}.deb" || :
APTLY_REPO_COMPONENTS="1c main"
INSTALL_PACKS="1c-enterprise-${OC_VERSION}-common" || :
[[ "${OC_MODE_SERVER}" = "1" ]] && INSTALL_PACKS="${INSTALL_PACKS} 1c-enterprise-${OC_VERSION}-server" || :
[[ "${OC_MODE_WS}" = "1" ]] && INSTALL_PACKS="${INSTALL_PACKS} 1c-enterprise-${OC_VERSION}-ws" || :
[[ "${OC_MODE_CRS}" = "1" ]] && INSTALL_PACKS="${INSTALL_PACKS} 1c-enterprise-${OC_VERSION}-crs" || :
[[ "${OC_MODE_CLIENT}" = "1" ]] && INSTALL_PACKS="${INSTALL_PACKS} 1c-enterprise-${OC_VERSION}-client" || :
INSTALL_URLS="stub"
OC_URL_LOGIN=login
OC_URL_PASSWORD=passwordОбратите внимание, что нужно указать логин и пароль для доступа к релизам 1С.Выполним команду:
sudo bash docker/users/builds/oc-server/docker-build.sh- Соберется образ с установленной платформой 1С.
Запустим снова init:
sudo bash docker/init.sh- Укажем имя «os-postgres».
- Укажем «build».
Выберем тип «Postgres»:
В каталоге docker/users/builds/oc-postgres зададим значения в файле .arg:
OS_TAG="os/debian:bookworm-slim"
PG_MAJOR_VERSION="17"
PG_VERSION="17.7"
PG_MANUFACTURER="Postgres pro"
PG_PATH="/var/lib/pgpro/1c-17"
PG_BIN_PATH="/opt/pgpro/1c-17/bin"
PG_SHARE_PATH="/opt/pgpro/1c-17/share"
PG_RU=1
PG_TAG="1c/postgres:${PG_VERSION}"Запустим сборку образа:
sudo bash docker/users/builds/postgres/docker-build.sh- Соберется образ с установленным Postgres с патчем под 1С от компании Postgres Pro.
В итоге мы получили 2 образа:
- Для 1С — 1c/server:8.3.27.1989.
- Для Postgres — 1c/postgres:17.7.
Теперь поднимем нашу инфраструктуру.
Запустим снова init:
sudo bash docker/init.shУкажем имя «os-postgres»:
Укажем «compose»:
Выберем 2 типа «1C Platform (server)», «Postgres»:
В каталоге docker/users/compose/oc-postgres зададим значения в файле .env:
OC_SERVER_NAME="oc_server"
OC_SERVER_TAG="1c/server:8.3.27.1989"
OC_SERVER_HOSTNAME="OC_SERVER_HOSTNAME"
HTTP_PORT="80"
OC_RAGENT_PORT="1540"
OC_RMNGR_PORT="1541"
OC_RAS_PORT="1545"
OC_DEBAGER_PORT="1549"
OC_RPHOST_PORT="1560-1591"
OC_SRVIFO_VOL="oc_srvinfo"
OC_LIC_VOL="oc_lic"
OC_LOG_VOL="oc_log"
OC_CONF_VOL="oc_conf"
POSTGRES_TAG="1c/postgres:17.7"
POSTGRES_HOSTNAME="postgres"
POSTGRES_NAME="postgres"
POSTGRES_USER="postgres"
POSTGRES_PASSWORD="postgres"
POSTGRES_DATA_PATH="/var/lib/pgpro/1c-17/data"
POSTGRES_NETWORK="postgres_network"
POSTGRES_PORT="5432"
POSTGRES_DATA_VOL="postgres_data"Переменную OC_SERVER_HOSTNAME нужно задать в соответствие доменного имени вашего хостового сервера.
Создадим тома вручную:
docker volume create oc_srvinfodocker volume create oc_licdocker volume create oc_logdocker volume create oc_confdocker volume create postgres_dataВыполним команду запуска контейнеров:
sudo bash docker/users/compose/oc-postgres/docker-compose-up.shПроверим логи:
sudo bash docker/users/compose/oc-postgres/docker-compose-logs.shpostgres |
postgres | PostgreSQL Database directory appears to contain a database; Skipping initialization
postgres |
postgres | 2026-02-20 15:35:08.055 UTC [1] СООБЩЕНИЕ: передача вывода в протокол процессу сбора протоколов
postgres | 2026-02-20 15:35:08.055 UTC [1] ПОДСКАЗКА: В дальнейшем протоколы будут выводиться в каталог "log".
oc_server | Beginning Ras in background
oc_server | gosu usr1cv8 ras cluster --daemon --port 1545 localhost:1540
oc_server | Beginning Ragent
oc_server | gosu usr1cv8 ragent /port 1540 /regport 1541 /range 1560:1591 /seclev 0 /d /home/usr1cv8/.1cv8/1C/1cv8 /pingPeriod 1000 /pingTimeout 5000
oc_server | 1C:Enterprise 8.3 (x86-64) (8.3.27.1989) Server Agent started. Ctrl+C to exit.
oc_server | 1C:Enterprise 8.3 (x86-64) (8.3.27.1989) Cluster Manager started. Ctrl+C to exit.
oc_server | 1C:Enterprise 8.3 (x86-64) (8.3.27.1989) Working Process started. Ctrl+C to exit.Минут через 5 проверяем инфраструктуру, контейнер 1С должен получить статус здоровья:
Пробуем подключиться к 1С через консоль и создать внутри информационную базу. Здесь важно отметить, что обращение от 1С до Postgres идет по доменным именам во внутренней сети compose. Соответствено, в env файле смотрим, что хостовое имя «postgres».
К кластеру можно подключиться по IP.
1С как микросервис через автономный сервер ibsrv
На основе созданного образа можно развернуть 1С как микросервис через автономный сервер ibsrv.
Остановим предыдущий сервис 1С+Postgres:
sudo bash docker/users/compose/oc-postgres/docker-compose-down.shЗапустим init:
sudo bash docker/init.sh- Укажем имя «os-ibsrv».
- Укажем «compose».
- Выберем только один тип «1C Platform (ibsrv)».
Заполним файл docker/users/compose/oc-ibsrv/.env:
OC_IBSRV_NAME="oc_ibsrv"
OC_IBSRV_TAG="rarus-samara.ru:5000/1c/server:8.3.27.1989"
OC_IBSRV_HOSTNAME="OC_SERVER_HOSTNAME"
OC_IBSRV_CONFIG_PATH="/srv/1c/ibsrv/config_ibsrv.yml"
OC_IBSRV_BASE_NAME="ibsrv"
OC_IBSRV_HTTP_PATH="/ibsrv"
OC_IBSRV_DEBUG="tcp"
OC_IBSRV_HTTP_PORT="8314"
OC_IBSRV_PORT="1541"
OC_IBSRV_DEBUG_PORT="1550"
OC_IBSRV_RANGE_PORT="1560-1591"
OC_IBSRV_DATA_VOL="oc_ibsrv_data"Переменную OC_SERVER_HOSTNAME нужно задать в соответствии с доменным именем вашего хостового сервера.
Создадим том:
docker volume create oc_ibsrv_dataВыполним команду запуска контейнеров:
sudo bash docker/users/compose/oc-ibsrv/docker-compose-up.shПроверим логи:
sudo bash docker/users/compose/oc-ibsrv/docker-compose-logs.shoc_ibsrv | Init ibsrv
oc_ibsrv | gosu usr1cv8 ibcmd server config init --http-address=any --http-port=8314 --http-base=/ibsrv --name=ibsrv --distribute-licenses=no --schedule-jobs=allow --disable-local-speech-to-text=false --database-path=/srv/1c/ibsrv/ibsrv --out=/srv/1c/ibsrv/config_ibsrv.yml
oc_ibsrv | server:
oc_ibsrv | address: any
oc_ibsrv | port: 8314
oc_ibsrv | database:
oc_ibsrv | path: /srv/1c/ibsrv/ibsrv
oc_ibsrv | infobase:
oc_ibsrv | id: c2627322-b1df-4cfd-a6cd-5ae05c54c2c5
oc_ibsrv | name: ibsrv
oc_ibsrv | distribute-licenses: no
oc_ibsrv | schedule-jobs: allow
oc_ibsrv | disable-local-speech-to-text: no
oc_ibsrv | access-right-audit-events-recording: no
oc_ibsrv | http:
oc_ibsrv | base: /ibsrv
oc_ibsrv | [INFO] Создание информационной базы...
oc_ibsrv | [INFO] Создание информационной базы успешно завершено
oc_ibsrv | Beginning ibsrv
oc_ibsrv | gosu usr1cv8 ibsrv --direct-regport=1541 --direct-range=1560:1591 --direct-seclevel=0 --debug=http --debug-address=any --debug-port=1550 --config=/srv/1c/ibsrv/config_ibsrv.yml
oc_ibsrv | 1C:Enterprise 8.3 (x86-64) (8.3.27.1989) Stand-alone Server started. Ctrl+C to exit.
oc_ibsrv | 1C:Enterprise 8.3 (x86-64) (8.3.27.1989) Stand-alone Server ready.По умолчанию поднялся автономный сервер и создал файловую базу.
Файл настроек и файловая база доступпны в томе oc_ibsrv_data.
Соответствено, их можно настраивать.
Обратимся к серверу через браузер по адресу:
http://OC_SERVER_HOSTNAME:8314/ibsrv/ru/Вместо OC_SERVER_HOSTNAME можно указать IP.
Обратимся к сервису через Конфигуратор, для этого опишем подключение:
И зайдем в Конфигуратор:
В данной ИБ дальше можно настроить любой веб-сервис, с которым будут общаться другие узлы инфраструктуры.
Заключение
Друзья, на этом вторая статья о контейнеризации заканчивается. Изучение контейнеризации, конечно, требует времени и сил, очень много особенностей нужно знать. При погружении в эту среду открываются огромные перспективы по автоматическому разворачиванию целых сред. И экосистема 1С не находится в антогонизме к технологии контейнеризации, что мы и пытались показать на примерах из своей практики.
Но это еще не всё. Уже задумана следующая статья, где будет рассказано про автоматическую сборку контейнеров, про их оркестрацию.
От экспертов «1С-Рарус»
Читайте первыми статьи от экспертов «1С‑Рарус»
Вы можете получать оповещения по электронной почте
Или получайте уведомления в телеграм-боте