Конвейер доставки 1С там, где нет SSH: RDP-диск как транспорт
Разработка - DevOps и автоматизация разработки
1. Откуда взялась задача
Я работаю с самописной конфигурацией на платформе 8.3 в режиме совместимости 8.2. В ней используются обычные формы, хранилище конфигурации находится на тестовом сервере, а боевой сервер доступен через шлюз удалённых рабочих столов. Рядом есть вторая база, типовая бухгалтерия. Хранилища у неё нет, поэтому доработки доставляются в виде расширения.
До автоматизации мой рабочий цикл выглядел так. Я открывал RDP, вручную обновлял тестовую базу из хранилища в Конфигураторе, захватывал объекты, объединял конфигурацию со своей сборкой, проверял результат, помещал изменения в хранилище и снимал захват. Затем открывал ещё один RDP-сеанс, уже на боевом сервере. Каждая доработка требовала около часа однообразных действий. Невнимательность обходилась дорого: можно было забыть завершить сеансы или объединить не те объекты. При десяти доработках в неделю на эту работу уходила заметная часть времени.
Я посмотрел, какие готовые инструменты есть в открытом доступе:
- Режим агента Конфигуратора (
/AgentMode; обзор, обвязка на Python): платформа принимает команды по SSH. По назначению этот вариант ближе всего к моей задаче, но для него нужен открытый порт на сервере. - vanessa-runner (OneScript): обёртка над пакетным Конфигуратором с группами команд
cf,cfe,epf,infobase,repo,cluster. Она закрывает весь мой цикл: обновляет конфигурацию из хранилища, захватывает объекты по списку (repo lock --objects), объединяет конфигурацию с.cfпо файлу настроек (cf merge --merge-settings), помещает изменения с комментарием (repo commit), снимает захват и связь с хранилищем, управляет сеансами и расширениями, делает выгрузки. На сервере я могу запустить её только вручную в RDP-сеансе или через собственного агента. Поэтому канал доставки команд всё равно пришлось бы разрабатывать. Вызовы Конфигуратора внутри агента можно заменить на vrunner, но тогда на каждом сервере потребуется OneScript. К тому времени мои обёртки уже прошли проверку на рабочем хранилище. - deployka (OneScript):
loadrepo,loadcfg,dbupdate,session. Проект объявлен устаревшим, вместо него рекомендуют vanessa-runner. - Конвейеры на OneScript + Jenkins (типовая сборка) и «1С on demand» с агентом сборки, который запускается по требованию.
- MCP-серверы для 1С (mcp-1c, MCP:RSV Data, INFATON, Infostart MCP): они обращаются к базе через HTTP-сервис или напрямую из внешнего процесса.
В моих условиях все эти варианты упирались в один вопрос: как запустить инструмент на сервере. Из доступных каналов у меня был только RDP. Открытых портов и WinRM не было, а установить OneScript или агент Jenkins мне не разрешали. Системные администраторы на такие запросы отвечали вежливым отказом.
2. Идея: диск как канал связи
RDP позволяет пробросить в сеанс локальный диск рабочей станции. На сервере он виден как \\tsclient\F. Сервер может читать и записывать файлы на этом диске, а локальным сценариям тот же диск доступен по обычному пути F:\.
На этом и построена схема. В RDP-сеансе на сервере работает PowerShell-скрипт, то есть агент. Раз в несколько секунд он проверяет папку \\tsclient\F\deploy\test\in. Увидев JSON с командой, агент запускает пакетный Конфигуратор, rac или COM, а затем кладёт ответ в формате JSON в папку out. На рабочей станции другой скрипт, оркестратор, записывает команду, ждёт ответ и выводит результат. Мне не понадобились сетевые порты, службы и установка программ. Агент работает, пока в RDP-сеансе открыто окно PowerShell.
рабочая станция RDP-сеанс на сервере 1С
deploy.ps1 pull ^72;`54; F:\deploy\test\in\20260907-1015-pull.json
deploy-agent.ps1: rac (снять сеансы)
1cv8 /ConfigurationRepositoryUpdateCfg
1cv8 /UpdateDBCfg
1cv8 /DumpCfg U94; artifacts\snapshot-….cf
deploy.ps1 `64;^72; F:\deploy\test\out\20260907-1015-pull.json {status: ok, sha256: …}
Звучит примитивно. Так и есть, и в этом смысл: схема работает на любом Windows-сервере 1С, если есть RDP с перенаправлением диска и PowerShell.

