cloudnative-1c | Овчаренко Дмитрий – Telegram
cloudnative-1c | Овчаренко Дмитрий
228 subscribers
9 photos
19 links
Канал о том, как платформа 1С становится "first-class citizen" в кластерах Kubernetes

@ovcharenko_di
Download Telegram
Когда всего месяц назад пересматривал Breaking Bad и ассоциация с лабораторией у тебя сейчас может быть только одна ⚗️
😁3
👀 Как разместить кластер 1С в кубере?

Да очень просто! Надо взять и установить соответствующий helm-чарт, вот так:
haha helm install go brrr...


Для большинства приложений такой сценарий действительно применим, но для 1С - нет.

Я знаю только один helm-чарт с сервером 1С от Руслана Жданова (@TheDemonCat). Насколько мне известно, Руслан - первопроходец этой темы, но его чарт не подразумевает работу с кластером 1С извне. А еще с его помощью можно поднять несколько серверов 1С, но собрать их в кластер не получится.

Это не совсем подходит под описанный мной ранее идеальный конечный результат, поэтому будем делать все самостоятельно.

✏️ Что такое этот ваш чарт?
k8s все объекты внутри себя представляет в виде так называемых манифестов - файлов в формате yml. Эти файлы описывают состояние объектов в кластере. Чтобы создать или изменить объект, нужно применить соответствующий манифест к кластеру. k8s "увидит", что текущее состояние отличается от желаемого и сделает все от него зависящее, чтобы устранить эти расхождения.

k8s состоит из множества разных объектов, под каждый есть свои манифесты. Вот они слева направо:
Pod, ConfigMap, ReplicaSet, Deployment, StatefulSet, Ingress, Service, Namespace, PersistentVolumeClaim, PersistentVolume, Role и тд и тп.

Более-менее сложное приложение обычно состоит из десятков разных манифестов. Чтобы управлять ими было проще, разработчики придумали Helm. По сути, это пакетный менеджер для k8s. Он позволяет "упаковать" все манифесты приложения в одну сущность под названием "чарт", а все параметры этого чарта вынести в отдельный файл. Возможности Helm этим не ограничиваются, но об этом как-нибудь в другой раз.

Итак, для проектирования кластера 1С в Kubernetes нужно разобраться с назначением ключевых объектов k8s, чтобы понять, какие из них подходят для нашего конструктора и как их лучше скомпоновать.

С этого поста начинается рубрика #k8s_101, stay tuned 📻
3👍1🔥1
🎓 Pod, Deployment, StatefulSet

Рубрика #k8s_101 начинается с этих трех объектов.

🧩 Pod
Это самый базовый объект k8s, точнее, это некая абстракция. Именно Pod определяет, какие контейнеры должны быть запущены. Чаще всего в поде один контейнер, но их может быть и несколько. Все поды размещаются на нодах кластера k8s и могут взаимодействовать друг с другом. Практически всегда поды описываются не напрямую, а через другие объекты - Deployment или StatefulSet.

🧩 Deployment
Используется для описания stateless-приложений.

Stateless-приложения - это приложения, которые не сохраняют свое состояние. А экземпляры таких приложений являются взаимозаменяемыми.


Спецификация Deployment описывает шаблон для создания подов и требуемое их количество. Также этот объект реализует различные стратегии обновления и масштабирование.

🧩 StatefulSet
В отличие от stateless, stateful-приложения должны хранить свое состояние. Получается, что каждый экземпляр должен иметь какой-то стабильный идентификатор, который не изменится в случае перезапуска и в случае его переноса на другую ноду. Самый простой пример stateful-приложения - база данных, например, Postgres. Для описания таких приложений используется StatefulSet. Помимо количества экземпляров приложения, в StatefulSet также описываются тома для хранения постоянных данных. Кластер будет сохранять эти тома за теми же подами. Важно понимать, что изначально поды - эфемерные объекты, но в StatefulSet они становятся очень даже "постоянными".

🪄 Перекладываем то, что узнали, на мир 1С
Очевидно, что каждый сервер 1С внутри кластера k8s должен быть отдельным подом. Но что использовать для описания подов - Deployment или StatefulSet? Каким приложением является сервер 1С - stateless или stateful?

🤔 Рассуждаем
На сервере 1С есть каталог кластера, в котором хранятся (как минимум):
• реестр кластера, настройки кластера
• рабочие каталоги ИБ с журналом регистрации, индексом полнотекстового поиска
• сеансовые данные

Потеря любого из этих компонентов приведет к полной / частичной недоступности системы, либо к ошибкам у пользователей.

Еще есть такой момент: центральные серверы назначают для нового соединения рабочий процесс на конкретном сервере. Если в ходе работы пользователя именно этого сервера вдруг не окажется, то пользователь получит ошибку. Значит, серверы 1С в кластере не взаимозаменяемы.

