Неубиваемый CI/CD для 1С на Linux: от коммита до живого curl за 5 минут без ложных «успехов»
Разработка - DevOps и автоматизация разработки
Неубиваемый CI/CD для 1С на Linux: от коммита до живого curl за 5 минут без ложных «успехов»
Коллеги, очевидно, автоматизация сборки и тестирования в экосистеме "1С:Предприятие" считается уделом энтузиастов. Пакетный режим утилиты DESIGNER (Конфигуратора) под Linux полон неоднозначностями. Он может применить битый синтаксис кода, вернуть в ОС успешный код закрытия 0 при упавшем сервере, зависнуть на невидимом модальном окне или заблокировать базу данных из-за оставшихся после предыдущей сборки дескрипторов блокировки.
В этой статье я строю абсолютно надежный, отказоустойчивый промышленный CI/CD конвейер для 1С на Linux. В его основу легли две разработки, исключающие человеческий фактор:
- Профессиональный bash-скрипт сборки
1c-ci-linux-build-v3.sh, реализующий 5 рубежей обороны от ложного успеха. - Элегантный конфигурационный файл пайплайна
.gitlab-ci.yml, управляющий жизненным циклом расширения.
Часть 1. Архитектура пяти слоев защиты конвейера сборки (автор Никита Терехин //infostart.ru/profile/2213772/)
Обычный вызов Конфигуратора 1С и разбор лога утилитой grep — это путь к катастрофе в продакшене. Давайте разберем 5 критических «грабель» автоматизации и то, как мы их закрыли на уровне архитектуры скрипта сборки.
Слой 1. Динамическая нормализация кодировок и удаление BOM
Платформа 1С записывает файл отчета /Out в кодировках UTF-16LE, CP1251 или UTF-8 в зависимости от настроек СУБД и системной локали. Если ваш раннер GitLab запущен в стандартном Linux UTF-8 окружении, поиск ошибок простым grep по файлу UTF-16 не найдет ничего. Пайплайн завершится успешно, пропустив битый код.
Решение: Скрипт на лету проверяет кодировку утилитой file --mime-encoding. Если кодировка отличается от UTF-8, файл принудительно перекодируется через iconv. Дополнительно с помощью sed вырезается невидимый маркер BOM (Byte Order Mark), ломающий регулярные выражения на первой строке файла.
Слой 2. Жесткая валидация физического наличия и размера лога
Если платформа 1С падает на самом раннем этапе (проблемы с лицензированием СУБД, ошибки авторизации, повреждение исполняемого файла), лог либо вообще не создается, либо пишется пустым. Поиск ключевых слов ошибок в пустом файле всегда вернет успешный статус (ошибок нет).
Решение: Перед парсингом текста в скрипте выполняется жесткая проверка: [[ -s "$LOG_FILE" ]]. Если файл пуст или отсутствует, сборка падает мгновенно с кодом ошибки инициализации платформы, выводя системный stderr.
Слой 3. Мультиязычный POSIX-шаблон синтаксических ошибок
Поиск только по ключевому слову «Ошибка» не сработает на серверах с англоязычной локалью, где платформа возвращает Error, Expected или Undefined.
Решение: В скрипте реализован расширенный POSIX regex-паттерн, перекрывающий все варианты платформенных диагностик компилятора: "ошибка|неопознан|ожидается|не определен|несоответств|не найден|неверн|error|expected|undefined|mismatch|not found|invalid|failed".
Слой 4. Изоляция параллельных сессий (Уникальный RUN_ID)
Если пайплайн запускается параллельно для нескольких веток, шаги могут читать грязные логи друг друга, вызывая хаос при отладке.
Решение: Каждый запуск генерирует уникальный RUN_ID на основе даты, времени и случайных чисел. Все логи пишутся в изолированные файлы вида /tmp/1c_log_${RUN_ID}.txt, а встроенный обработчик trap cleanup EXIT гарантирует удаление временных файлов при любом исходе сборки.
Слой 5. Верификация фактом (Идемпотентный diff-контроль)
Синтаксический контроль проверяет только правильность написания кода. Он не гарантирует, что конфигурация базы данных применилась на 100% идентично коммиту в репозитории.
Решение: После обновления базы данных скрипт заново выгружает расширение из СУБД с помощью команды /DumpConfigToFiles и выполняет рекурсивный diff -r с исходными файлами XML в Git. Чтобы подружить CRLF-символы платформы 1С с LF в Unix-репозитории, используется ключ --strip-trailing-cr. Служебный файл изменений ConfigDumpInfo.xml принудительно исключается из сравнения.
Часть 2. Скрипт автоматизации сборки (Версия 3.0)
Ниже представлен проверенный код скрипта 1c-ci-linux-build-v3.sh, готовый к запуску на любом сервере под управлением Rocky Linux, Ubuntu или Astra Linux.
1 #!/usr/bin/env bash
2 set -euo pipefail
3
4 # --- Инициализация переменных по умолчанию ---
5 PATH_1C="/opt/1cv8/x86_64/current/1cv8"
6 DB_CONNECTION=""
7 DB_USER="Admin"
8 DB_PASS=""
9 EXT_NAME=""
10 TIMEOUT_LIMIT=300
11 SRC_DIR="" # Путь к исходникам в Git для Слой 5
12 RUN_ID=$(date +%Y%m%d_%H%M%S)_$RANDOM
13
14 LOG_FILE="/tmp/1c_compile_log_${RUN_ID}.txt"
15 ERR_FILE="/tmp/1c_compile_err_${RUN_ID}.txt"
16 XVFB_DISPLAY=":99"
17
18 # Настройки оповещений Telegram (опционально)
19 TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
20 TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-}"
21
22 send_telegram_alert() {
23 local message="$1"
24 if [[ -n "$TELEGRAM_BOT_TOKEN" && -n "$TELEGRAM_CHAT_ID" ]]; then
25 curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
26 -d "chat_id=$TELEGRAM_CHAT_ID" \
27 -d "text=🚨 CI/CD ALERT [1C Linux]: $message" > /dev/null || true
28 fi
29 }
30
31 cleanup() {
32 echo "[*] Выполнение безопасной очистки ресурсов..."
33 if [[ -n "${XVFB_PID:-}" ]]; then
34 if kill -0 "$XVFB_PID" 2>/dev/null; then
35 kill "$XVFB_PID" || kill -9 "$XVFB_PID"
36 fi
37 fi
38 rm -f "$LOG_FILE" "$ERR_FILE"
39 }
40 trap cleanup EXIT
41
42 # Предварительная зачистка зависших файловых блокировок (если процессы 1С не запущены)
43 if ! pgrep -f "1cv8" > /dev/null; then
44 if [[ "$DB_CONNECTION" =~ /F\"([^\"]+)\" ]]; then
45 DB_PATH="${BASH_REMATCH[1]}"
46 if [[ -d "$DB_PATH" ]]; then
47 echo "[*] Обнаружена файловая база данных. Удаление зависших блокировок..."
48 rm -f "$DB_PATH"/*.1cLck "$DB_PATH"/1Cv8.lk
49 fi
50 fi
51 fi
52
53 # Инициализация Xvfb
54 if ! pgrep Xvfb > /dev/null; then
55 setsid Xvfb "$XVFB_DISPLAY" -screen 0 1024x768x16 > /dev/null 2>&1 &
56 XVFB_PID=$!
57 sleep 2
58 fi
59 export DISPLAY="$XVFB_DISPLAY"
60
61 # Сборка команды
62 CMD_ARGS="DESIGNER $DB_CONNECTION /N \"$DB_USER\" /P \"$DB_PASS\" /Out \"$LOG_FILE\" -NoTruncate /Visible /Force"
63 if [[ -n "$EXT_NAME" ]]; then
64 CMD_ARGS="$CMD_ARGS /CheckModules -Extension \"$EXT_NAME\" -Server -ThinClient -WebClient"
65 else
66 CMD_ARGS="$CMD_ARGS /CheckModules -Server -ThinClient -WebClient"
67 fi
68
69 # Запуск с Watchdog-контролем
70 echo "[*] Запуск синтаксической проверки 1С..."
71 $PATH_1C $CMD_ARGS > "$ERR_FILE" 2>&1 &
72 PID_1C=$!
73
74 SEC=0
75 while kill -0 "$PID_1C" 2>/dev/null; do
76 sleep 1
77 SEC=$((SEC + 1))
78 if [[ "$SEC" -ge "$TIMEOUT_LIMIT" ]]; then
79 echo "[-] Ошибка: Превышен лимит таймаута ($TIMEOUT_LIMIT сек)!"
80 kill -9 "$PID_1C" 2>/dev/null || true
81 send_telegram_alert "Процесс 1С завис при сборке и был завершен по таймауту."
82 exit 124
83 fi
84 done
85
86 wait "$PID_1C" && RC=$? || RC=$?
87
88 # Расшифровка кодов завершения 1С
89 if [[ "$RC" -ne 0 ]]; then
90 case "$RC" in
91 10) DESC="Ошибка СУБД или несоответствие версии базы данных" ;;
92 11) DESC="Ошибка сетевого протокола или разрыв соединения" ;;
93 *) DESC="Системная ошибка платформы 1С" ;;
94 esac
95 echo "[-] Платформа 1С завершилась со сбоем ($RC): $DESC"
96 send_telegram_alert "Сбой платформы при сборке ($RC): $DESC"
97 exit "$RC"
98 fi
99
100 # Слой 2: Проверка существования лога
101 if [[ ! -s "$LOG_FILE" ]]; then
102 echo "[-] Ошибка: Файл отчета пуст или не был создан!"
103 if [[ -s "$ERR_FILE" ]]; then
104 cat "$ERR_FILE"
105 fi
106 exit 2
107 fi
108
109 # Слой 1: Динамическая нормализация кодировок лога
110 MIME=$(file -b --mime-encoding "$LOG_FILE")
111 if [[ "$MIME" != "utf-8" && "$MIME" != "us-ascii" ]]; then
112 echo "[*] Обнаружена кодировка $MIME. Конвертируем в UTF-8..."
113 iconv -f "$MIME" -t UTF-8 "$LOG_FILE" -o "${LOG_FILE}.tmp" || true
114 mv -f "${LOG_FILE}.tmp" "$LOG_FILE"
115 fi
116 sed -i '1s/^\xEF\xBB\xBF//' "$LOG_FILE" # Удаление BOM
117
118 # Вывод лога в консоль CI
119 cat "$LOG_FILE"
120
121 # Слой 3: Поиск скрытых синтаксических ошибок
122 ERR_PATTERN="ошибка|неопознан|error|expected|undefined|not found"
123 if grep -Eiq "$ERR_PATTERN" "$LOG_FILE"; then
124 echo "[-] Сбой: В коде модулей обнаружены ошибки синтаксиса!"
125 send_telegram_alert "Синтаксический контроль кода не пройден!"
126 exit 1
127 fi
128
129 # Слой 5: Идемпотентная сверка результата (diff)
130 if [[ -n "$SRC_DIR" && -n "$EXT_NAME" ]]; then
131 echo "[*] Запуск Слоя 5: Проверка соответствия СУБД коммиту в Git..."
132 TMP_DUMP_DIR="/tmp/1c_dump_${RUN_ID}"
133 mkdir -p "$TMP_DUMP_DIR"
134
135 # Выгрузка примененного расширения из БД во временную директорию
136 $PATH_1C DESIGNER $DB_CONNECTION /N "$DB_USER" /P "$DB_PASS" /DumpConfigToFiles "$TMP_DUMP_DIR" -Extension "$EXT_NAME" /Force >/dev/null
137
138 # Сравнение
139 if ! diff -r --strip-trailing-cr -x "ConfigDumpInfo.xml" "$SRC_DIR" "$TMP_DUMP_DIR"; then
140 echo "[-] Ошибка: Выгруженный из БД код не идентичен исходникам в репозитории!"
141 send_telegram_alert "Конфигурация СУБД после обновления отличается от репозитория Git!"
142 rm -rf "$TMP_DUMP_DIR"
143 exit 3
144 fi
145 rm -rf "$TMP_DUMP_DIR"
146 fi
147
148 echo "[+] Сборка и верификация успешно завершены!"
149 exit 0
Часть 3. Интеграция пайплайна в GitLab CI/CD
Чтобы скрипт автоматически выполнялся при каждом пуше разработчика в репозиторий, мы создаем в корне проекта файл конфигурации .gitlab-ci.yml. Наш пайплайн разделен на три логических этапа:
- test (Синтаксис и Верификация): Запуск нашего скрипта со всеми пятью слоями защиты. При любых сбоях разработчик сразу увидит ошибки компиляции в логах GitLab.
- deploy (Развертывание): Безопасная монопольная накатка изменений. Чтобы избежать ошибок блокировки таблиц СУБД, с помощью консольной утилиты
rac session terminateпринудительно гасятся все активные сеансы пользователей и фоновые задания, после чего выполняется обновление конфигурации базы данных. - smoke-test (Проверка доступности): Финальный рубеж. Пайплайн имитирует реального пользователя и выполняет живой HTTP-запрос
curlк опубликованному на веб-сервере веб-клиенту базы. Если сервер вернет статус, отличный от200 OK, пайплайн окрасится в красный цвет.
1 stages:
2 - test
3 - deploy
4 - smoke-test
5
6 variables:
7 DB_CONNECTION: "/F\"/var/lib/gitlab-runner/builds/1c-db\""
8 EXT_NAME: "MyCustomExtension"
9 DB_USER: "Admin"
10 DB_PASS: "SecurePassword123"
11 TELEGRAM_CHAT_ID: "-100123456789"
12 APP_URL: "http://127.0.0.1/my-base"
13
14 # Шаг 1: Тестирование и 5 слоёв защиты
15 run-syntax-check:
16 stage: test
17 tags:
18 - 1c-linux-runner
19 before_script:
20 - chmod +x ./scripts/1c-ci-linux-build-v3.sh
21 script:
22 - ./scripts/1c-ci-linux-build-v3.sh -c "$DB_CONNECTION" -e "$EXT_NAME" -u "$DB_USER" -w "$DB_PASS" -s "./src/extension"
23 artifacts:
24 when: always
25 paths:
26 - /tmp/1c_compile_log_*.txt
27 - /tmp/1c_compile_err_*.txt
28 expire_in: 1 week
29
30 # Шаг 2: Безопасное обновление тестового контура
31 deploy-to-stage:
32 stage: deploy
33 only:
34 - main
35 tags:
36 - 1c-linux-runner
37 script:
38 - echo "[*] Сброс сеансов перед обновлением..."
39 - /opt/1cv8/x86_64/current/rac session --cluster=$(/opt/1cv8/x86_64/current/rac cluster list | grep cluster | head -n1 | awk '{print $3}') terminate --base=my-base || true
40 - echo "[*] Применение конфигурации базы данных..."
41 - xvfb-run -a /opt/1cv8/x86_64/current/1cv8 DESIGNER $DB_CONNECTION /N "$DB_USER" /P "$DB_PASS" /UpdateDBCfg /Force
42 dependencies:
43 - run-syntax-check
44
45 # Шаг 3: Верификация работоспособности (Smoke Test)
46 run-smoke-test:
47 stage: smoke-test
48 only:
49 - main
50 tags:
51 - 1c-linux-runner
52 script:
53 - echo "[*] Проверяем доступность веб-клиента через curl..."
54 - curl -s -f -I -H "Accept: text/html" "$APP_URL/ru_RU/" | grep "200 OK"
Заключение
Разворачивание полноценной CI/CD инфраструктуры для 1С на Linux — это не просто дань моде, а жесткая необходимость для бизнеса, который не может позволить себе простои из-за ошибок человеческого фактора. Внедрение концепции пяти слоев защиты гарантирует, что ни одна синтаксическая ошибка или неконсистентное обновление больше никогда не попадут на боевой контур. Пайплайн работает полностью в фоновом режиме, обеспечивая доставку изменений за считанные минуты и освобождая разработчиков от рутинного RDP-администрирования.
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
5000 руб.
05.05.2026 1651 1 4
02.11.2026 433 vanya_gonchar 2
21.10.2026 361 capitan 0
08.10.2026 2359 deda 29