lulu_39
lulu_39

Reputation: 43

When I specify NodePort service as Ingress backend in GKE, I get two backends

-- Overview

I have a custom installation of istio on GKE (type=nodeport). The installation commands are as follows

istioctl install --set profile=default --set values.gateways.istio-ingressgateway.type=NodePort

I'm building Ingress and specifying the NodePort service as the backend. I found that another backend specified set by GCP as a default even though I specified NodePort. So, I couldn't connect to GCP LoadBalancer via TCP/IP. If I set the same port as the pod's readinessprobe for ingress and so on, the health checks look there too. Are there any way to solve this?

-- Detail

Detail view of LB

# This is a value that is automatically set by istio
$ k get svc istio-ingressgateway -n istio-system -o yaml
  ports:
  - name: status-port
    nodePort: 32476
    port: 15021
    protocol: TCP
    targetPort: 15021
  - name: http2
    nodePort: 32241
    port: 80
    protocol: TCP
    targetPort: 8080
  - name: https
    nodePort: 31739
    port: 443
    protocol: TCP
    targetPort: 8443
  - name: tcp-istiod
    nodePort: 32488
    port: 15012
    protocol: TCP
    targetPort: 15012
  - name: tls
    nodePort: 32741
    port: 15443
    protocol: TCP
    targetPort: 15443
$ k get po istio-ingressgateway-6f8bbbbd8c-qmkln -n istio-system -o yaml
:
    readinessProbe:
      failureThreshold: 30
      httpGet:
        path: /healthz/ready
        port: 15021
        scheme: HTTP
      initialDelaySeconds: 1
      periodSeconds: 2
      successThreshold: 1
      timeoutSeconds: 1
# 
spec:
  rules:
  - host: www.custom.com
    http:
      paths:
      - backend:
          serviceName: istio-ingressgateway
          servicePort: 80
      - backend:
          serviceName: istio-ingressgateway
          servicePort: 15021
istio-system   istio-ingressgateway   NodePort    10.47.13.185   <none>        15021:31761/TCP,80:31561/TCP,443:31257/TCP,15012:31841/TCP,15443:32172/TCP   9h

Upvotes: 2

Views: 1351

Answers (1)

Dawid Kruk
Dawid Kruk

Reputation: 9887

I've divided this answer on parts:

  • Two backends when creating an Ingress resource with GKE.
  • Ingress definition in the question.
  • Integrating Cloud Armor with Istio.

Two backends when creating an Ingress resource with GKE

This is working as expected as Ingress created with GKE will have 2 backends:

  • The one specified in the YAML manifest.
  • The default backend: default-http-backend.

As an example you can follow below steps:

  • $ kubectl create deployment nginx --image=nginx
  • $ kubectl expose deployment nginx --port=80 --type=NodePort
  • Create an Ingress resource for nginx but with a hello path (for example purposes)

After that you should be seeing a similar setup:

GCP LB

The first backend service is using an Instance group to send the requests to the default-backend that are not matching the Ingress resource.

The second backend service is using NEG (Network Endpoint Groups) to send the requests that are matching with the Ingress resource (in this example to an nginx Deployment).

I've marked the red squares to "connect it" with the Kubernetes resources (look on ports):

  • $ kubectl get svc nginx
NAME    TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
nginx   NodePort   10.20.6.229   <none>        80:32612/TCP   51m
  • $ kubectl get svc -n kube-system default-http-backend
NAME                   TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
default-http-backend   NodePort   10.20.15.39   <none>        80:30603/TCP   121m

Ingress definition in the question

The part of the Ingress definition that was included in the question is/was created in a way that was referencing the same paths with 2 different backends:

    http:
      paths:
      - backend:
          serviceName: istio-ingressgateway
          servicePort: 80
      - backend:
          serviceName: istio-ingressgateway
          servicePort: 15021

Above example:

  • Is having 2 different backends.
  • Is configured that 2 different backends share the same path.
  • The requests (as I've reproduced it) were coming to the "15021" backend which is only for health checking.

To fix that, you will need to remove the 15021 backend and use backendConfig resource to configure health checking and security policy (more on that later).

A side note!

The YAML manifest is using and old and soon to be deprecated way to describe Ingress. Please refer to this documentation for more reference:


Integrating Cloud Armor with Istio

One of the ways that you can use Cloud Armor with Istio is the following:

  • Create a security policy.
  • Create a backendConfig as a prerequisite for Istio Service.
  • Install Istio with modification to its Service.
  • Create an Ingress resource to point to istio-ingressgateway.
  • Test with an example.

Create a security policy

For example purposes a security policy can be created that only blocks a single IP address. It can be done either by gcloud or Cloud Console (Web UI):

Let's assume that the security policy named: deny-single was created that blocks a single IP address.

Create a backendConfig as a prerequisite for Istio Service.

You will need to create a backendConfig that will configure health checks and will enforce the security policy:

apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: ingress-backendconfig
  namespace: istio-system
spec:
  healthCheck:
    requestPath: /healthz/ready
    port: 15021
    type: HTTP
  securityPolicy:
    name: deny-single # <-- IMPORTANT

Install Istio with modification to its Service

You will need to add following annotations to the Service of your istio-ingressgateway:

    cloud.google.com/backend-config: '{"default": "ingress-backendconfig"}'
    cloud.google.com/neg: '{"ingress":true}'

This annotations will inform GCP on the security policy to apply as well on the health checks that are required for the traffic to be passed to the istio-ingressgateway.

Create an Ingress resource to point to istio-ingressgateway

A basic Ingress definition that will send the request from HTTP(S) Load Balancer to istio-ingressgateway can be following:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: istio-ingress
  namespace: istio-system
spec:
  rules:
  - http:
      paths:
      - path: /*
        pathType: ImplementationSpecific
        backend:
          service:
            name: istio-ingressgateway
            port:
              number: 80

Test with an example

To check if the setup is working correctly you can spawn the Bookinfo Application.

Testing with 2 different IP addresses:

  • $ curl ifconfig.me
217.AAA.BBB.CCC
  • $ curl 34.XXX.YYY.ZZZ/productpage
<!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden%
  • $ curl ifconfig.me
94.EEE.FFF.GGG
  • $ curl 34.XXX.YYY.ZZZ/productpage
<html>
  <head>
    <title>Simple Bookstore App</title>
<-- REDACTED --> 

A side note!

The "closed port" that you've received could be related to the fact that istio-ingressgateway was configured to listen on specific path like /productpage and not /. (if the request was specifically targeted to port 80 instead of 15021)


Additional resources:

Upvotes: 4

Related Questions