И вдогонку: для добавления сервера 1С в кластер недостаточно просто поднять еще один под, необходимо также выполнить команду rac server insert и настроить на новом сервере требования назначения функциональности.

✏️ Вывод:
Сервер 1С - это stateful-приложение и описывать его надо как StatefulSet.

Завтра очень кратко расскажу про то, как поды в k8s общаются друг с другом \ с внешним миром и как это все подружить с 1С!
32🔥2
🔗 Service, Ingress

Продолжаю рубрику #k8s_101!

Service
Сервисы в Kubernetes нужны в первую очередь для обеспечения сетевого доступа к подам. В глобальном масштабе настройка сетей в Kubernetes состоит из двух больших подзадач: организация сетевого доступа между подами внутри кластера и организация доступа к приложению извне.

🔎 ClusterIP
Поды - вещь эфемерная, поэтому Kubernetes не заботится о том, чтобы у них были стабильные IP-адреса. Сервис типа ClusterIP нужен для того, чтобы у группы подов появился фиксированный внутренний IP-адрес. Этот адрес будет доступен только внутри кластера. Когда него придет запрос, Kubernetes будет знать, каким конкретно подам его направить.

🔎 Headless Service
Этот тип сервиса нужен для того, чтобы наладить обращение к конкретному поду по имени внутри кластера. По сути, этот сервис просто создает специальные DNS-записи внутри кластера. Такой тип сервисов часто используется для stateful-приложений. Это надо запомнить, пригодится!

🔎 NodePort
Сервис типа NodePort открывает указанные порты на каждой ноде кластера. Например, есть кластер Kubernetes из трех узлов. Если создать в нем сервис NodePort с портом 30001, то этот порт будет открыт на всех трех нодах. Запросы по IP-адресу любой ноды и по порту NodePort будут направлены в соответствующие поды. Этот тип сервиса удобен для разработки и отладки, но редко используется в промышленных системах.

🔎 LoadBalancer
Сервис типа LoadBalancer - это один из способов публикации приложения в Kubernetes. Важно понимать, что реализует такой сервис облачный провайдер. То есть да, это объект Kubernetes и манифест для него нужно писать самостоятельно, но где-то в недрах вашего облака реализован специальный контроллер, который определит, что вы добавили LoadBalancer и настроит ваше облако так, чтобы трафик шел "куда надо".

🔎 Ingress (Gateway API)
С Ingress ситуация похожа на LoadBalancer в том плане что эта вещь тоже работает на стороне облачного провайдера. Обычно Ingress обрабатывает HTTP(S) трафик, но многие реализации поддерживают и другие протоколы, например, TCP.
На замену Ingress в свежих версиях Kubernetes пришел Gateway API.

Пост получился довольно большим, поэтому примерять сервисы Kubernetes к кластеру 1С я продолжу завтра!
2🔥21
🕗 В прошлом посте я разобрал базовые компоненты Kubernetes Networking.

Так что там с 1С?
Открываем документацию к платформе. В ней написано, что толстый и тонкий клиент 1С работает с кластером 1С по TCP. Причем, сначала клиент обращается к менеджеру кластера, а менеджер кластера передает клиенту адрес рабочего процесса. Понятнее будет на схеме, см. картинку.

Имеем кластер 1С из двух серверов: srv-1c-01 (центральный) и srv-1c-02 (рабочий). Пользователь заходит в информационную базу Srvr="srv-1c-01";Ref="ERP".
1️⃣ Тонкий клиент подключается к менеджеру сервера (rmngr), порт 1541.
2️⃣ Менеджер сервера регулярно синхронизирует информацию о состоянии всего кластера и знает, где работают рабочие процессы, как они загружены и какого рода нагрузку можно на них подавать.
3️⃣ Менеджер кластера выбирает наиболее подходящий рабочий процесс и отправляет клиенту его адрес в формате сервер:порт.
4️⃣ Тонкий клиент устанавливает соединение с рабочим процессом и начинает работу в информационной базе.

На что надо обратить внимание:
📌 в примере выше центральный сервер направил клиента на другой рабочий сервер, а это значит, что клиент должен иметь возможность подключаться к любому серверу кластера 1С напрямую
📌 имя рабочего сервера, которое выдается клиенту, берется из реестра кластера: клиенту будет выдано именно то имя, которое там указано
📌 когда центральных серверов 1С больше одного, в настройках подключения к базе нужно перечислить все. Тогда клиент 1С будет обращаться сначала к первому, потом ко второму в случае недоступности первого и т.д.

Получается, что для размещения кластера 1С в Kubernetes надо решить две задачи:
1️⃣ каждый сервер 1С, размещенный в кластере Kubernetes и обслуживающий клиентские соединения по TCP, должен быть выставлен наружу Kubernetes
2️⃣ надо сделать так, чтобы клиент, который находится за пределами кластера Kubernetes, мог разрешать DNS-имена серверов 1С в IP-адреса

