Полезное

Перезапуск всех сервисов

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 и вуаля:

image.png

Давайте попробуем все же обмануть 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

Возвращаемся к танцам с бубном касательно тенантов - это периодическим еняется от версии к версии...

... в процессе написания