Переход на 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


Версия #11
Вербовик Максим Арнольдович создал 2026-08-02 12:00:23 MSK
Вербовик Максим Арнольдович обновил 2026-08-03 11:54:32 MSK