Решаем первую задачу.
Есть три варианта сделать так, чтобы серверы 1С были выставлены наружу Kubernetes:

🖼️ NodePort
Сервис типа NodePort открывает указанные порты на каждом узле кластера Kubernetes. Это приведет к тому, что в реальных больших кластерах Kubernetes диапазоны портов разных кластеров 1С должны быть очень тщательно спланированы заранее. В противном случае переезд сервера 1С с узла на узел легко может привести к конфликтам. Этот вариант технически приемлем, но сейчас выглядит для меня очень неуклюжим.

🖼️ LoadBalancer
Под каждый сервер 1С надо создать отдельный LoadBalancer. LoadBalancer будет иметь отдельный внешний IP и весь трафик, приходящий на него, будет направлен на конкретный Pod с сервером 1С. Тоже не идеально, но пока что этот вариант мне больше всего по душе.

🖼️ Ingress
ingress-nginx можно настроить так, чтобы TCP-трафик перенаправлялся на определенный Service. Мой опыт использования публичных облаков говорит о том, что Ingress тяжелее, чем остальные варианты. Как минимум, он долго перенастраивается при внесении изменений в конфиг. Это может в будущем стать критичным недостатком, ведь я хочу динамически масштабировать кластер 1С, поэтому перенастройка должна выполняться за секунды, а не за минуты.

Вывод:
Пока что я выбираю реализацию на LoadBalancer, а Ingress оставлю как запасной вариант для TCP и как основной вариант для HTTP(S).

Решение второй задачи будет в следующем посте. Самое время подписаться, потому что shit is getting real 😎
Please open Telegram to view this post
VIEW IN TELEGRAM
3🔥21
Решение второй задачи из прошлого поста.

Напомню:

Надо сделать так, чтобы клиент, который находится за пределами кластера Kubernetes, мог разрешать имена серверов 1С в IP-адреса


Подумал, поприкидывал. Родилась схема, см. картинку.

Очень упрощенно она читается так:
1️⃣ CoreDNS кластера Kubernetes выставляется наружу через отдельный LoadBalancer с 53 портом.
2️⃣ Клиентская машина настраивается так, чтобы определенные зоны резолвились именно через CoreDNS кубера. Тогда клиент при открытии 1С зарезолвит имя сервера во внешний IP LoadBalancer-а.
3️⃣ LoadBalancer направляет запрос к единственному поду за ним - к центральному серверу srv-1c-01, а тот вернет адрес рабочего процесса, например srv-1c-02:1560. Обратите внимание: сервер, где находится рабочий процесс, уже другой! Все, как в реальной жизни.
4️⃣ Клиент точно так же резолвит имя srv-1c-02 во внешний IP другого LoadBalancer-а и устанавливает соединение с рабочим процессом по порту 1560.
5️⃣ Где-то тут нужны будут Headless-сервисы, которые, собственно, и создадут нужные DNS записи в CoreDNS кластера Kubernetes.

На бумаге решение выглядит рабочим, надо пробовать! 🚀
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥3
😺 Какая же серьезная инициатива без отдельной организации на GitHub?

Создал репозиторий, в который буду выкладывать скрипты, манифесты и инструкции.

https://github.com/cloudnative-1c/1c-k8s-lab

Пока что добавил инструкции по подготовке окружения, а уже совсем скоро там появится прототип!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍4
Последние несколько вечеров я занимаюсь выпуском релизов новых версий gitsync-plugins (успешно) и gitsync (пока не очень успешно).

Но мне все равно есть, что показать: как поднять кластер kind и развернуть на нем приложение.

Как полагается, тренироваться надо на кошках hello-world.
Инструкции разместил тут.

В результате у вас будет локальный Kubernetes из одного узла, на нем разворачивается два экземпляра nginx. Наружу он публикуется на localhost:8080 через port forwarding

Обычно во всяких опасных видео на ютубе говорят "не повторяйте это дома", но тут немного другая ситуация, поэтому я говорю: "смело повторяйте это дома!" 😈

Дальше будет поинтереснее: соберем образ сервера 1С и запустим в Kubernetes уже его 🔥
🔥51👍1
🐳 Как обещал, в этот раз будем собирать образ с сервером 1С.

Почему нельзя взять готовый образ, как для nginx? Потому, что nginx распространяется свободно, а платформа 1С - нет. Образы с платформой 1С нельзя публиковать в общем доступе. Кстати, может кто-то и пушит образы в публичные репозитории, но он явно делает это не подумавши.

Правильное решение такое: взять свой логин и пароль от ИТС, клонировать себе проект onec-docker и собрать образ самостоятельно.
Я подготовил детальные инструкции по сборке в своем репозитории, см. тут: 02-1c-docker-image.
Кстати, во время подготовки этого поста мне пришлось доработать скрипты в проекте onec-docker, чтобы образы можно было собирать локально, без Docker Registry.

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

