Введение
Сервисы предоставляют стабильные точки доступа к приложениям внутри кластера. Ingress добавляет перед сервисами правила маршрутизации HTTP и позволяет нескольким приложениям использовать одну точку входа, различая их по имени хоста или URL-пути.
Вы изучите подготовленный контроллер ingress-nginx, развернёте два бэкенда, добавите маршрутизацию по хосту и пути, а затем проследите путь запроса через Ingress, Service и Pod.
На протяжении всей лабораторной работы держите в уме следующий маршрут запроса: клиент → точка входа ingress-nginx → правило Ingress → Service → готовый Pod. Если запрос завершается ошибкой, проверять эти связи по порядку гораздо проще, чем рассматривать Ingress как единый «чёрный ящик».
Изучение контроллера Ingress
На этом шаге вы изучите контроллер, уже предоставленный средой CKA, вместо установки его второй копии.
Объект Ingress содержит конфигурацию, а не сам процесс прокси. Он не будет работать, если совместимый контроллер не отслеживает этот объект. Для начала убедитесь, что присутствуют обе необходимые части инфраструктуры: IngressClass с именем nginx и доступный Deployment контроллера ingress-nginx.
cd /home/labex/project/ingress-routing
kubectl get ingressclasses
kubectl get deployments,pods,services -n ingress-nginx
kubectl wait --for=condition=Available deployment/ingress-nginx-controller -n ingress-nginx --timeout=60s
Ресурс Ingress хранит намерение маршрутизации. Контроллер ingress-nginx отслеживает ресурсы, у которых значение ingressClassName равно nginx, и настраивает фактический прокси.
Сервис контроллера публикует прокси через NodePort в этом локальном кластере. Позже вы определите этот порт, не прописывая его жёстко.
Подготовленная среда должна показать класс nginx, один доступный контроллер и сервис NodePort:
NAME CONTROLLER
nginx k8s.io/ingress-nginx
deployment.apps/ingress-nginx-controller 1/1 ...
service/ingress-nginx-controller NodePort ... 80:.../TCP,443:.../TCP
Два Pod со статусом Completed, которые также могут отображаться, — это уже завершившиеся установочные Job. Они не являются отказавшими репликами контроллера.
Развёртывание двух сервисов бэкенда
На этом шаге из одного многофайлового документа создайте два веб-приложения с одной репликой каждое и соответствующие сервисы ClusterIP.
Эти бэкенды используют концепции из курса «Kubernetes для начинающих», поэтому основное внимание уделяется не синтаксису Deployment, а связи между ресурсами и правилам маршрутизации. Файл содержит пять YAML-документов, разделённых ---: сначала Namespace, затем Deployment и Service для каждого приложения. Сопоставьте Service.spec.selector с меткой соответствующего Pod — они должны совпадать, прежде чем Ingress сможет направлять трафик.
cd /home/labex/project/ingress-routing
cat <<'EOF' > backends.yaml
apiVersion: v1
kind: Namespace
metadata: {name: practice-ingress}
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: storefront, namespace: practice-ingress}
spec:
replicas: 1
selector: {matchLabels: {app: storefront}}
template:
metadata: {labels: {app: storefront}}
spec:
containers: [{name: web, image: nginx:1.27-alpine, imagePullPolicy: IfNotPresent, ports: [{name: http, containerPort: 80}]}]
---
apiVersion: v1
kind: Service
metadata: {name: storefront, namespace: practice-ingress}
spec: {selector: {app: storefront}, ports: [{name: http, port: 80, targetPort: http}]}
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: reports, namespace: practice-ingress}
spec:
replicas: 1
selector: {matchLabels: {app: reports}}
template:
metadata: {labels: {app: reports}}
spec:
containers: [{name: web, image: httpd:2.4-alpine, imagePullPolicy: IfNotPresent, ports: [{name: http, containerPort: 80}]}]
---
apiVersion: v1
kind: Service
metadata: {name: reports, namespace: practice-ingress}
spec: {selector: {app: reports}, ports: [{name: http, port: 80, targetPort: http}]}
EOF
Примените все пять документов одной командой и дождитесь готовности обоих Deployment. Раздельное ожидание помогает понять, какой именно бэкенд неисправен, если проблема связана с образом или селектором:
kubectl apply -f backends.yaml
kubectl rollout status deployment/storefront -n practice-ingress --timeout=60s
kubectl rollout status deployment/reports -n practice-ingress --timeout=60s
Ingress направляет трафик только к сервисам, поэтому у каждого бэкенда уже должны быть готовые конечные точки.
Перед созданием правил маршрутизации явно проверьте это условие:
kubectl get services,endpointslices -n practice-ingress
У каждого сервиса должен быть соответствующий EndpointSlice с одним готовым адресом.
service/reports ClusterIP ... 80/TCP
service/storefront ClusterIP ... 80/TCP
endpointslice.../reports-... IPv4 80 10.244.104...
endpointslice.../storefront-... IPv4 80 10.244.104...
Суффиксы и адреса создаются автоматически и могут отличаться, но у каждого имени Service должен быть один непустой EndpointSlice. Ingress не может исправить сервис без бэкенда — эта проверка намеренно подтверждает работоспособность нижнего уровня заранее.
Добавление маршрутизации по хосту
На этом шаге направьте запросы к store.practice.test в сервис storefront.
Правило Ingress принимает три решения о маршрутизации: host, path и порт сервиса бэкенда. Параметр ingressClassName: nginx выбирает нужный контроллер. Аннотация rewrite зависит от конкретного контроллера: она изменяет путь запроса, передаваемого бэкенду, на /, который могут обработать оба демонстрационных веб-сервера.
cd /home/labex/project/ingress-routing
cat <<'EOF' > ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: practice-routing
namespace: practice-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: store.practice.test
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: storefront
port: {name: http}
EOF
Примените правило и с помощью describe изучите, как контроллер его интерпретировал, включая определённую конечную точку бэкенда:
kubectl apply -f ingress.yaml
kubectl describe ingress practice-routing -n practice-ingress
pathType: Prefix сопоставляет путь / и все его подпути. Аннотация rewrite направляет выбранный запрос к пути / на бэкенде, где демонстрационный веб-сервер предоставляет страницу. Хост используется как ключ HTTP-маршрутизации; для этого локального теста публичная DNS-запись не требуется.
Команда describe должна разрешить правило вплоть до адреса Pod:
Rules:
Host Path Backends
store.practice.test
/ storefront:http (10.244.104...:80)
Пустое поле Address сразу после создания объекта в этой локальной среде не означает ошибку. Важными подтверждениями являются найденный бэкенд storefront:http и адрес его Pod.
Добавление маршрутизации по пути и проверка запросов
На этом шаге добавьте маршрут /reports и проверьте оба правила через точку входа узла.
Путь JSON Patch заканчивается на /-. Для массива - означает добавление нового элемента, а не замену существующего маршрута /. Новый бэкенд указывает на сервис reports, используя его именованный порт http.
Выполните это добавление один раз. В отличие от kubectl apply, добавление в /- не является идемпотентным: повторный запуск добавит ещё один идентичный элемент /reports, вместо того чтобы распознать уже существующий.
Следующие две команды определяют конечную точку вместо использования жёстко заданного адреса. minikube ip -p labex-v135 возвращает IP-адрес узла для указанного профиля Minikube, а подстановка команд $(...) сохраняет вывод каждой команды в переменную оболочки. Запрос JSONPath выбирает порт сервиса с именем http и извлекает его NodePort.
kubectl patch ingress practice-routing -n practice-ingress --type='json' -p='[{"op":"add","path":"/spec/rules/0/http/paths/-","value":{"path":"/reports","pathType":"Prefix","backend":{"service":{"name":"reports","port":{"name":"http"}}}}}]'
NODE_IP=$(minikube ip -p labex-v135)
HTTP_NODE_PORT=$(kubectl get service ingress-nginx-controller -n ingress-nginx -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}')
echo "Ingress endpoint: ${NODE_IP}:${HTTP_NODE_PORT}"
Эти две переменные позволяют не включать в инструкции адреса, зависящие от конкретной среды. Теперь отправьте запросы с заголовком host, который требуется правилом. В каждой команде curl параметр -s скрывает индикатор выполнения, --retry 5 повторяет запрос при временных сбоях, --retry-connrefused также повторяет запрос при первоначальном отказе в соединении, а --retry-delay 2 ждёт две секунды между попытками. Параметр -H задаёт HTTP-заголовок Host, а конвейер передаёт ответ в grep, чтобы вывести только текст, идентифицирующий страницу.
curl -s --retry 5 --retry-connrefused --retry-delay 2 -H 'Host: store.practice.test' "http://${NODE_IP}:${HTTP_NODE_PORT}/" | grep 'Welcome to nginx'
curl -s --retry 5 --retry-connrefused --retry-delay 2 -H 'Host: store.practice.test' "http://${NODE_IP}:${HTTP_NODE_PORT}/reports" | grep 'It works'
Два ответа подтверждают, что одна точка входа направляет запросы к разным сервисам.
Первый ответ поступает от NGINX, а второй — от Apache httpd. Отличающийся текст страниц намеренно служит доказательством того, что правило маршрутизации по пути выбрало другой бэкенд, а не просто вернуло код HTTP 200.
Ожидаемые строки:
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
<title>It works! Apache httpd</title>
<p>It works!</p>
Этот результат также показывает, почему важен пользовательский заголовок Host: оба запроса достигают одного и того же IP-адреса узла и NodePort, а именно хост и путь определяют правило и выбранный бэкенд.
Итоги
Вы использовали подготовленный контроллер ingress-nginx, связали правила Ingress с готовыми сервисами и проверили маршрутизацию по хосту и пути через единую точку входа.


