APISIX как ingress в Kubernetes: глобальные правила, TLS и OpenTelemetry
Published: 2026-02-22
APISIX заменил Traefik во всех шести кластерах. Он отвечает за маршрутизацию ingress, терминацию TLS, access-логи в Elasticsearch, распределённую трассировку через OpenTelemetry и gzip-сжатие — всё через декларативные CRD.
Два ingress class
apisix-int работает в каждом окружении. Это внутренний ingress с ingressClass: apisix: через него внутренние сервисы (Grafana, Kibana, дашборды приложений) публикуются на приватных IP.
apisix-ext есть только в кластере demo. У него отдельный LoadBalancer IP, и он обслуживает внешние домены (*.test.antonnovikov.com, *.demo.test.antonnovikov.com).
Оба разворачиваются как HelmRelease через FluxCD. Базовый HelmRelease живёт в fluxcd/base/apisix-int.yaml; патчи для окружений переопределяют только LoadBalancer IP и адрес otel-collector.
Базовый HelmRelease
yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: apisix-int
namespace: ingress-apisix
spec:
chart:
spec:
chart: apisix
version: "2.8.*"
sourceRef:
kind: HelmRepository
name: apisix
namespace: flux-system
retries: -1
values:
apisix:
enabled: true
kind: DaemonSet
gateway:
type: LoadBalancer
ingress-controller:
enabled: true
etcd:
enabled: true
replicaCount: 1
kind: DaemonSet — один под APISIX на узел, распределение нагрузки без HPA.
ApisixGlobalRule: плагины для всего кластера
Вместо того чтобы вешать плагины на каждый маршрут отдельно, ApisixGlobalRule применяет их ко всему трафику.
Логирование в Elasticsearch
yamlapiVersion: apisix.apache.org/v2
kind: ApisixGlobalRule
metadata:
name: elasticsearch-logger
namespace: ingress-apisix
spec:
plugins:
- name: elasticsearch-logger
enable: true
config:
endpoint_addr: "http://infra-master.elasticsearch.svc.cluster.local:9200"
field:
index: "apisix"
pipeline: "apisix"
batch_max_size: 1000
buffer_duration: 60
Запросы со всех маршрутов попадают в индекс apisix в Elasticsearch. pipeline: "apisix" запускает ingest pipeline в ES, который разбирает сырой JSON на структурированные поля. Без ingest pipeline логи лягут неструктурированными JSON-строками — отфильтровать их в Kibana не получится.
Трассировка OpenTelemetry
yamlapiVersion: apisix.apache.org/v2
kind: ApisixGlobalRule
metadata:
name: opentelemetry
namespace: ingress-apisix
spec:
plugins:
- name: opentelemetry
enable: true
config:
sampler:
name: always_on
collector:
address: "otel-collector.elasticsearch.svc.cluster.local:4318"
additional_attributes:
- apisix_service_id
- apisix_balancer_ip
- apisix_consumer
- remote_addr
- upstream_addr
- upstream_status
- upstream_response_time
Сэмплирование — always_on. APISIX отправляет spans по OTLP/HTTP в otel-collector на порт 4318, а коллектор проксирует их в APM Server (тот принимает только gRPC).
additional_attributes добавляет в каждый span контекст APISIX: какой upstream получил запрос, код HTTP-ответа, время ответа upstream.
Указывайте полный FQDN в адресе otel-collector: короткие DNS-имена иногда не резолвятся в Lua-рантайме APISIX.
Gzip, real-ip и request-id
yaml- name: real-ip
enable: true
config:
source: http_x_forwarded_for
recursive: true
- name: gzip
enable: true
config:
min_length: 1024
types:
- text/html
- application/json
- text/plain
- name: request-id
enable: true
config:
header_name: X-Request-ID
include_in_response: true
real-ip с recursive: true корректно обрабатывает двойной NAT с несколькими балансировщиками.
TLS через ApisixTls
yamlapiVersion: apisix.apache.org/v2
kind: ApisixTls
metadata:
name: dev-antonnovikov-com
namespace: ingress-apisix
spec:
hosts:
- "*.dev.test.antonnovikov.com"
secret:
name: dev-antonnovikov-com-tls
namespace: ingress-apisix
TLS-секрет содержит tls.crt и tls.key, запечатанные через SealedSecrets. Ротация сертификата: обновите SealedSecret, закоммитьте, запушите — APISIX подхватит изменение без перезапуска.
Пример ApisixRoute
yamlapiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: grafana
namespace: ingress-apisix
spec:
http:
- name: grafana-rule
match:
hosts:
- grafana.dev.test.antonnovikov.com
paths:
- "/*"
backends:
- serviceName: kube-prom-stack-grafana
servicePort: 80
namespace: observability
Маршруты могут ссылаться на сервисы в других namespace — не нужно дублировать маршрут в каждом namespace.
Cilium L2 для LoadBalancer IP (on-prem)
На bare-metal-кластерах сервисы типа LoadBalancer получают IP из пула Cilium L2:
yamlvalues:
gateway:
type: LoadBalancer
annotations:
io.cilium/lb-ipam-ips: "172.16.57.200"
Патчинг APISIX для конкретного окружения
yaml# projects/dev/kustomization/hub/patches/apisix-int.yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: apisix-int
namespace: dev
spec:
values:
apisix:
externalIPs:
- 172.16.57.200
plugins:
- name: opentelemetry
conf:
collector:
address: "otel-collector.elasticsearch.svc.cluster.local:4318"
Suspend/resume при ручном вмешательстве
bashflux suspend helmrelease apisix-int -n dev --context=infra-k8s
flux resume helmrelease apisix-int -n dev --context=infra-k8s
На кластерах Yandex Cloud APISIX иногда застревает в цикле upgrade→rollback из-за порядка обновления DaemonSet. Suspend, исправление, resume — надёжный способ восстановиться.
Проверка состояния плагинов APISIX
bashkubectl exec -n ingress-apisix deploy/apisix -- \
curl -s http://localhost:9080/apisix/admin/plugins/list
kubectl exec -n ingress-apisix deploy/apisix -- \
curl -s http://localhost:9080/apisix/admin/global_rules