Окно агента в RDP-сеансе. Имена машин и баз заменены, тексты платформы и тайминги настоящие.
3. Что умеет агент
Команды появлялись по мере необходимости. За два месяца их набралось около тридцати. Вот основные:
- Хранилище:
pullобновляет тестовую базу и делает снимок.cf;testзахватывает объекты по списку и накладывает сборку черезMergeCfg;commitпомещает версию;unlockотменяет захват;repo-bindиrepo-unbindуправляют связью базы с хранилищем. - Боевая:
update-prod -Mode hot|full. Сначала агент делает резервную копию конфигурации. Затем он либо выполняет динамическое обновление без завершения сеансов, либо запускает полное обновление во время выделенного для этого окна. Если динамическое обновление не применилось из-за реструктуризации, агент останавливается и ждёт решения человека. Самостоятельно переходить наfullон не будет, поскольку полное обновление затронет сотню работающих людей. - База без хранилища:
ext-list,ext-dump,ext-installс автоматической резервной копией прежней версии, а такжеdump-cfиdump-dt. - Диагностика:
sessions;peek, чтобы посмотреть файл или каталог на сервере;windows, чтобы получить список всех окон 1С, включая модальные диалоги;screenshot;com-check, чтобы проверить доступность базы по COM и собрать подробности для заявки системным администраторам;fetch, чтобы забрать файл с сервера. - MCP:
mcp-start/mcp-stop/mcp-list. Об этих командах расскажу отдельно ниже.

Команда test на рабочей станции: захват по списку, локальная копия сборки, объединение, применение. Ответ агента печатается целиком.
Перед опасными командами оркестратор выводит заметное предупреждение. Команды test и commit меняют общее хранилище, update-prod обновляет боевую базу, а dump-dt завершает все сеансы. Я запускаю эти команды через ИИ-агента Claude Code. В его инструкциях прямо запрещено выполнять commit и update-prod без моего явного «да».
4. Неочевидные особенности, ради которых стоило написать статью
Эта часть для меня самая полезная. О некоторых особенностях я позже прочитал на форумах, а упоминаний о других не нашёл. Но со всеми сначала познакомился на практике, когда что-то уже переставало работать.
4.1. Файловые операции через \tsclient очень медленны
Первая версия агента записывала лог в папку обмена построчно с помощью Add-Content. Одна строка записывалась около десяти секунд. Теперь лог хранится локально в %TEMP%, а после каждой команды копируется в папку обмена целиком.
Следующая проблема оказалась серьёзнее. MergeCfg обрабатывал сборку размером 54 МБ тридцать минут. Сначала я винил размер конфигурации, но затем запустил тот же MergeCfg с файлом на локальном диске сервера. Операция заняла 22 секунды. При объединении .cf читается многократно, а каждое чтение через перенаправленный RDP-диск обходится дорого. Поэтому теперь агент сначала копирует крупные файлы, в том числе сборки, расширения и снимки, на локальный диск сервера и лишь потом передаёт их платформе. Копирование 54 МБ занимает две с половиной минуты, а весь test выполняется за три с половиной вместо тридцати.
Скорость канала держится примерно на уровне 1 МБ/с. Выгрузка базы размером 17 ГБ передавалась четыре с лишним часа. Поэтому dump-dt оставляет файл на сервере. Затем его можно забрать отдельной командой fetch, причём оркестратор сразу предупреждает, что операция будет долгой.
4.2. Два разных \tsclient в одном сеансе
Однажды мне понадобилось скопировать выгрузку с сервера. Сначала я решил запустить robocopy через com-exec, поскольку агент умеет выполнять на сервере VBScript. Команда завершилась без единой ошибки и сообщила, что файл «скопирован», но на рабочей станции его не оказалось.
Выяснилось, что путь \\tsclient\F для процесса, запущенного через cscript, указывал на другой RDP-сеанс того же пользователя. В тот момент у меня были открыты два сеанса на одном сервере. В результате robocopy записал 16 ГБ на диск другой машины. Теперь файлы копирует сам агент с помощью Copy-Item, а после копирования он сверяет размеры исходного и полученного файлов.
4.3. Закрытое окно Конфигуратора не означает, что сеанс завершён
В теории это очевидно, но на практике легко забыть. Команда ConfigurationRepositoryUpdateCfg останавливается из-за блокировки, хотя кажется, что «никто не работает». Поэтому перед каждой пакетной операцией агент завершает через rac все сеансы базы. В ответе он указывает, сколько сеансов завершено и сколько осталось.
Есть и побочный эффект. Завершение сеансов разрывает COM-соединение демона MCP, если тот подключён к этой же базе. Я добавил в демон одну повторную попытку: он восстанавливает соединение и снова отправляет запрос.
4.4. LoadCfg и UpdateDBCfg в одном запуске платформа не принимает
Команда /LoadCfg file.cfe -Extension Имя /UpdateDBCfg -Extension Имя возвращает «Ошибка в параметрах командной строки». Если выполнить её за два отдельных запуска, всё работает. На выяснение причины у меня ушёл час. В документации я не нашёл описания этого ограничения. На форуме такая тема есть (пакетное обновление расширения из хранилища), но увидел я её уже после.
4.5. Как понять, что динамическое обновление боевой базы не применилось
При активных сеансах и необходимости реструктуризации UpdateDBCfg -Dynamic+ завершается ошибкой исключительной блокировки и печатает список сеансов, которые её держат. Конфигурация при этом остаётся полученной из хранилища, но к базе не применяется, то есть база и её конфигурация расходятся. По одному коду возврата не понять, что именно случилось: нужен монопольный режим или обновление сломалось по другой причине. Поэтому агент считает динамическое обновление применённым только при нулевом коде и строке «Обновление конфигурации успешно завершено» в выводе. Всё остальное он возвращает отдельным статусом «динамика не применилась, стоп» вместе с полным выводом платформы. На всякий случай он ещё ищет в выводе слова «монопол» и «реструктуриз»: нулевой код с такими словами тоже считается стопом. Да, это русская локаль и регулярные выражения. Я проверил такое поведение на работающей боевой базе со 112 сеансами.

