м. Київ, вул. Кирилівська 102

26 липня 2026 р.

Встановлення та налаштування Nginx Ingress Controller

Встановлення та налаштування Nginx Ingress Controller

Ingress Controller приймає HTTP та HTTPS трафік на межі Kubernetes-кластера, аналізує host і path, а потім спрямовує запит до потрібного Service. Без контролера ресурс Ingress залишається лише декларацією: Kubernetes збереже YAML, але самостійно не створить reverse proxy і не почне обробляти зовнішні з’єднання.

У цьому матеріалі встановимо community-проєкт ingress-nginx через офіційний Helm chart, перевіримо створені компоненти, опублікуємо тестовий застосунок, налаштуємо host-based routing і розберемо діагностику. Перед початком потрібні робочий кластер, доступ через kubectl, Helm і розуміння того, звідки надходить зовнішній трафік. Якщо chart-и ще незнайомі, корисно спочатку пройти практичний матеріал Helm Charts для початківців.

Ingress працює тільки з HTTP(S). Для довільного TCP або UDP потрібна окрема конфігурація контролера чи Service іншого типу. Також важливо не плутати ingress-nginx із комерційними продуктами NGINX Inc.: у них різні chart-и, образи, параметри та документація.

Що перевірити перед встановленням контролера

Спочатку переконаємося, що kubectl спрямований у правильний кластер. Помилка kube-context небезпечніша за помилку YAML, адже коректна команда може змінити не те середовище.

bash
kubectl config current-context
kubectl cluster-info
kubectl get nodes -o wide
helm version

Далі перевіримо, чи вже немає іншого Ingress Controller. У керованому кластері він може бути встановлений платформою, а в k3s або Rancher Desktop часто вже працює Traefik. Два контролери допустимі, але для них потрібні різні IngressClass і зрозумілий розподіл ресурсів.

bash
kubectl get ingressclass
kubectl get pods --all-namespaces \
  -l app.kubernetes.io/component=controller

Потрібно заздалегідь визначити спосіб зовнішнього доступу. У хмарному кластері Service типу LoadBalancer зазвичай отримує адресу від інтеграції провайдера. На bare-metal сам тип LoadBalancer не створить фізичний балансувальник: потрібен MetalLB, зовнішній load balancer, NodePort або інша мережева схема. Цю частину не можна маскувати налаштуванням Ingress, бо controller не керує маршрутом до Kubernetes-вузлів.

Для production також варто визначити кількість реплік, topology spread або anti-affinity, ресурси, політику збереження client IP та джерело TLS-сертифікатів. Коли такі рішення охоплюють кластер, CI/CD і спостережуваність, їх доцільно оформлювати як єдиний контур DevOps-послуг, а не як набір ручних команд.

Встановлення ingress-nginx через Helm

Додамо офіційний chart repository та переглянемо доступні версії. У відтворюваному процесі версію chart потрібно фіксувати, а не щоразу мовчки брати найновішу.

bash
helm repo add ingress-nginx \
  https://kubernetes.github.io/ingress-nginx
helm repo update
helm search repo ingress-nginx/ingress-nginx --versions | head

Збережемо типові values у файл для аудиту. Це допомагає бачити доступні параметри саме тієї версії, яку плануємо встановити.

bash
helm show values ingress-nginx/ingress-nginx \
  --version CHART_VERSION \
  > ingress-nginx-default-values.yaml

Створимо невеликий `values-ingress-nginx.yaml`. Для універсального прикладу залишаємо LoadBalancer, дві репліки, ресурси та metrics endpoint. У конкретній хмарі до Service можуть бути потрібні provider-specific annotations.

yaml
controller:
  replicaCount: 2

  service:
    type: LoadBalancer
    externalTrafficPolicy: Local

  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 512Mi

  metrics:
    enabled: true

  config:
    use-forwarded-headers: "true"

`externalTrafficPolicy: Local` допомагає зберігати адресу клієнта, але вимагає уважної перевірки health checks і розміщення controller pods. `use-forwarded-headers` має сенс лише тоді, коли перед ingress-nginx є довірений proxy або load balancer. Не можна без перевірки довіряти довільним forwarded headers з інтернету.

Встановимо release idempotent-командою. Значення `CHART_VERSION` потрібно замінити на перевірену версію з попереднього списку.

bash
helm upgrade --install ingress-nginx \
  ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --version CHART_VERSION \
  -f values-ingress-nginx.yaml \
  --atomic \
  --wait \
  --timeout 10m

Параметр `--atomic` поверне release до попереднього стану, якщо upgrade не завершиться успішно. Це не скасовує необхідність окремо перевіряти мережу, DNS і доступність backend після встановлення.

Перевірка controller, webhook і зовнішньої адреси

Після Helm-команди перевіримо release та Kubernetes-об’єкти. Controller pod повинен перейти у стан Ready, а admission jobs і webhook — створитися без помилок.

bash
helm status ingress-nginx -n ingress-nginx
kubectl get pods,svc -n ingress-nginx -o wide
kubectl get ingressclass
kubectl get validatingwebhookconfiguration \
  ingress-nginx-admission

Перший запуск може тривати довше, поки jobs створюють сертифікат admission webhook. Дочекаємося готовності controller pods:

bash
kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=180s

У хмарі зовнішню адресу дивимося у Service:

bash
kubectl get service ingress-nginx-controller \
  -n ingress-nginx \
  -o wide

