On-Premises Helm
Пошагово здесь: https://elma365.com/ru/help/install-kubernetes.html
- Pods
- Полезное
- Перезапуск всех сервисов
- Установка порта отличного от 80
- Проверка статуса узлов кластера
- Переход на Cilium Gateway
- Переход на Cilium Gateway (Hub)
- Ошибка при вызове Web API
- Проблемы
- Hub
Pods
Удалить evicted pods
kubectl get po -A --all-namespaces -o json | jq '.items[] | select(.status.reason!=null) | select(.status.reason | contains("Evicted")) | "kubectl delete po \(.metadata.name) -n \(.metadata.namespace)"' | xargs -n 1 bash -c
Предварительно должен быть установлен jq
Полезное
Перезапуск всех сервисов
kubectl -n default rollout restart deploy
kubectl -n default rollout restart ds
Если namespace отличен от по умолчанию, заменить default на свой
Более интересный вариант:
#!/usr/bin/env bash
function clearCompleted() {
kubectl delete job $(kubectl get job -o=jsonpath='{.items[?(@.status.succeeded==1)].metadata.name}') > /dev/null 2>&1
}
kubectl scale deploy --replicas=0 --all
while [[ $(kubectl get pods -n default | grep -c "") -ne 0 ]]
do
clearCompleted
echo "Waiting for all pods are Terminating."
sleep 15
done
kubectl scale deploy --replicas=1 --all
kubectl scale --replicas=4 deployment/worker
while true
do
clearCompleted
echo "Waiting for all pods are Ready."
kubectl wait pods --all -n default --for condition=Ready --timeout=60s > /dev/null 2>&1 && break
sleep 15
done
echo "All done."
Установка порта отличного от 80
tar -xzf elma365.tar.gz elma365
sed -i -e 's/: 80/: 88/g' elma365/charts/front/templates/ingress.yaml
Проверка статуса узлов кластера
etcdctl --cluster=true endpoint health
Переход на Cilium Gateway
Не решен вопрос с CORS
Перед переходом на Cilium Gateway необходимо выполнить шаги, описанные тут. Здесь мы рассмотрим вариант для single node редакция Enterprise версия 2026.4.42. Для редакции Hub все намного сложнее и будет описано позже.
Из справки тут создаем gateway:
kubectl apply -n kube-system -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: cilium-gateway
spec:
gatewayClassName: cilium
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- name: elma365-tls
allowedRoutes:
namespaces:
from: All
EOF
Нам не нужен 443, т.к. у нас используется reverse proxy, который выполняет все нужные активности в части HTTPS
Поэтому в упрощенному случае у нас будет:
kubectl apply -n kube-system -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: cilium-gateway
spec:
gatewayClassName: cilium
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
EOF
Должны получить:
gateway.gateway.networking.k8s.io/cilium-gateway created
Смотрим что на самом деле:
kubectl get gateway -A
Видим, что появился gateway:
NAMESPACE NAME CLASS ADDRESS PROGRAMMED AGE
kube-system cilium-gateway cilium True 71s
Смотрим что у нас с сервисами:
kubectl get svc -n kube-system
Видим что появился LoadBalancer, но он еще не настроен (а еще какой то новый сервис hubble-peer):
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cilium-gateway-cilium-gateway LoadBalancer 10.152.183.225 <pending> 80:30514/TCP 4m13s
ck-storage-rawfile-csi-controller ClusterIP None <none> <none> 189d
ck-storage-rawfile-csi-node ClusterIP 10.152.183.56 <none> 9100/TCP 189d
coredns ClusterIP 10.152.183.238 <none> 53/UDP,53/TCP 189d
hubble-peer ClusterIP 10.152.183.166 <none> 443/TCP 189d
metrics-server ClusterIP 10.152.183.180 <none> 443/TCP 189d
Возможно можно как то настроить NodePort для ситуации single node, но эту гипотезу мы тут не проверяем.
Так же load-balancer отключен по k8s status - его нужно включить:
k8s enable load-balancer
Должны получить:
Enabling load-balancer on the cluster. This may take a few seconds, please wait.
load-balancer enabled.
# k8s status
cluster status: ready
control plane nodes: 192.168.56.83:6400 (voter)
high availability: no
datastore: etcd
network: enabled
dns: enabled at 10.152.183.238
ingress: disabled
load-balancer: enabled, L2 mode
local-storage: enabled at /var/snap/k8s/common/rawfile-storage
gateway enabled
# kubectl get pod,svc -n metallb-system
NAME READY STATUS RESTARTS AGE
pod/metallb-controller-676c8f595c-5chlt 1/1 Running 0 2m6s
pod/metallb-speaker-t2x96 1/1 Running 0 2m6s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/metallb-webhook-service ClusterIP 10.152.183.39 <none> 443/TCP 2m7s
Неоходимо для нашего LoadBalancer назначить пул IP адресов (в нашем случае у нас single node и поэтому укажем только один):
Использовать IP нашего узла НЕЛЬЗЯ. Необходимо указать свободный адрес в вашей сети. (а может и можно)!
k8s set load-balancer.cidrs=192.168.56.73-192.168.56.73
Получилось:
Configuration updated.
# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cilium-gateway-cilium-gateway LoadBalancer 10.152.183.225 192.168.56.73 80:30514/TCP 86m
ck-storage-rawfile-csi-controller ClusterIP None <none> <none> 189d
ck-storage-rawfile-csi-node ClusterIP 10.152.183.56 <none> 9100/TCP 189d
coredns ClusterIP 10.152.183.238 <none> 53/UDP,53/TCP 189d
hubble-peer ClusterIP 10.152.183.166 <none> 443/TCP 189d
metrics-server ClusterIP 10.152.183.180 <none> 443/TCP 189d
Теперь переходим непосредственно к настройке ELMA365. Правим наш values-elma365.yaml. Отключаем Ingress и включаем Gateway API:
global:
gatewayAPI:
enabled: true
parentRefs:
- name: cilium-gateway
namespace: kube-system
ingress:
enabled: false
Устанавливаем (обновляем) чарт ELMA365 как это мы делаем стандартно (у каждого свой подход), но суть - применить наши изменения.
И тут начались танцы с бубном....
helm upgrade --install elma365 ./elma365 -f values-elma365.yaml --timeout=30m --debug --wait
Получили (причем тут istio вообще?):
level=DEBUG msg="number of dependencies in the chart" chart=messenger-vkteamsbot dependencies=0
level=DEBUG msg="number of dependencies in the chart" chart=messenger-whatsapp dependencies=0
level=DEBUG msg="number of dependencies in the chart" chart=postman dependencies=0
Error: unable to build kubernetes objects from release manifest: [resource mapping not found for name: "balancer-auth" namespace: "" from "": no matches for kind "AuthorizationPolicy" in version "security.istio.io/v1"
ensure CRDs are installed first, resource mapping not found for name: "main-body-size-limit" namespace: "istio-system" from "": no matches for kind "EnvoyFilter" in version "networking.istio.io/v1alpha3"
ensure CRDs are installed first]
Изучив ~/elma365/charts/balancer/values.yaml было обнаружено интересное значение workloadSelector, про которое ничего не сказано в оффициальной справке:
global:
gatewayAPI:
enabled: false
parentRefs:
- name: main-gateway
namespace: istio-system
workloadSelector:
gateway.istio.io/managed: istio.io-gateway-controller
annotations: {}
hosts: []
Заменили значение на
Смотрим ~/elma365/charts/balancer/templates/httproute.yaml а там захаркодено если включен gatewayAPI:
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: {{ template "balancer.name" . }}-auth
labels:
{{- include "balancer.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
app: {{ template "balancer.name" . }}
action: DENY
rules:
- to:
- operation:
ports: ["{{ $servicePort }}"]
paths: ["/balancer*"]
when:
- key: request.headers[authorization]
values: ["*"]
Пробуем удалить (далее сделаем патч к дистрибутиву и пробуем установить снова ELMA365 - эта проблема ушла но осталась вторая:
level=DEBUG msg="number of dependencies in the chart" chart=textextractor dependencies=0
level=DEBUG msg="number of dependencies in the chart" chart=widget dependencies=0
Error: unable to build kubernetes objects from release manifest: resource mapping not found for name: "main-body-size-limit" namespace: "istio-system" from "": no matches for kind "EnvoyFilter" in version "networking.istio.io/v1alpha3"
ensure CRDs are installed first
Пробуем добавить отключение envoyFilter в нашей конфигурации, ведь мы никакой Envoy не устанавливали:
gatewayAPI:
enabled: true
# annotations: {}
parentRefs:
- name: cilium-gateway
namespace: kube-system
# timeoutSeconds: "300s"
# retries:
# attempts: 3
envoyFilter:
enabled: false
# namespace: "istio-system"
Установка пошла дальше! Ура! Ждем результат...
Все поднялось без ошибок. Смотрим какие у нас появились ресурсы HTTPRoute:
kubectl get httproute -A
Получили что то похожее:
NAMESPACE NAME HOSTNAMES AGE
default balancer ["d.rmg365.ru"] 9m33s
default fileprotection ["d.rmg365.ru"] 9m33s
default front ["d.rmg365.ru"] 9m33s
default hydra-adaptor ["d.rmg365.ru"] 9m33s
default main ["d.rmg365.ru"] 9m33s
default main-publicapi ["d.rmg365.ru"] 9m33s
default notifier ["d.rmg365.ru"] 9m33s
default notigate ["d.rmg365.ru"] 9m33s
default vahter ["d.rmg365.ru"] 9m33s
default web-forms ["d.rmg365.ru"] 9m33s
Перенастроили reverse proxy на наш новый адрес, что мы указали ранее для LB и вуаля:
Давайте попробуем все же обмануть LB и указать ему адрес хоста, чтобы не плодить у себя айпишники:
k8s set load-balancer.cidrs=192.168.56.83-192.168.56.83
Вроде не ругнулось даже:
Configuration updated.
# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cilium-gateway-cilium-gateway LoadBalancer 10.152.183.225 192.168.56.83 80:30514/TCP 158m
ck-storage-rawfile-csi-controller ClusterIP None <none> <none> 190d
ck-storage-rawfile-csi-node ClusterIP 10.152.183.56 <none> 9100/TCP 190d
coredns ClusterIP 10.152.183.238 <none> 53/UDP,53/TCP 190d
hubble-peer ClusterIP 10.152.183.166 <none> 443/TCP 190d
metrics-server ClusterIP 10.152.183.180 <none> 443/TCP 190d
Эксперимент прошел удачно и мы вернули настройки reverse proxy как было в случае Ingress.
Ну вот собственно и патч для 2026.4 (актуально для 2026.4.42, покка не исплавили) - balancer-httproute.patch.2026.4
--- elma365/charts/balancer/templates/httproute.yaml 2026-07-31 09:06:50.000000000 +0300
+++ ./httproute.yaml 2026-08-02 14:13:28.294230220 +0300
@@ -43,24 +43,4 @@
- name: {{ $serviceName }}
port: {{ $servicePort }}
{{- end }}
----
-apiVersion: security.istio.io/v1
-kind: AuthorizationPolicy
-metadata:
- name: {{ template "balancer.name" . }}-auth
- labels:
- {{- include "balancer.labels" . | nindent 4 }}
-spec:
- selector:
- matchLabels:
- app: {{ template "balancer.name" . }}
- action: DENY
- rules:
- - to:
- - operation:
- ports: ["{{ $servicePort }}"]
- paths: ["/balancer*"]
- when:
- - key: request.headers[authorization]
- values: ["*"]
{{- end }}
После загрузки нового дистро применяем патч:
patch elma365/charts/balancer/templates/httproute.yaml < balancer-httproute.patch.2026.4
Переход на Cilium Gateway (Hub)
Статья в разработке. Ищем пути поднятия системы
Ранее мы рассмотрели переход для редакции Enterprise для single node. А теперь рассмотрим редакцию Hub на 4х узлах кластера.
Итак мы имеем кластер следующего вида:
# k8s status
cluster status: ready
control plane nodes: 192.168.56.151:6400 (voter), 192.168.56.152:6400 (voter), 192.168.56.153:6400 (voter)
high availability: yes
datastore: etcd
network: enabled
dns: enabled at 10.152.183.211
ingress: disabled
load-balancer: enabled, L2 mode
local-storage: enabled at /var/snap/k8s/common/rawfile-storage
gateway enabled
# kubectl get nodes -A -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
hc1n1 Ready control-plane,worker 189d v1.33.11 192.168.56.151 <none> Ubuntu 24.04.4 LTS 6.17.13-19-pve containerd://1.7.31
hc1n2 Ready control-plane,worker 189d v1.33.11 192.168.56.152 <none> Ubuntu 24.04.4 LTS 6.17.13-19-pve containerd://1.7.31
hc1n3 Ready control-plane,worker 136d v1.33.11 192.168.56.153 <none> Ubuntu 24.04.4 LTS 6.17.13-19-pve containerd://1.7.31
hc1n4 Ready worker 186d v1.33.11 192.168.56.154 <none> Ubuntu 24.04.4 LTS 7.0.14-5-pve containerd://1.7.31
При этом как видно у нас уже включен load-balancer, т.к. у нас ранее установлен portainer в LB варианте:
portainer service/portainer-agent LoadBalancer 10.152.183.27 192.168.56.170 9001:31417/TCP 186d
portainer service/portainer-agent-headless ClusterIP None <none> <none> 186d
Создаем gateway из прошлой статьи. У нас подцепился нужный IP из преднастроенного пула:
kube-system cilium-gateway-cilium-gateway LoadBalancer 10.152.183.249 192.168.56.171 80:31186/TCP 15s
Применяем патч и обновляет ELMA365:
helm upgrade --install elma365 ./elma365 -f values-elma365.yaml --timeout=30m --debug --wait
И вот больше нет доступа к нашим ресурсам. Смотрим что там у нас с HTTPRoute:
# kubectl get httproute -A
NAMESPACE NAME HOSTNAMES AGE
default balancer ["hc1.rmg365.ru"] 11m
default fileprotection ["hc1.rmg365.ru"] 11m
default front ["hc1.rmg365.ru"] 11m
default hydra-adaptor ["hc1.rmg365.ru"] 11m
default linkhub ["hc1.rmg365.ru"] 11m
default main ["hc1.rmg365.ru"] 11m
default main-publicapi ["hc1.rmg365.ru"] 11m
default notifier ["hc1.rmg365.ru"] 11m
default notigate ["hc1.rmg365.ru"] 11m
default vahter ["hc1.rmg365.ru"] 11m
default web-forms ["hc1.rmg365.ru"] 11m
Возвращаемся к танцам с бубном касательно тенантов - это периодическим еняется от версии к версии...
... в процессе написания
Ошибка при вызове Web API
После обновления на релиз 2026.1 вариант Helm может перестать работать Web API. Чтобы решить эту проблему необходимо проверить наличие в values-elma365.yaml записи ingressClassName и если ее нет то добавить:
# домен или ip адрес, по которому будет доступна система
# host: 'host.randm.ru'
host: 'host.rmg365.ru'
ingress:
# включение host в ingress (значение берется из host)
# для установленного s3 minio через чарты elma365-extensions, укажите в блоке minio
# значение в параметре hosts в файле values-extensions.yaml
ingressClassName: nginx
До версии 2026.1 этого не требовалось
Проблемы
Error: Kubernetes cluster unreachable: Get https://127.0.0.1:16443
После обновления сертификатов в кубике возможна неработоспособность helm - появляется ошибка или с неверным сертификатом или что то с портом.
Необходимо обновить файл конфигурации кубика:
microk8s.kubectl config view --raw > $HOME/.kube/config
После этого helm должен ожить.
Hub
2025.8.6+: Доступ к площадкам
Начиная с данной версии вырезано в Ingress прописывание тенантов и как следствие система перестала работать как надо.
Чтобы это вылечить, необходимо:
в values-elma365.yaml указать:
global:
host: 'myhubdomain.ru'
ingress:
hostEnabled: false
В реверс прокси для каждого адреса тенанта добавить в хидер:
X-Company <tenant>
где, <tenant> для конкретного названия, которое будет добавлено к полному имени <tenant>.myhubdomain.ru
edition: hub (solution: hub на текущий момент в природе не существует )
секцию hub прописываем как и раньше для каждого тенанта
если надо включить фишки хаб сервисов, то hubEnabled: true
2026.1-2026.3: Не создаются площадки
Начиная с указанной версии перестали создаваться и обновляться площадки. Это связано с некорректным значением в чарте дистрибутива. Для устранения данной проблемы необходимо создать следующий патч create-company.patch:
--- elma365/templates/create-company.yaml 2026-04-10 11:06:27.000000000 +0300
+++ ./create-company.yaml 2026-04-08 08:20:01.000000000 +0300
@@ -1,4 +1,5 @@
{{- if eq .Values.global.solution "onPremise" }}
+{{- if or (eq .Values.global.edition "standard") (eq .Values.global.edition "enterprise") }}
apiVersion: batch/v1
kind: Job
metadata:
@@ -57,7 +58,7 @@
activeDeadlineSeconds: {{ default 1800 .Values.global.activeDeadlineSeconds }}
ttlSecondsAfterFinished: 120
-{{- else if eq .Values.global.solution "hub" }}
+{{- else if eq .Values.global.edition "hub" }}
{{- range $index, $job := .Values.global.hub }}
---
@@ -206,3 +201,4 @@
data: {}
{{- end }}
+{{- end }}
После чего применить его:
patch -u elma365/templates/create-company.yaml < create-company.patch
rm -f elma365/templates/create-company.yaml.orig
2026.4+: Не создаются площадки
Начиная с указанной версии перестали создаваться и обновляться площадки. Это связано с некорректным значением в чарте дистрибутива. Для устранения данной проблемы необходимо создать следующий патч create-company.patch:
--- elma365/templates/create-company.yaml 2026-05-14 14:35:38.000000000 +0300
+++ ./create-company.yaml 2026-05-17 09:53:59.345172000 +0300
@@ -1,4 +1,5 @@
{{- if eq .Values.global.solution "onPremise" }}
+{{- if or (eq .Values.global.edition "standard") (eq .Values.global.edition "enterprise") }}
apiVersion: batch/v1
kind: Job
metadata:
@@ -64,7 +65,7 @@
activeDeadlineSeconds: {{ default 1800 .Values.global.activeDeadlineSeconds }}
ttlSecondsAfterFinished: 120
-{{- else if eq .Values.global.solution "hub" }}
+{{- else if eq .Values.global.edition "hub" }}
{{- range $index, $job := .Values.global.hub }}
---
@@ -83,9 +84,6 @@
template:
metadata:
labels:
- {{- if .Values.global.helmLibrary }}
- {{- include "helm-library.deployment.podLabels" . | nindent 8 }}
- {{- end }}
app: hub
tier: elma365
sidecar.istio.io/inject: "false"
@@ -208,3 +206,4 @@
data: {}
{{- end }}
+{{- end }}
После чего применить его:
patch -u elma365/templates/create-company.yaml < create-company.patch