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

@ovcharenko_di
Download Telegram
🐘 Зачем это все?

Не буду игнорировать слона в комнате, отвечу на самый очевидный вопрос:

Зачем тащить 1С в k8s? Платформа же для этого не предназначена!


Я тоже считал, что она не предназначена. Не так давно я даже сам лично отговаривал от таких идей коллег и заказчиков.
Поворотный момент случился, когда я познакомился с проектом cloudnative-pg, а чуть позже — со Strimzi. Это два open source проекта, предназначенные для разворачивания в Kubernetes кластеров Postgres и Kafka и управления ими. То есть некий коллектив разработчиков сделал то, что считается невозможным, нерациональным или идеологически неверным: им удалось затащить stateful-приложения в кластер k8s и сделать их там объектами первого класса! А ведь помимо Postgres и Kafka что только сейчас не разворачивают в k8s.

Чем 1С хуже? Какие особенности платформы не позволят сделать то же самое? Похоже, что никаких ограничений нет, всё реализуемо. Действительно, платформа не создавалась в парадигме cloudnative, но ведь и Postgres, и Kafka — тоже.

Вот с такими мыслями и установками я решил начать работу в этом направлении.
🤓3👏2🔥1
Идеальный конечный результат

⚠️ Если терминология и концепции звучат незнакомо - не переживайте и скорее подписывайтесь, потому что в следующих постах я шаг за шагом всё разъясню.


В первом посте я привел примеры операций, которые предстоит реализовать через манифесты и kubectl.
Здесь расскажу чуть подробнее о своем видении. Включайте воображение:

Имеем кластер k8s на несколько узлов, в котором установлен ArgoCD и какой-нибудь observability-стек типа VictoriaMetrics. В ArgoCD добавлено приложение (Application), желаемая конфигурация которого находится в определенной ветке репозитория GitLab. Репозиторий хранит заготовку нашего кластера 1C в виде yaml-манифестов или helm-чарта. Прямо в репозитории мы указываем параметры нашего кластера: количество центральных и рабочих серверов, ТНФ, подключаем сервер лицензирования, подсовываем конфиг для техжурнала. Мы коммитим и пушим наши изменения в репозиторий. ArgoCD определяет, что приложение рассинхронизировано с веткой, получает новые версии манифестов и начинает их применять в кластере. Что при этом происходит:
• поднимаются поды с контейнерами, в которых работают серверы 1С
• стартуют сервисы k8s (LoadBalancer, ClusterIP), поды подключаются к сервисам k8s
• некоторые сервисы k8s публикуются "наружу"
• из серверов 1С собирается кластер, на них настраиваются ТНФ, активируются лицензии
• подключаются экспортеры для техжурнала

Вуаля! Кластер работоспособен, а вы - великолепны. Можно создавать информационные базы и работать. Причем, любые изменения в конфигурации кластера 1С в дальнейшем выполняются точно так же, через git. А там, где git, там и версионирование, а там, где версионирование, там и контроль, и возможность откатить действие. К слову, этот подход называется GitOps.

📈 Наиболее смелая идея - это сделать так, чтобы кластер 1С мог автомасштабироваться в зависимости от нагрузки. Представьте, что когда в нашу ИБ зайдет еще 500 пользователей, то кубер автоматически создаст новый сервер 1С и подключит его к кластеру. А когда нагрузка снизится, то сервер будет удален. How cool is that? 😎

Я еще не решил, нужно ли делать так, чтобы сущность "Информационная база" тоже была объектом первого класса в k8s. Пока думаю, что нет, но в том же Strimzi из предыдущего поста даже такие штуки как Kafka Topic можно создавать с помощью отдельного манифеста. В общем, я буду рад услышать ваши соображения на этот счет.

Кстати, пишите мне пожелания, о чем надо рассказать подробнее. Особенно если ни*его не понял, но очень интересно 😁
😁2
🥼🧪 Обустраиваем лабу

Мне нужно определить место для экспериментов. Я уже выбрал один вариант - kind (или KinD, то есть "Kubernetes in Docker"). Это проект с открытым исходным кодом, который позволяет развернуть полноценный кластер k8s в докере на вашей локальной машине. Каждая нода кластера - это отдельный контейнер. Есть и другие альтернативы: minikube, k3s. В конце концов, можно арендовать минималистичный кластер у одного из облачных провайдеров, но это стоит реальных денег. У меня был опыт с minikube, но он как будто "тяжелее", чем kind. Пока что kind мне показался самым разумным вариантом: он прост в освоении и при этом очень похож на настоящий k8s. Его будет достаточно, чтобы работать в режиме "на коленке" первое время, а дальше посмотрим.

У меня есть подходящая под мои задачи машина с Ubuntu Server 22.04, само собой, без графического интерфейса. Она и будет моим НИИ на первое время. Однако, мне предстоит редактировать много развесистых yaml-ов, поэтому очень важно иметь удобный редактор, например VS Code. Причем, VS Code я буду открывать локально, а уже в нем по ssh я буду работать файлами и консолью удаленного сервера. Лепота!

Так, kind создаст нам кластер k8s, но мне этим кластером еще нужно будет управлять. Для этого потребуется kubectl.
На моей "лабораторной" машине уже есть docker, поэтому ставить я буду только kind и kubectl. Установка обоих инструментов заключается, по сути, в скачивании двух бинарников. Лепота №2! Очень люблю за такое проекты, написанные на go.

Как заведено, прежде чем делать что-либо свое, разумно будет развернуть "hello-world". Для kind - это создать кластер с конфигом по умолчанию, задеплоить какой-нибудь стандартный nginx и потыкать в него палочкой браузером или curl-ом.
Расписывать это здесь не буду, задача тривиальная.

Так, совсем забыл про СУБД! Я ее, пожалуй, разверну потом в отдельном контейнере. Кстати, можно вообще попробовать облачно-нативный вариант из одного из прошлых постов, чтобы вообще весь наш контур управлялся кубером.

Лаба более менее обустроена, завтра начинаем варить, ага 😎 думать над тем, как засунуть 1С в k8s 🤓
3
Когда всего месяц назад пересматривал 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