Сразу иду в самый конец server/Dockerfile и вижу это:

# Настройка точки входа и экспонирование портов
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
EXPOSE 1540 1541 1545 1560
CMD ["ragent"]


Что интересно в этом фрагменте:

🔘 ENTRYPOINT устанавливается из файла docker-entrypoint.sh, его рассмотрим далее
🔘 в EXPOSE не перечислены все порты рабочих процессов из стандартного диапазона, но это нужно больше для красоты
🔘 в CMD ["ragent"] означает, что в скрипт docker-entrypoint.sh будет передан параметр "ragent"

Ок, что интересного внутри docker-entrypoint.sh?

🔘 по умолчанию скрипт запускает процессы ragent и ras
🔘 ragent запускается через exec, то есть он станет PID 1. А это значит, что контейнер скорее всего будет корректно обрабатывать сигналы типа SIGTERM. Это очень правильный подход, это мы одобряем.
🔘 ragent и ras запускаются через gosu от имени usr1cv8, что тоже является хорошей морской практикой
🔘 все стандартные параметры запуска ragent и ras устанавливаются по умолчанию, но могут быть переопределены
🔘 в CMD можно вместо параметра "ragent" передать свою команду

Что еще в этом образе:

🔘 сборка состоит из нескольких этапов и финальный образ построен на минималистичном debian:bookworm-slim
🔘 добавлен симлинк /opt/1cv8/current, что *капец* как удобно

В общем, образ мне нравится, огромное спасибо автору - Егору Иванову и всем, кто приложил руку к onec-docker. Да и мне самому тоже, чего уж там 😅

Единственное, что немного смущает: в таком контейнере не соблюдается принцип one service per container, потому что помимо сервера 1С в нем будет работать и ras, который в общем случае можно запустить отдельно. Но этот принцип - это тоже не догма и пока что это все вообще не принципиально. Сейчас игнорируем, но на будущее запомним.

Образ есть, в следующий раз засунем его в... (гусары, молчать!) kind и запустим 😁

PS: параллельно занимаюсь полировкой нового релиза gitsync, версия 3.7.0 уже почти готова.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥31👍1
Всем привет! Продолжаю тащить 1С в кубер 😎

Напомню: я хочу не просто запустить сервер 1С в Kubernetes, а хочу сделать так, чтобы с ним можно было работать из тонкого/толстого клиента снаружи Kubernetes.

Я думал было уместить все в один пост, но материала оказалось много, поэтому сделаю несколько частей. Подпишись, чтобы не пропустить!

Как обычно, все манифесты и скрипты по мере моего продвижения будут выкладывать в этом репозитории. Для сегодняшнего "занятия" материалы уже выложил.

Прокомментирую важные моменты по дизайну решения:

📌 можно запариться и развернуть Docker Registry с HTTPS, а можно просто "загрузить" образ сервера 1С прямо в kind командой kind load docker-image. Я выбрал второе 😅

📌 каждый сервер 1С определяется через отдельный StatefulSet с количеством реплик равным 1

В будущем я хочу делать так, чтобы разные серверы 1С имели разные настройки, как минимум разные ТНФ. Для этого стандартный StatefulSet не подходит: в нем для всех реплик используется единая спецификация. То есть все поды-реплики хоть и будут иметь некую идентичность, настройки у них будут одинаковыми. Получается, в будущем надо будет придумать свой объект для кубера, описывающий сущность типа «группа серверов 1С». Да, такое возможно, но это я сильно вперед забегаю. Пока останавливаюсь на формуле один сервер 1С = один StatefulSet с одной репликой. Кстати, для начала я в кубере разверну не один кластер из двух серверов 1С, а два разных кластера. Но это тоже пока.

📌 сервисы Kubernetes

Помимо манифестов StatefulSet, в cluster1c.yaml есть также манифесты для сервисов двух типов: Headless Service и LoadBalancer.
Первый сервис нужен для взаимодействия с серверами по имени. Второй нужен для того, чтобы опубликовать серверы 1С наружу. См. схему из предыдущего поста. В манифестах сервисов я указал все порты 1С по умолчанию и успел огорчиться от того, что в них нельзя задавать порты диапазонами 😢 Из-за этого манифест превращается в простыню на 600+ строк.

Как сервисы понимают, к каким StatefulSet им надо "присоединиться"? Все просто - по совпадению полей selector, которые указываются и в Service, и в StatefulSet. Там и там они должны совпадать.

📌 использование MetalLB

В моей лаборатории нет настоящего managed-кластера Kubernetes, которым управляет большой облачный провайдер, поэтому приходится решать многие вопросы самостоятельно. Например, выставлять сервисы наружу я буду с помощью собственного балансировщика на базе MetalLB.
В манифесте metallb.yaml я задал два диапазона IP-адресов: один для серверов 1С, другой для DNS. Диапазон для DNS состоит из одного адреса и имеет свойство autoAssign: false. Это нужно для того, чтобы этот адрес не назначался автоматом никуда, а использовался только публикации сервиса DNS.

