Ingress Gateways
Разом із підтримкою ресурсів Ingress Kubernetes, Istio також дозволяє налаштувати вхідний трафік, використовуючи ресурс Istio Gateway або Kubernetes Gateway. Gateway
забезпечує ширші налаштування та гнучкість, ніж Ingress
, і дозволяє застосовувати функції Istio, такі як моніторинг та правила маршрутизації, до трафіку, що входить у кластер.
Ця задача описує, як налаштувати Istio для експонування сервісу за межами сервісної мережі, використовуючи Gateway
.
Перш ніж почати
Налаштуйте Istio, дотримуючись інструкцій з Посібника з встановлення.
Запустіть httpbin, який буде служити цільовим сервісом для вхідного трафіку:
$ kubectl apply -f @samples/httpbin/httpbin.yaml@
Зверніть увагу, що для цілей цього документа, який показує, як використовувати шлюз для контролю вхідного трафіку у вашому “Kubernetes кластері”, ви можете запустити сервіс
httpbin
з увімкненою чи вимкненою ін’єкцією sidecar (тобто, цільовий сервіс може бути як всередині, так і поза мережею Istio).
Налаштування вхідного трафіку за допомогою шлюзу
Вхідний Gateway
описує балансувальник навантаження, який працює на периметрі мережі та приймає вхідні HTTP/TCP зʼєднання. Він налаштовує відкриті порти, протоколи тощо, але, на відміну від ресурсів Ingress Kubernetes, не включає жодної конфігурації маршрутизації трафіку. Маршрутизація трафіку для вхідного трафіку налаштовується за допомогою правил маршрутизації, точно так само, як і для внутрішніх запитів до сервісів.
Подивімось, як можна налаштувати Gateway
на порту 80 для HTTP трафіку.
Створимо Istio Gateway:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# Селектор збігається з мітками podʼів ingress gateway.
# Якщо ви встановили Istio за допомогою Helm, слідуючи стандартній документації, це буде "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOF
Налаштуйте маршрути для трафіку, що надходить через Gateway
:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
Тепер ви створили конфігурацію віртуального сервісу для сервісу httpbin
, що містить два правила маршрутизації, які дозволяють трафік для шляхів /status
та /delay
.
Список шлюзів вказує, що дозволені лише запити через ваш httpbin-gateway
. Усі інші зовнішні запити будуть відхилені з відповіддю 404.
Створіть Kubernetes Gateway:
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
gatewayClassName: istio
listeners:
- name: http
hostname: "httpbin.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
EOF
Оскільки створення ресурсу Kubernetes Gateway
також виконає розгортання асоційованого проксі-сервісу, виконайте наступну команду, щоб дочекатися готовності шлюзу:
$ kubectl wait --for=condition=programmed gtw httpbin-gateway
Налаштуйте маршрути для трафіку, що входить через Gateway
:
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: httpbin-gateway
hostnames: ["httpbin.example.com"]
rules:
- matches:
- path:
type: PathPrefix
value: /status
- path:
type: PathPrefix
value: /delay
backendRefs:
- name: httpbin
port: 8000
EOF
Ви створили конфігурацію HTTP Route для сервісу httpbin
, що містить два правила маршрутизації, які дозволяють трафік для шляхів /status
та /delay
.
Визначення IP-адреси та портів для вхідного трафіку
Кожен Gateway
підтримується сервісом типу LoadBalancer. Зовнішня IP-адреса та порти навантажувача для цього сервісу використовуються для доступу до шлюзу. Сервіси Kubernetes типу LoadBalancer
стандартно підтримуються у кластерах, що працюють на більшості хмарних платформ, але в деяких середовищах (наприклад, тестових) вам може знадобитися виконати наступні дії:
minikube
— запустіть зовнішній навантажувач, виконавши наступну команду в іншому терміналі:$ minikube tunnel
kind
— дотримуйтеся посібника, щоб забезпечити роботу сервісів типуLoadBalancer
.інші платформи — ви можете використовувати MetalLB для отримання
EXTERNAL-IP
для сервісів типуLoadBalancer
.
Для зручності ми збережемо IP-адресу та порти для вхідного трафіку у змінних середовища, які будуть використовуватися в подальших інструкціях. Налаштуйте змінні середовища INGRESS_HOST
та INGRESS_PORT
відповідно до наступних інструкцій:
Встановіть наступні змінні оточення на назву та простір імен, де знаходиться вхідний шлюз Istio у вашому кластері:
$ export INGRESS_NAME=istio-ingressgateway
$ export INGRESS_NS=istio-system
Запустіть наступну команду, щоб визначити, чи знаходиться ваш кластер Kubernetes в середовищі, яке підтримує зовнішні балансувальники навантаження:
$ kubectl get svc "$INGRESS_NAME" -n "$INGRESS_NS"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 172.21.109.129 130.211.10.121 ... 17h
Якщо встановлено значення EXTERNAL-IP
, ваше середовище має зовнішнього балансувальника навантаження, який ви можете використовувати для вхідного шлюзу. Якщо значення EXTERNAL-IP
дорівнює <none>
(або постійно <pending>
), у вашому середовищі не передбачено зовнішнього балансувальника навантаження для вхідного шлюзу.
Якщо ваше середовище не підтримує зовнішні балансувальники навантаження, ви можете спробувати доступ до вхідного шлюзу за допомогою портів вузла. В іншому випадку, встановіть IP-адресу і порти вхідного шлюзу за допомогою наступних команд:
$ export INGRESS_HOST=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
$ export TCP_INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="tcp")].port}')
Отримайте адресу та порт шлюзу з ресурсу шлюзу httpbin:
$ export INGRESS_HOST=$(kubectl get gtw httpbin-gateway -o jsonpath='{.status.addresses[0].value}')
$ export INGRESS_PORT=$(kubectl get gtw httpbin-gateway -o jsonpath='{.spec.listeners[?(@.name=="http")].port}')
Доступ до сервісів ingress
Доступ до сервісу httpbin за допомогою curl:
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/status/200" ... HTTP/1.1 200 OK ... server: istio-envoy ...
Зверніть увагу, що ви використовуєте прапорець
-H
, щоб встановити HTTP-заголовок Host на “httpbin.example.com”. Це необхідно, оскільки ваш вхіднийGateway
налаштовано на обробку “httpbin.example.com”, але у вашому тестовому середовищі ви не маєте привʼязки DNS для цього хосту і просто надсилаєте запит на вхідний IP.Доступ до будь-якої іншої URL-адреси, яка не була відкрита явно. Ви побачите помилку HTTP 404:
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/headers" HTTP/1.1 404 Not Found ...
Доступ до сервісів ingress за допомогою оглядача
Введення URL сервісу httpbin
у оглядачі не працюватиме, оскільки ви не можете передати заголовок Host оглядачу так, як це зробили з curl
. У реальній ситуації це не є проблемою, тому що ви налаштовуєте запитуваний хост правильно, і він доступний через DNS. Таким чином, ви використовуєте доменне ім’я хосту в URL, наприклад, https://httpbin.example.com/status/200
.
Ви можете обійти цю проблему для простих тестів і демонстрацій наступним чином:
Використовуйте значення універсального символу *
для хосту в конфігураціях Gateway
та VirtualService
. Наприклад, змініть вашу конфігурацію для вхідного трафіку на наступну:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# Селектор збігається з мітками podʼів ingress gateway.
# Якщо ви встановили Istio за допомогою Helm, слідуючи стандартній документації, це буде "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /headers
route:
- destination:
port:
number: 8000
host: httpbin
EOF
Якщо ви видалите імена хостів з конфігурацій Gateway
і HTTPRoute
, вони будуть застосовуватися до будь-якого запиту. Наприклад, змініть конфігурацію вхідних даних на наступну:
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
gatewayClassName: istio
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
spec:
parentRefs:
- name: httpbin-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /headers
backendRefs:
- name: httpbin
port: 8000
EOF
Потім ви можете використовувати $INGRESS_HOST:$INGRESS_PORT
в URL-адресі оглядача. Наприклад, http://$INGRESS_HOST:$INGRESS_PORT/headers
покаже всі заголовки, які надсилає ваш оглядач.
Розуміння того, що сталося
Ресурси конфігурації Gateway
дозволяють зовнішньому трафіку потрапляти до сервісної мережі Istio і надають можливість використовувати функції керування трафіком та політики Istio для граничних сервісів.
У попередніх кроках ви створили сервіс всередині сервісної мережі та експонували HTTP-точку доступу цього сервісу для зовнішнього трафіку.
Використання NodePort сервісу ingress gateway
Якщо ваше середовище не підтримує зовнішні навантажувачі, ви все ще можете експериментувати з деякими функціями Istio, використовуючи NodePort сервісу istio-ingressgateway
.
Налаштуйте порти для вхідного трафіку:
$ export INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
$ export SECURE_INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
$ export TCP_INGRESS_PORT=$(kubectl -n "${INGRESS_NS}" get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="tcp")].nodePort}')
Налаштування IP-адреси для вхідного трафіку залежить від постачальника кластера:
GKE:
$ export INGRESS_HOST=worker-node-address
Вам потрібно створити правила брандмауера для дозволу TCP-трафіку на порти сервісу ingressgateway. Виконайте наступні команди, щоб дозволити трафік для порту HTTP, захищеного порту (HTTPS) або обох:
$ gcloud compute firewall-rules create allow-gateway-http --allow "tcp:$INGRESS_PORT" $ gcloud compute firewall-rules create allow-gateway-https --allow "tcp:$SECURE_INGRESS_PORT"
IBM Cloud Kubernetes Service:
$ ibmcloud ks workers --cluster cluster-name-or-id $ export INGRESS_HOST=public-IP-of-one-of-the-worker-nodes
Docker For Desktop:
$ export INGRESS_HOST=127.0.0.1
Інші середовища:
$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n "${INGRESS_NS}" -o jsonpath='{.items[0].status.hostIP}')
Розвʼязання проблем
Перевірте значення змінних середовища
INGRESS_HOST
таINGRESS_PORT
. Переконайтеся, що вони мають дійсні значення відповідно до результатів наступних команд:$ kubectl get svc -n istio-system $ echo "INGRESS_HOST=$INGRESS_HOST, INGRESS_PORT=$INGRESS_PORT"
Перевірте, що у вас немає інших шлюзів Istio, які визначені на тому ж порту:
$ kubectl get gateway --all-namespaces
Перевірте, що у вас немає ресурсів Kubernetes Ingress, які визначені на тій самій IP-адресі та порту:
$ kubectl get ingress --all-namespaces
Якщо у вас є зовнішній навантажувач, і він не працює, спробуйте отримати доступ до шлюзу, використовуючи його NodePort.
Очищення
Видаліть конфігурації Gateway
та VirtualService
та вимкніть службу httpbin:
$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@
Видаліть конфігурації Gateway
і VirtualService
та вимкніть службу httpbin:
$ kubectl delete httproute httpbin
$ kubectl delete gtw httpbin-gateway
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@