Тот самый стоп: платформа вернула ошибку исключительной блокировки и 112 сеансов, агент не стал переключаться на полное обновление.
4.6. Связь с хранилищем рвётся после перезаливки базы
После того как тестовую базу перезалили из .dt, команда pull стала возвращать ошибку: «Пользователь существующей связи отличается от текущего». В Конфигураторе эту известную проблему решают отключением от хранилища. Пакетно сменить пользователя существующей связи нельзя. Можно только выполнить /ConfigurationRepositoryUnbindCfg -force, а при следующем обновлении привязаться заново. Для этого я добавил команду repo-unbind.
Отвязанная база подводит ещё раз, и уже незаметно: pull на ней завершается успешно, а вот захват падает с пустым «Ошибка захвата объектов в хранилище» — ровно так же, как если бы объект держал коллега. Разбираться в этом посреди доставки неприятно, поэтому теперь агент делает это сам: разбирает текст ошибки платформы, выполняет /ConfigurationRepositoryBindCfg -forceBindAlreadyBindedUser под учётной записью из конфига и один раз повторяет упавший шаг. Замену конфигурации базы хранилищной (-forceReplaceCfg) он включает только внутри pull, где база и так приводится к состоянию хранилища, и никогда на боевой роли. Отдельно связь ставится командой repo-bind.
Одно лечению не поддаётся: отказ «Пользователь уже аутентифицирован в хранилище». Файловое хранилище держит одну сессию на пользователя, и если она залипла, повторный вход отвергается до тех пор, пока сессия не отвалится сама. Помогает либо другая учётная запись, либо ожидание.
4.7. Пакетный Конфигуратор молчит, и это выглядит как зависание
1cv8 DESIGNER в пакетном режиме не пишет в консоль ничего до самого выхода, а Copy-Item не показывает прогресс. В итоге копирование сборки на 55 МБ через канал RDP занимало восемь минут абсолютной тишины, и в эти минуты трудно отличить работу от повисшего процесса. Теперь агент раз в десять секунд переписывает в своём окне строку «шаг: идёт, N с», а крупные файлы копирует потоком и показывает проценты. В файл лога счётчик не идёт: там остаются только начало, четверти и итог.
4.8. Внешняя обработка со старшей платформы без сообщения не открывается на младшей
На рабочей станции установлена платформа 8.3.27, а на сервере 8.3.24. Собранный на рабочей станции файл .epf сервер не открывает и не показывает причину. Только в глубине лога я нашёл сообщение «Неизвестная версия формата 2.20». Поэтому команда build-epf собирает обработку из XML на платформе сервера через LoadExternalDataProcessorOrReportFromFiles.
4.9. Расширение нужно собирать на той версии типовой конфигурации, которая установлена в боевой базе
Команда UpdateDBCfg -Extension завершилась сообщением «Значение контролируемого свойства Тип у объекта … не совпадает со значением в расширяемой конфигурации». Моя копия бухгалтерии для разработки отставала на семь релизов. При этом база осталась в промежуточном состоянии: LoadCfg выполнился, а UpdateDBCfg нет. Помогла автоматическая резервная копия, которую ext-install создаёт перед установкой. Я установил прежнюю версию с -NoBackup, и база вернулась в нормальное состояние. Автоматическую резервную копию можно отключить, но я этого не делаю.
5. Доступ к базе через MCP по COM, без клиента 1С
Параллельно возникла другая задача. Я хотел, чтобы ИИ-агент на рабочей станции мог выполнять запросы только на чтение к боевой базе и помогать с анализом задач. Заказчик не разрешил публиковать на боевой базе HTTP-сервис, и это разумное ограничение.
Я снова использовал файловый канал. Внешняя обработка содержит ядро MCP: разбор JSON-RPC, инструменты execute_query, метаданные и историю изменений. Она открывается во внешнем соединении через V83.COMConnector. Небольшой демон на VBScript передаёт обработке запросы из папки in, а ответы складывает в out. Для работы не нужны окна и клиент 1С, но требуется одна лицензия на внешнее соединение.
Я пробовал обойтись тонким клиентом с /Execute. В обычном приложении ключ /Execute запускает клиент и показывает рабочий стол, однако модуль обработки не выполняется. В управляемом приложении обработка подключается, что видно в журнале регистрации по событию ExternalDataProcessorConnect, но её форма не открывается и автоматический запуск из ПриОткрытии не срабатывает. Обработчик ожидания в клиенте, запущенном в пакетном режиме, тоже не тикает. Из проверенных вариантов сработало COM-соединение.
При настройке COM-соединения я столкнулся ещё с несколькими особенностями:
- Файл
.epfоткрывает сервер 1С, а не скрипт. Процессrphostне видит проброшенный\\tsclient, поэтому обработка должна находиться на диске, доступном серверу. Если кластер работает не на той машине, где запущен агент, как в случае с бухгалтерией, путь к файлу приходится вручную задавать в файле настроек. - Кэш
rphostпривязан к пути к файлу. Я перезаписал.epfпод прежним именем, но сервер продолжил загружать старую редакцию. Новые методы возвращали COM-ошибку 438 «Object doesn't support this property or method», хотя в файле они были. Поэтому при обновлении обработки я меняю имя файла. - При позднем связывании PowerShell получал от объектов 1С
$nullвместо значений свойств. Поэтому работу через COM я написал на VBScript. - В VBScript нет
CallByName, он есть в VBA. Кроме того, VBScript не вызывает методы с кириллическими именами. Поэтому точка входа обработки названа латиницей,ProcessMCPRequest, а для ядра с кириллическим именем сделана экспортная обёртка. - Лицензии. На боевой бухгалтерии с двумя десятками пользователей второе внешнее соединение уже возвращает «Не обнаружено свободной лицензии». Поэтому я не держу запущенными лишние демоны.
Я не включил ядро MCP в репозиторий: у каждого оно своё, а на Инфостарте есть несколько готовых вариантов, от mcp-1c до INFATON. Демону и агенту нужен от обработки только один экспортный метод.
6. Что не вошло и что пока не решено
- Сборка
release.cfиз исходников. Я используюibcmd config import files --partial --no-checkповерх снимка хранилища, но эта тема заслуживает отдельного рассказа. Например,LoadConfigFromFiles -files <манифест>в Конфигураторе успешно завершается, но добавляет ноль новых объектов. Возможно, я вернусь к этому в следующей статье. - Агент работает, пока существует RDP-сеанс. Если отключиться от сеанса, агент продолжит работать, но перезагрузка сервера его остановит. Скрипт
rdp-open.ps1умеет открыть сеанс и запустить через Win+R сценарий запуска, используяSendKeys. Такой обходной путь нельзя считать надёжным решением. - В папке обмена нет аутентификации. Команды может отправлять тот, у кого есть доступ на запись к диску рабочей станции. В моих условиях это приемлемо, поскольку диск принадлежит мне.
- Агент разбирает тексты платформы в русской локали.
- Вызовы Конфигуратора внутри агента можно передать vanessa-runner. Агент тогда останется каналом доставки, а
repo lock,cf merge,repo commitи остальные операции выполнит vrunner. Для этого политика сервера должна разрешать запуск портативного OneScript. В моём окружении я такой вариант не проверял, поскольку собственные обёртки к тому времени уже работали.
7. Итог
За полтора месяца с помощью конвейера я сорок раз поместил изменения в хранилище и восемь раз обновил боевую базу. В это число вошли полные обновления с завершением сеансов. Вместо часа однообразных действий я теперь запускаю четыре команды и один раз проверяю результат в тестовой базе вручную.
На практике перенаправленный RDP-диск оказался пригодным для управления сервером, несмотря на невысокую скорость. В моём процессе его хватает для всего цикла доставки. Важно сначала копировать крупные файлы на локальный диск сервера и не записывать логи в папку обмена построчно.
Код: https://github.com/ShcherbakovP/1c-deploy-agent, лицензия MIT. В репозитории лежат агент, оркестратор, сценарий запуска, демон COM и README со списком ограничений, с которыми я столкнулся на практике.
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
02.11.2026 466 vanya_gonchar 2