А вот о настройке CoreDNS + resolvctl и обо всем остальном я расскажу в следующих постах.

Кстати, я совсем забыл: куда же без базы данных? Предлагаю решить голосованием, какой вариант мне поднять - обычный контейнер с Postgres от 1C или сразу сloudnative-pg? Как говорится, чего мелочиться-то?

PS: тем временем релиз gitsync 3.7.0 я наконец-таки выпустил! Ура!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
В прошлом посте и в опросе к нему я как-то на автомате написал "Postgres от 1С", имея в виду "Postgres Pro 1C".
Да, это разные сборки и между ними есть путаница. А ведь есть еще Tantor, Pangolin и Jatoba, но они хотя бы называются сильно по-разному.

Так вот, два самых популярных бесплатных варианта Postgres для 1С:
1️⃣ Сборка "PostgreSQL с патчем от 1С" - Postgres с патчами от фирмы 1С, публикуется на releases.1c.ru
2️⃣ Сборка "Postgres Pro 1С" - Postgres с патчами от Postgres Pro, публикуется на 1c.postgres.ru

Оба варианта официально поддерживаются платформой и оба можно использовать без ограничений, но для своих экспериментов я планировал задействовать вторую, которая "Postgres Pro 1С".

Fun fact: СУБД "Postgres Pro" - это не второе название "Postgres Pro 1С", а вообще отдельный продукт 😳 Он платный, у него есть редакции Standard (Certified), Enterprise (Certified), Enterprise для 1С и еще какие-то. В общем, нейминг для "бесплатных" вариантов получился не очень удачный, мягко говоря.

Опрос показал, что хотим развернуть именно вариант cloudnative-pg (далее - cnpg). Ну что ж, поехали!

cnpg - это оператор для Kubernetes с очень подробной документацией.

🟡Что такое оператор?
Если очень упрощенно, то оператор - это такая программа, которая умеет управлять конкретным приложением и его жизненным циклом в кластере Kubernetes. Это некая прослойка между приложением и внутренним API Kubernetes.

🟡Когда нужны операторы?
Стандартные возможности Kubernetes покрывают условно 99% ситуаций в жизненном цикле самых разных приложений. Однако, есть ряд особенных приложений (или приложений с особенностями 🤤), для которых встроенного API и абстракций Kubernetes недостаточно. Postgres как раз попадает в их число, из-за своей stateful природы а также из-за необходимости кластеризации, репликации, бекапирования и т.д. Угадайте, какая еще платформа подходит под этот профиль? 🤔

Kubernetes API — штука расширяемая, и большая часть операторов добавляет в Kubernetes свои кастомные ресурсы: то есть оператор может работать не только со встроенными объектами типа StatefulSet, Service и т.д., но и добавляет свои виды объектов. Например, cnpg определяет такой объект как ScheduledBackup, с помощью него в cnpg можно декларативно управлять бекапами кластера. В Kubernetes такие определения называются "Custom Resource Definitions" или CRD.

Очень упрощенная аналогия с платформой 1С: представьте, если бы у обычного разработчика 1С была бы возможность создать новый вид объекта метаданных, полностью описать его поведение и взаимодействие с другими механизмами платформы, а затем пользоваться этим объектом наряду со стандартными? Так вот, Kubernetes позволяет делать подобные штуки!

Кстати, помимо cnpg есть и другие операторы Postgres, например, Zalando и Stolon. cnpg вроде как моложе их обоих, но имеет очень богатые возможности и в 2025 году он прямо-таки "выстрелил" в плане популярности 🚀

🟡Установка cnpg
Простейшее развертывание cnpg заключается в установке оператора и применении манифеста вида "Cluster". Да, в кластере Kubernetes мы будем разворачивать кластер Postgres. А потом в кластере Kubernetes развернем и кластер 1С. В этом канале будет еще много про кластер x в кластере Kubernetes, привыкайте 😉

Я дополнил лабу 03-kind-hello-world-1c инструкциями по разворачиванию cnpg.

Из интересного там:
1️⃣ я переопределил стандартный образ cnpg на образ от Егора Иванова, в нем установлена как раз сборка "Postgres Pro 1С".
2️⃣ при подготовке стенда я столкнулся с тем, что cnpg ожидает, что для postgres:postgres UID и GID будут равны 26:26. Пришлось заглянуть в образ Егора, выяснить, что в нем эти значения равны 999:1000 (sic!) и переопределить их в манифесте, в полях spec.postgresUID, spec.postgresUID, а также указать spec.podSecurityContext.fsGroup: 999. Хорошо, что спецификация это позволяет, иначе пришлось бы пересобирать образ и устанавливать пресловутое 26:26 прямо в нем.

