Gateways de Entrada
Además del soporte para los recursos Ingress de Kubernetes, Istio también le permite configurar el tráfico de entrada
utilizando un Gateway de Istio o un recurso Gateway de Kubernetes.
Un Gateway proporciona una personalización y flexibilidad más amplias que Ingress, y permite que las features de Istio, como el monitoreo y las reglas de ruta, se apliquen al tráfico que ingresa al cluster.
Esta tarea describe cómo configurar Istio para exponer un service fuera de la service mesh utilizando un Gateway.
Antes de empezar
Configure Istio siguiendo las instrucciones de la guía de instalación.
Inicie la muestra httpbin, que servirá como service de destino para el tráfico de entrada:
$ kubectl apply -f @samples/httpbin/httpbin.yaml@Tenga en cuenta que, para el propósito de este documento, que muestra cómo usar un gateway para controlar el tráfico de entrada en su “cluster de Kubernetes”, puede iniciar el service
httpbincon o sin la inyección de sidecar habilitada (es decir, el service de destino puede estar dentro o fuera de la mesh de Istio).
Configuración de la entrada usando un gateway
Un Gateway de entrada describe un balanceador de carga que opera en el borde de la mesh y que recibe conexiones HTTP/TCP entrantes.
Configura los puertos expuestos, protocolos, etc.
pero, a diferencia de los Recursos Ingress de Kubernetes,
no incluye ninguna configuración de enrutamiento de tráfico. El enrutamiento de tráfico para el tráfico de entrada se configura
utilizando reglas de enrutamiento, exactamente de la misma manera que para las solicitudes de services internos.
Veamos cómo puede configurar un Gateway en el puerto 80 para el tráfico HTTP.
Cree un Gateway de Istio:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# El selector coincide con las etiquetas del pod del ingress gateway.
# Si instaló Istio usando Helm siguiendo la documentación estándar, esto sería "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOFConfigure las rutas para el tráfico que ingresa a través del 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
EOFAhora ha creado una configuración de virtual service
para el service httpbin que contiene dos reglas de ruta que permiten el tráfico para las rutas /status y
/delay.
La lista de gateways
especifica que solo se permiten las solicitudes a través de su httpbin-gateway.
Todas las demás solicitudes externas serán rechazadas con una respuesta 404.
Cree un Gateway de Kubernetes:
$ 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
EOFDebido a que la creación de un recurso Gateway de Kubernetes también
desplegará un service proxy asociado,
ejecute el siguiente comando para esperar a que el gateway esté listo:
$ kubectl wait --for=condition=programmed gtw httpbin-gatewayConfigure las rutas para el tráfico que ingresa a través del 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
EOFAhora ha creado una configuración de Ruta HTTP
para el service httpbin que contiene dos reglas de ruta que permiten el tráfico para las rutas /status y
/delay.
Determinación de la IP y los puertos de entrada
Cada Gateway está respaldado por un service de tipo LoadBalancer.
La IP y los puertos del balanceador de carga externo para este service se utilizan para acceder al gateway.
Los services de Kubernetes de tipo LoadBalancer son compatibles por defecto en clusters que se ejecutan en la mayoría de las plataformas en la nube, pero
en algunos entornos (por ejemplo, de prueba) es posible que deba hacer lo siguiente:
minikube: inicie un balanceador de carga externo ejecutando el siguiente comando en una terminal diferente:$ minikube tunnelkind: siga la guía para que los services de tipoLoadBalancerfuncionen.otras plataformas: es posible que pueda usar MetalLB para obtener una
EXTERNAL-IPpara los servicesLoadBalancer.
Para mayor comodidad, almacenaremos la IP y los puertos de entrada en variables de entorno que se utilizarán en instrucciones posteriores.
Establezca las variables de entorno INGRESS_HOST e INGRESS_PORT de acuerdo con las siguientes instrucciones:
Establezca las siguientes variables de entorno con el nombre y el namespace donde se encuentra el ingress gateway de Istio en su cluster:
$ export INGRESS_NAME=istio-ingressgateway
$ export INGRESS_NS=istio-systemEjecute el siguiente comando para determinar si su cluster de Kubernetes se encuentra en un entorno que admite balanceadores de carga externos:
$ 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 ... 17hSi el valor EXTERNAL-IP está establecido, su entorno tiene un balanceador de carga externo que puede usar para el ingress gateway.
Si el valor EXTERNAL-IP es <none> (o perpetuamente <pending>), su entorno no proporciona un balanceador de carga externo para el ingress gateway.
Si su entorno no admite balanceadores de carga externos, puede intentar acceder al ingress gateway utilizando los puertos de nodo. De lo contrario, establezca la IP y los puertos de entrada utilizando los siguientes comandos:
$ 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}')Obtenga la dirección y el puerto del gateway del recurso httpbin gateway:
$ 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}')Acceso a services de entrada
Acceda al service httpbin usando curl:
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/status/200" ... HTTP/1.1 200 OK ... server: istio-envoy ...Tenga en cuenta que utiliza el flag
-Hpara establecer la cabecera HTTP Host en “httpbin.example.com”. Esto es necesario porque suGatewayde entrada está configurado para manejar “httpbin.example.com”, pero en su entorno de prueba no tiene ninguna vinculación DNS para ese host y simplemente está enviando su solicitud a la IP de entrada.Acceda a cualquier otra URL que no haya sido expuesta explícitamente. Debería ver un error HTTP 404:
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/headers" HTTP/1.1 404 Not Found ...
Acceso a services de entrada usando un navegador
Introducir la URL del service httpbin en un navegador no funcionará porque no puede pasar la cabecera Host
a un navegador como lo hizo con curl. En una situación real, esto no es un problema
porque configura el host solicitado correctamente y es resoluble por DNS. Por lo tanto, utiliza el nombre de dominio del host
en la URL, por ejemplo, https://httpbin.example.com/status/200.
Puede solucionar este problema para pruebas y demostraciones simples de la siguiente manera:
Use un valor comodín * para el host en las configuraciones de Gateway
y VirtualService. Por ejemplo, cambie su configuración de entrada a lo siguiente:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# El selector coincide con las etiquetas del pod del ingress gateway.
# Si instaló Istio usando Helm siguiendo la documentación estándar, esto sería "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
EOFSi elimina los nombres de host de las configuraciones de Gateway y HTTPRoute, se aplicarán a cualquier solicitud.
Por ejemplo, cambie su configuración de entrada a lo siguiente:
$ 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
EOFLuego puede usar $INGRESS_HOST:$INGRESS_PORT en la URL del navegador. Por ejemplo,
http://$INGRESS_HOST:$INGRESS_PORT/headers mostrará todas las cabeceras que envía su navegador.
Comprender lo que sucedió
Los recursos de configuración de Gateway permiten que el tráfico externo ingrese a la
service mesh de Istio y ponen a disposición las features de gestión de tráfico y políticas de Istio
para los services de borde.
En los pasos anteriores, creó un service dentro de la service mesh y expuso un endpoint HTTP del service al tráfico externo.
Uso de puertos de nodo del service de ingress gateway
Si su entorno no admite balanceadores de carga externos, aún puede experimentar con algunas de las features de Istio utilizando
los puertos de nodo del service istio-ingressgateway.
Establezca los puertos de entrada:
$ 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}')La configuración de la IP de entrada depende del proveedor del cluster:
GKE:
$ export INGRESS_HOST=worker-node-addressDebe crear reglas de firewall para permitir el tráfico TCP a los puertos del service ingressgateway. Ejecute los siguientes comandos para permitir el tráfico para el puerto HTTP, el puerto seguro (HTTPS) o ambos:
$ 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-nodesDocker For Desktop:
$ export INGRESS_HOST=127.0.0.1Otros entornos:
$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n "${INGRESS_NS}" -o jsonpath='{.items[0].status.hostIP}')
Solución de problemas
Inspeccione los valores de las variables de entorno
INGRESS_HOSTeINGRESS_PORT. Asegúrese de que tienen valores válidos, de acuerdo con la salida de los siguientes comandos:$ kubectl get svc -n istio-system $ echo "INGRESS_HOST=$INGRESS_HOST, INGRESS_PORT=$INGRESS_PORT"Verifique que no tiene otros ingress gateways de Istio definidos en el mismo puerto:
$ kubectl get gateway --all-namespacesVerifique que no tiene recursos Ingress de Kubernetes definidos en la misma IP y puerto:
$ kubectl get ingress --all-namespacesSi tiene un balanceador de carga externo y no le funciona, intente acceder al gateway utilizando su puerto de nodo.
Limpieza
Elimine la configuración de Gateway y VirtualService, y apague el service httpbin:
$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@Elimine la configuración de Gateway y HTTPRoute, y apague el service httpbin:
$ kubectl delete httproute httpbin
$ kubectl delete gtw httpbin-gateway
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@