Якщо поле EXTERNAL-IP довго залишається `<pending>`, причина зазвичай не в Ingress YAML. Треба перевірити cloud controller manager, квоти, annotations провайдера або відсутність реалізації LoadBalancer у bare-metal кластері.

На bare-metal для першого тесту можна використати NodePort. Змініть `controller.service.type` на `NodePort`, виконайте Helm upgrade і подивіться виділені порти. За замовчуванням вони потрапляють у діапазон 30000–32767.

bash
kubectl get service ingress-nginx-controller \
  -n ingress-nginx
kubectl get nodes -o wide

NodePort не означає автоматичний доступ на стандартних 80/443. Зовнішній firewall, NAT, DNS і маршрути до IP вузла залишаються окремими компонентами.

Тестовий застосунок і ресурс Ingress

Створимо окремий namespace і простий HTTP backend. У production замість імперативних команд ці ресурси мають зберігатися у Git як YAML або chart.

bash
kubectl create namespace ingress-demo
kubectl create deployment echo \
  --namespace ingress-demo \
  --image=hashicorp/http-echo \
  -- -text="ingress works"

kubectl expose deployment echo \
  --namespace ingress-demo \
  --port=80 \
  --target-port=5678

Тепер створимо `echo-ingress.yaml`. Ресурс Ingress і backend Service повинні бути в одному namespace. Поле `ingressClassName: nginx` явно вказує, який controller має обробляти правило.

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: echo
  namespace: ingress-demo
spec:
  ingressClassName: nginx
  rules:
    - host: echo.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: echo
                port:
                  number: 80

Застосуємо маніфест і перевіримо, як controller його прийняв:

bash
kubectl apply -f echo-ingress.yaml
kubectl get ingress -n ingress-demo
kubectl describe ingress echo -n ingress-demo
kubectl get endpointslices -n ingress-demo \
  -l kubernetes.io/service-name=echo

DNS A або CNAME record для `echo.example.com` повинен вести на зовнішню адресу ingress-nginx. До зміни DNS правило можна перевірити через curl, підставивши адресу вручну:

bash
curl --resolve echo.example.com:80:INGRESS_IP \
  http://echo.example.com/

Для локальної діагностики без зовнішнього load balancer підійде port-forward. Це тестовий метод, а не production-схема.

bash
kubectl port-forward \
  --namespace ingress-nginx \
  service/ingress-nginx-controller 8080:80

curl -H 'Host: echo.example.com' \
  http://127.0.0.1:8080/

Після перевірки тимчасовий namespace можна видалити, але не робіть цього, якщо він використовується командою для подальшої діагностики.

TLS, оновлення та типові помилки

Для HTTPS ресурс Ingress посилається на Secret типу `kubernetes.io/tls` у тому самому namespace. Secret можна створити вручну для тесту, але у стабільному середовищі сертифікати краще випускати та поновлювати автоматично.

yaml
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - echo.example.com
      secretName: echo-example-tls

Перед оновленням chart переглядайте release notes, diff values і сумісність із версією Kubernetes. Збережіть поточні values та історію:

bash
helm get values ingress-nginx \
  -n ingress-nginx -o yaml > current-values.yaml
helm history ingress-nginx -n ingress-nginx
helm repo update

Потім спочатку виконайте dry run, а реальний upgrade запускайте з тим самим versioned values-файлом через контрольований pipeline. Такий процес природно доповнює побудову та оптимізацію CI/CD.

bash
helm upgrade ingress-nginx \
  ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --version NEW_CHART_VERSION \
  -f values-ingress-nginx.yaml \
  --dry-run=server \
  --debug

Типова помилка — створити Ingress без controller або з неправильною `ingressClassName`. У такому разі ресурс існує, але маршрут не з’являється. Друга проблема — Service selector не знаходить pod, тому EndpointSlice порожній, а NGINX повертає 502 або 503. Третя — DNS веде не на ту адресу чи firewall не пропускає 80/443.

Четверта помилка — використання annotations без перевірки документації ingress-nginx. Деякі annotations змінюють поведінку NGINX, а небезпечні snippet annotations можуть бути заборонені адміністратором. П’ята — очікування, що bare-metal LoadBalancer з’явиться без MetalLB або іншої зовнішньої реалізації.

Для діагностики дивіться події Ingress, endpoints backend і логи controller, фільтруючи конкретний host:

bash
kubectl describe ingress echo -n ingress-demo
kubectl get endpointslices -n ingress-demo
kubectl logs -n ingress-nginx \
  -l app.kubernetes.io/component=controller \
  --tail=200 | grep echo.example.com

Висновок

Надійне встановлення ingress-nginx складається не лише з однієї Helm-команди. Потрібно перевірити наявні IngressClass, вибрати спосіб зовнішнього доступу, зафіксувати chart version, зберігати values у Git, дочекатися admission webhook і протестувати повний шлях від DNS до backend endpoints.

Робоча послідовність виглядає так: перевірка kube-context, Helm installation у власний namespace, контроль controller pods і Service, тестовий backend, Ingress з `networking.k8s.io/v1` та `ingressClassName`, перевірка через curl, а потім додавання TLS і автоматизованого upgrade-процесу. Якщо маршрут не працює, діагностику слід вести пошарово: зовнішня адреса, firewall, DNS, controller, правило Ingress, Service selector і готовність pod.

Такий підхід дає відтворювану точку входу в кластер і зменшує кількість ситуацій, коли зовнішня помилка маскується випадковою правкою annotations. Після стабілізації HTTP-маршрутизації наступним логічним кроком буде автоматичний випуск TLS-сертифікатів через cert-manager.

📞