Кстати, я не уверен, что образ Егора прокатит для cnpg. Документация cnpg говорит, что официально поддерживаются только их родные образы. Но сейчас кластер инициировался успешно 👀
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥41👍1
🪄 CoreDNS и systemd-resolved

Ух, пришлось сегодня изрядно помучиться и поломать голову насчет DNS.

В чем проблема?
Проблема в том, что центральный сервер 1С выдает клиенту адрес рабочего процесса в формате хост:порт. Чтобы начать работу в информационной базе, клиент должен установить TCP соединение с этим рабочим процессом. Я относительно легко смог сделать так, чтобы клиент, находящийся снаружи кластера Kubernetes, мог зарезолвить имя рабочего сервера в IP-адрес балансировщика.

Для этого я сделал 3 вещи:
1️⃣ прикинул, что в реестре кластера 1С все серверы должны быть зарегистрированы по имени службы, а не по имени хоста, иначе снаружи Kubernetes до них будет не достучаться
2️⃣ ночью чуть-чуть изменил гравитационное поле Земли добавил плагин k8s_external для CoreDNS в своем кластере Kubernetes, выставил сам CoreDNS наружу
3️⃣ настроил systemd-resolved на хосте так, чтобы запросы к зоне cluster.local шли на CoreDNS.

Изи 🤓

Загвоздка тут в том, что серверы кластера 1С будут общаться друг с другом через этот же внешний IP-адрес балансировщика.
Что в этом плохого? Ну, во-первых, скорее всего будут лишние "хопы", соответственно, увеличатся задержки. Во-вторых, некоторые облачные провайдеры тарифицируют балансировщики не только по времени, но и по трафику.

Я думал, призывал на помощь ИИ и экспериментировал, но сделать так называемый Split-DNS в Kubernetes у меня пока не получилось. Split-DNS - это когда одно имя резволвится в один адрес при обращении к нему из одной сети, и в другой адрес при обращении из другой сети.

Однако, я обновил лабу 03-kind-hello-world-1c разделом с настройкой DNS как оно есть сейчас, а задачу по настройке Split-DNS отправил в бэклог.

Как же в тему сейчас этот стикер 👇
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥31👍1
This media is not supported in your browser
VIEW IN TELEGRAM
🤝2😁1
🎉 TA-DAAAA!

Это самое долгожданное сообщение об ошибке лицензирования за всю мою карьеру 😅
В комментарии к этому посту еще выложу скринкаст с демонстрацией.

Помимо очевидного (отсутствия лицензии), это сообщение означает, что сервер 1С размещен в Kubernetes так, что клиент не просто может подключиться к менеджеру кластера 1С извне, но еще и может установить соединение с рабочим процессом, который менеджер кластера выделил для него! 💪

Я сейчас перечитываю абзац выше и понимаю, что это звучит довольно просто. Но повозиться мне с этим пришлось знатно 😮‍💨

В следующих сериях:
📌 расскажу и покажу, как этого удалось достичь
📌 активирую коммюнити-лицензию, чтобы можно было работать с базой по-настоящему
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥71👍1
⚡️Подробности про установку 1С в кластер Kubernetes

Манифесты для серверов 1С у меня уже были подготовлены, поэтому после настройки DNS я просто применил их.
Два сервера 1С получили EXTERNAL-IP из того диапазона, который я ранее определил в metallb.yaml, а имена соответствующих им LoadBalancer-ов успешно резолвились с моего хоста.

Для начала я попробовал создать информационную базу прямо с локальной машины, но столкнулся с тем, что СУБД должна быть с нее доступна 🤯. Я не публиковал ее наружу и не планировал, поэтому пришлось создавать базу изнутри контейнера.

Тут же обнаружилось несколько нюансов, связанных с cloudnative-pg: я взял 1С-совместимый образ, но совершенно забыл, что оператор cloudnative-pg переопределяет ENTRYPOINT. Это привело к двум проблемам:
1️⃣ стандартный пользователь app по-умолчанию является тварью дрожащей учеткой без каких-либо привилегий и не может создавать БД
2️⃣ кластер Postgres инициализировался с локалью en_EN.UTF-8 и с неправильным параметром --lc-collate=C, о чем платформа не постеснялась мне сообщить в консоли

Поэтому я почитал доку к cloudnative-pg (давно пора 😅) и немного дополнил манифест кластера Postgres в файле cnpg.yaml.

> ВАЖНО! Применение обновленного манифеста поверх имеющегося кластера вызовет его аварийную остановку. Поэтому лучше снести кластер и его PVC, а затем задеплоить по-новой.


Кстати, пароль от учётной записи app задаётся в типичном для Kubernetes стиле - с использованием секретов (Secrets).

После всего этого база 1С создалась и я добавил ее в список баз на локальной машине, причем сервер 1С я указал как server1c-01-lb.default.cluster.local. Но при запуске в режиме конфигуратора меня ждала подстава в виде ошибки:

Временный сбой в разрешении имен: server1c-01-0 и тд и тп


Откуда server1c-01-0?
Дело в том, что менеджер кластера передает клиенту адрес рабочего процесса с тем именем сервера 1С, которое указано в реестре кластера. А какое имя указано в реестре кластера? Правильно - имя хоста, то есть пода, то есть server1c-01-0. А моя локальная машина ничего не знает об именах подов в Kubernetes, да и не должна знать. Выходит, нужно сделать так, чтобы платформа возвращала имя сервиса с типом LoadBalancer.

Я попробовал удалить кластер и создать его заново с помощью rac с правильным именем хоста, в моем случае это server1c-01-lb.default.cluster.local. Но rac выдал ошибку:

Ошибка операции администрирования
Local host parameters are not found
command terminated with exit code 255


Похоже, в платформе есть какая-то проверка на то, что создание кластера должно выполняться именно на localhost.

Как заставить систему думать, что некое имя ресурса это localhost? Самый простой способ - с помощью /etc/hosts!
А в шаблоне пода в StatefulSet для этого есть даже специальный параметр:

...
spec:
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "server1c-02-lb.default.cluster.local"
...


И это даже нельзя считать грязным хаком. Помните, в одном из прошлых постов я хотел, чтобы внутренний трафик ходил напрямую, а не через LoadBalancer? Короче, одним выстрелом двух зайцев, по крайней мере в рамках одного сервера 1С это будет работать. Получается, что Headless-сервисы пока мне не нужны.

Как обычно, дополнил и скорректировал лабу 03-kind-hello-world-1c.

Итогов года не будет, потому что канал я создал только в конце ноября. Но зато планы на 2026 год у меня большие! Перечислю несколько интересных задач:
🔸 активировать коммьюнити-лицензию на моем стенде
🔸 по-честному объединить несколько серверов 1С в кластер
🔸 добыть найти несколько серверных лицензий уровня КОРП для экспериментов
🔸 попробовать написать свой оператор для 1С (потихоньку уже изучаю go 😎)
🔸 проработать observability кластера: сбор метрик, ТЖ

Всех с наступающим! 🎄
Спасибо, что следите за моим каналом!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍21
По многочисленным 😅 просьбам комментаторов в предыдущем посте, напишу, что у меня было самого интересного в 2025 году в профессиональном плане:

🔸 с начала года я стал членом программного комитета конференции по 1С от Онтико. Онтико организуют HighLoad++ и кучу других топовых не 1С-ных конференций. Конференция по 1С пока не состоялась, но опыт был интересный.
🔸 в марте выступил в Клубе Питерских Одинэсников с докладом про веб-сервисы и автономный сервер, запись вот тут.
🔸 весь год тащил на основной работе два проекта: первый - это перевод двух больших самописных конфигураций на Linux и Postgres, второй - разработка универсального CI/CD для 1С на базе GitLab. Плюс к этому была куча других задач по производительности и стабильности, ну и пресейлы, куда уж без них.
🔸 стал мейнтейнером одного из самых популярных проектов на OneScript - gitsync, заодно и gitsync-plugins. Перевел тестирование на Github Actions, исправил баги и выпустил по новому релизу и там, и там.
🔸 сдал экзамен "1С:Эксперт по технологическим вопросам"! Сертификат оказался с "выдержкой", ведь первая попытка сдачи была аж в 2015 году! 😳
🔸 в ходе подготовки к Эксперту наконец-то проникся ведением базы знаний в Obsidian. Без нее сдать экзамен было бы в разы сложнее! Теперь использую его для других задач, в том числе на своих проектах.
🔸 создал канал cloudnative-1c 🎉
🔸 дотянул до релиза свой очень старый PR в bsl-language-server.
🔸 прямо под елочку, 26 декабря, стал Decorated Certified DevOps Engineer по продукту VK Tax Compliance. Этот продукт состоит из 50+ микросервисов и разворачивается в кубере с помощью Terraform и ArgoCD.

Спасибо всем, с кем довелось поработать в 2025 году! Увидимся в 2026-ом! 💪
Please open Telegram to view this post
VIEW IN TELEGRAM
1🎉7👍43🤩1
👋 Всем привет!

Потихоньку вливаемся в рабочий режим!
На каникулах мне пришлось организовать переезд моей лаборатории. Я арендовал сервер на hostkey, все развернул по-новой и дошел до активации лицензии. Кстати, я шел по своим же шагам из лабораторных, поэтому заодно проверил их воспроизводимость.

Как водится, с активацией комьюнити-лицензий 1С не все просто. Загвоздка в том, что эта лицензия активируется строго интерактивно. Причем, если нужно активировать ее для сервера, то это надо делать на самом сервере, то есть, прямо в поде.

🤓 Вообще, правильно говорить не "в поде", а "в контейнере", но в моем случае без разницы, потому что в моем поде строго один контейнер.


Получается такой набор действий:
1️⃣ установить и запустить графический интерфейс + VNC-сервер в поде
2️⃣ открыть в поде стартовое окно 1С с выводом на дисплей
3️⃣ подключиться к поду по VNC
4️⃣ интерактивно добавить новую файловую ИБ
5️⃣ при попытке открытия этой ИБ откроется окно с выбором\активацией лицензий

После активации комьюнити-лицензии в поде должен появиться файл /var/1C/licenses/202601*.lic. Эта лицензия позволяет работать серверу 1С и еще четырем сеансам.
Кстати, количество комьюнити-лицензий на один аккаунт ограничено, поэтому заодно я расширил спецификацию кластера 1С объектами Persistent Volume и Persistent Volume Claim. Без них любое пересоздание пода приводило бы к потере файла с лицензией. А нам такое не надо.

Мой коллега Олег подсказал мне пару ссылок на ИТС с документацией по фрешу, где есть почти все нужные команды для установки GUI + VNC.
Единственное, что ставить systemd в моем поде - это очень-очень большой overkill, поэтому запускать графический интерфейс и VNC я буду вручную.

Как водится, я обновил лабу 03-kind-hello-world-1c. Офигеть, какой развесистый hello-world получается!

Что получилось в итоге:
Если открыть графический интерфейс в поде и добавить в список баз клиент-серверную ИБ, созданную ранее, то база открывается, а в окне информации отображается полученная ранее комьюнити-лицензия (см. картинку). То есть, с сервера 1С все работает, но это не совсем то, что мне было нужно.
Если открыть ту же базу с другого хоста, то сервер 1С лицензию почему-то не выдает.

Почему? Там довольно интересная ситуация, мне пришлось даже пообщаться с поддержкой 1С. Обходной путь я нашел, но надеюсь, что у меня получится разобраться с этой проблемой как полагается. Об этом расскажу в следующих постах! 😅
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍5🙏3
Продолжаю переписываться с поддержкой 1С по поводу того, что сервер не выдает клиенту комьюнити-лицензию, если клиент расположен на другой машине. Выясняю все методично и дотошно, спасибо им большое за терпение 🙏

А сегодня с утра в рассылке OpenYellow обнаружил занятный проект onec-community-docker. В нем максимально автоматизировано получение и продление комьюнити-лицензий на сервере и на клиенте 1С внутри докер-контейнеров.
Связался с автором. Оказалось, что Александр вообще только осваивает разработку в 1С и сделал этот проект для погружения в предметную область. Мое почтение! 💪 Накидайте ему, пожалуйста, звездюлей звезд на гитхабе!
Конечно, я сразу захотел портировать эти наработки в onec-docker.

Александр мне скинул ссылки на публикации и обсуждения на Infostart, где утверждается, что сервер 1С с активированной комьюнити-лицензией не раздает эти лицензии клиентам, даже если флажок "Разрешать выдачу лицензий сервером 1С:Предприятия" установлен (см. также --license-distribution=allow).
Обидно. Досадно. Но ладно ничего не поделаешь: придется активировать две лицензии - одну на сервере, одну на клиенте.
Кстати, это тот самый "способ обхода", про который я говорил в прошлом посте. Получается, что никакой это не обход, а штатное поведение.

А теперь про другой интересный нюанс. Когда моя лаборатория переехала на новый абсолютно чистый VPS-сервер, то при подключении с этого хоста к серверу 1С в поде Kubernetes я внезапно стал получать такую ошибку:

Сервер 1С:Предприятия использует лицензию для разработчиков. Запуск клиентского приложения Конфигуратор с лицензией ПРОФ и КОРП запрещен. Обратитесь ...


WTF???
Оказалось, что с этого сервера мне стали доступны чьи-то чужие клиентские лицензии, аж 300 штук. Клиент 1С использовал их, а потом выдавал ошибку, потому что комьюнити-лицензии нельзя смешивать с обычными лицензиями (кроме строго одного случая).
Кстати, поддержка 1C сообщила, что до 8.3.24 это ограничение было только на бумаге, а в последующих версиях оно уже реализовано на уровне платформы.
А проблема решилась запретом на использование аппаратных лицензий.

Такие дела!

В следующий раз буду ручками собирать настоящий кластер 1С из двух серверов. Ожидаю, что после этого будет более-менее понятно, что должен уметь делать minimum viable оператор для 1С и какими ресурсами он должен управлять. О том, что такое операторы в Kubernetes я писал тут.

🏆 Мини-викторина: в каком случае разрешено совместное использование обычных лицензий и комьюнити-лицензий?
Пишите ваши варианты в комментариях, победителю поставлю красивую звездочку ⭐️
Только чур никуда не подглядывать!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍74🙏1