This topic describes how to configure and update a Spring Cloud Gateway for Kubernetes instance.

Configure Gateway Instances

To create a Gateway instance, you must create a resource of type SpringCloudGateway. The definition for SpringCloudGateway specifies:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name:            # Name given to this Gateway instance (required)
  labels:
    my-custom-label: hello # Labels defined in the Gateway resource will also be applied to the Gateway Pods for simplified management
spec:
  count:           # Number of container instances (pods) to scale Gateway for high availability (HA) configuration
  tls:             # Set a list of TLS-enabled hosts
    - hosts:       # Array of hostnames for which to perform TLS termination using the specified certificate
      secretName:  # Name of TLS secret to load certificate and key from
  sso:
    secret:        # Secret name to be used for SSO configuration
    roles-attribute-name:
                   # Roles attribute name used to extract user roles for Roles filter (default: 'roles')
    inactive-session-expiration-in-minutes:
                  # Time to life of inactive sessions in minutes, 0 means sessions won't expire.
  observability:
    metrics:
      wavefront:
        enabled:  # If wavefront metrics should be pushed
      prometheus:
        enabled:  # If a prometheus endpoint should be exposed
        annotations:
          enabled: # If scrapping annotations should be included in the Pod
    tracing:
      wavefront:
        enabled: # If wavefront traces should be pushed
    wavefront:
      secret:        # Secret name to be used for wavefront configuration
      source:        # The wavefront source (default: Gateway Pod name, `gateway-0`).
      application:   # The wavefront application (default: Gateway Namespace `namespace`).
      service:       # The wavefront service (default: Gateway name `my-gateway`).
  api:
    title:         # Title describing the context of the APIs available on the Gateway instance (default: `Spring Cloud Gateway for K8S`)
    description:   # Detailed description of the APIs available on the Gateway instance (default: `Generated OpenAPI 3 document that describes the API routes configured for '[Gateway instance name]' Spring Cloud Gateway instance deployed under '[namespace]' namespace.`)
    documentation: # Location of additional documentation for the APIs available on the Gateway instance
    version:       # Version of APIs available on this Gateway instance (default: `unspecified`)
    serverUrl:     # Base URL that API consumers will use to access APIs on the Gateway instance
    cors:
      allowedOrigins:   # Allowed origins to make cross-site requests
      allowedMethods:   # Allowed HTTP methods on cross-site requests
      allowedHeaders:   # Allowed headers in cross-site request
      maxAge:           # How long, in seconds, the response from a pre-flight request can be cached by clients
      allowCredentials: # Whether user credentials are supported on cross-site requests
      exposedHeaders:   # HTTP response headers to expose for cross-site requests
  java-opts:       # JRE parameters for Gateway instance to enhance performance

  env:             # Set a list of [configuration](https://cloud.spring.io/spring-cloud-gateway/reference/html/appendix.html#common-application-properties) environment variables to configure this Gateway instance
    - name:          # Name of the environment variable
      value:         # Value of environment variable

  extensions:                 # Additional configurations for global features (e.g. custom filters, Api Key,...)
    custom:                   # Array of custom extensions to load (name must match the ConfigMap name).
    secretsProviders:         # Array of secret providers. These are identified by a name and follow conventions similar to `volumes`. Currently supported Vault.
    filters:
      apiKey:                 # API Key specific configurations
        enabled:
        secretsProviderName:
      jwtKey:                 # JWT Key specific configurations
        enabled:
        secretsProviderName:

  resources:
    requests:      # Requested amount of compute resources for the Gateway instance
      cpu:
      memory:
    limits:        # Maximum amount of compute resources allowed for the Gateway instance
      cpu:
      memory:

  securityContext: # SecurityContext applied to the Gateway pod(s).
    fsGroup:       # Set to 1000 by default
    runAsGroup:
    runAsUser:

  serviceAccount:  # Name of the ServiceAccount associated to the Gateway instance
    name:

Following is an example Gateway instance configuration file:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  count: 3
  api:
    title: My Exciting APIs
    description: Lots of new exciting APIs that you can use for examples!
    version: 0.1.0
    serverUrl: https://gateway.example.com
  env:
    - name: spring.cloud.gateway.httpclient.connect-timeout
      value: "90s"

Configure External Access

Each Gateway instance has an associated service of type ClusterIP. You can expose this service via common Kubernetes approaches such as ingress routing or port forwarding. Consult your cloud provider's documentation for Ingress options available to you.

Using an Ingress Resource

Before adding an Ingress, ensure that you have an ingress controller running in your Kubernetes cluster according to your cloud provider documentation.

To use an Ingress resource for exposing a Gateway instance:

  1. In the namespace where the Gateway instance was created, locate the ClusterIP service associated with the Gateway instance. You can either use this service as an Ingress backend or change it to a different Service type.

  2. Create a file called ingress-config.yaml, with the following YAML definition:

    apiVersion: networking.k8s.io/v1
    kind: Ingress 
    metadata: 
      name: my-gateway-ingress
      namespace: my-namespace
      annotations: 
        kubernetes.io/ingress.class: contour 
    spec: 
      rules: 
        - host: my-gateway.my-example-domain.com 
          http: 
            paths:
              - path: /
                pathType: Prefix
                backend: 
                  service:
                    name: my-gateway 
                    port:
                      number: 80 
    

    For the host and serviceName values, substitute your desired hostname and service name.

    This example Ingress resource configuration uses the Project Contour Ingress Controller. You can adapt the example configuration if you wish to use another Ingress implementation.

  3. Apply the Ingress definition file. The Ingress resource will be created in the same namespace as the Gateway instance.

  4. Examine the newly created Ingress resource:

    $ kubectl -n my-namespace get ingress my-gateway-ingress
    
    NAME                  CLASS    HOSTS                                     ADDRESS       PORTS   AGE
    my-gateway-ingress    <none>   my-gateway.my-example-domain.com          34.69.53.79    80     2m51s
    
    $ kubectl -n my-namespace describe ingress my-gateway-ingress
    
    Name:             my-gateway-ingress
    Namespace:        my-namespace 
    Address:          34.69.53.79 
    Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>) 
    Rules: 
      Host                                     Path  Backends 
      ----                                     ----  -------- 
      my-gateway.my-example-domain.com
                                               /   my-gateway:80 () 
    

    As the example output shows, the my-gateway.my-example-domain.com virtual host in the Ingress definition is mapped to the my-gateway service on the backend.

  5. Ensure that you can resolve the Ingress definition hostname (in this example, my-gateway.my-example-domain.com) to the IP address of the Ingress resource.

    The IP address is shown in the Address field of the output from the kubectl describe command.

    For local testing, use the command below to open your /etc/hosts file.

    sudo vim /etc/hosts
    

    Resolve the hostname by adding a line to the hosts file.

    34.69.53.79     my-gateway.my-example-domain.com 
    

    For extended evaluation, you might create a wildcard DNS A record that maps any virtual host on the domain name (for example, *.my-example-domain.com) to the Ingress resource.

  6. You should now be able to connect to your Gateway instance via the Ingress resource, using a web browser or an HTTP client such as HTTPie or cURL.

    $ http my-gateway.my-example-domain.com/github
    $ http my-gateway.my-example-domain.com/github/<YOUR_GITHUB_USERNAME>
    

    These requests should receive responses from the GitHub homepage (https://github.com) or from the requested path on the GitHub website.

  7. Test the SSO configuration, for example using an HTTP client such as HTTPie:

    $ http my-gateway.my-example-domain.com/github
    

    This request should result in a 302 HTTP status code response, redirecting to the SSO login page. If you use a web browser to access the route my-gateway.my-example-domain.com/github, you will be redirected to the SSO login page. After authenticating, you will be redirected to the GitHub home page.

TLS Passthrough

If you would like to enable TLS termination on your Gateway instance, you will need to route requests to port 443, rather than port 80, of the gateway service.

You will also need to configure your Ingress to allow TLS passthrough - this configuration is Ingress implementation dependent.

As an example, to do this using Contour, instead of using the Ingress API you will need to create an HTTPProxy instance, using the TLS passthrough option:

apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  name: my-gateway-httpproxy
spec:
  virtualhost:
    fqdn: my-gateway.my-example-domain.com
    tls:
      passthrough: true
  tcpproxy:
    services:
      - name: my-gateway
        port: 443

Gateway Actuator Management Port

Spring Cloud Gateway for Kubernetes instances are created with a Spring Boot actuator management port. The management port is 8090 on each Gateway instance pod based on the HA configuration. This management port can be used for monitoring using the following endpoints:

  • /actuator/info - display version and other Gateway instance information
  • /actuator/health - displays Gateway instance health indicator as status value UP or DOWN
  • /actuator/gateway/routes - retrieve list of all API routes currently available on Gateway instance
  • /actuator/gateway/globalfilters - retrieve list of global filters enabled on Gateway instance
  • /actuator/gateway/routefilters - retrieve list of route filters available on Gateway instance

Configure for High Availability

You can configure Spring Cloud Gateway for Kubernetes to run multiple instances in High Availability as you would do with a normal Kubernetes resource.

While a Gateway is running you can use kubectl scale to modify the number of replicas. For example, given a Gateway that has 1 replica, the following will increase the number of replicas to 4.

$ kubectl scale scg my-gateway --replicas=4

And to decrease the number back to the original value.

$ kubectl scale scg my-gateway --replicas=1

In initial configuration, you can specify the number of replicas using the spec.count parameter. The following example configures a replica count of 3.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  count: 3

So long as no other changes are introduced in the descriptor, you can safely modify spec.count and re-apply to increase or decrease the number of replicas.

To verify your changes use kubectl get pods to check that the pods match the count number.

Configure TLS termination

You can configure gateway instances to perform TLS termination, using different certificates for different routes.

Certificates and their associated private keys are loaded from Kubernetes TLS secrets. Create a TLS type secret for each certificate you would like the Gateway to serve. The easiest way to do this is with kubectl and PEM encoded certificate and key files:

kubectl create secret tls my-tls-secret-name --cert=path/to/tls.crt --key=path/to/tls.key

The tls.crt file can contain multiple CA certificates concatenated together with the server certificate to represent a complete chain of trust.

The tls.key file should contain the private key for the server certificate in PKCS#8 or PKCS#1 format.

Next, create a Gateway resource which references your TLS certificates. Each entry in the spec.tls array contains a secretName which references the TLS secret containing the certificate(s)/key pair you want to serve, and a list of hosts. When a request arrives at the gateway referencing one of these hosts, the gateway will serve the certificate from the matching secret.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: test-gateway-tls
spec:
  count: 1
  tls:
    - hosts:
        - host-a.my-tls-gateway.my-example-domain.com
        - host-b.my-tls-gateway.my-example-domain.com
      secretName: tls-secret-1
    - hosts:
        - host-c.my-tls-gateway.my-example-domain.com
        - host-d.my-tls-gateway.my-example-domain.com
      secretName: tls-secret-2

The client with which you make requests to your gateway must support Server Name Indication, in order to pass the requested host to the gateway as part of the TLS handshake.

To verify that everything is working as expected, you can use openssl to check the certificates that are returned for each of the configured hosts. For example:

openssl s_client -showcerts -servername host-a.my-tls-gateway.my-example-domain.com -connect <your ingress ip>:443 | openssl x509 -text

where <your ingress ip> should be replaced with the external IP of your TLS passthrough enabled ingress.

Configure Environment Variables

You can define a map of environment variables to configure the API gateway using the spec.env property. The following example configure the connection timeout from API gateway to application services and the Spring Framework web package logging level.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: gateway-demo
spec:
  ...
  env:
    - name: spring.cloud.gateway.httpclient.connect-timeout
      value: "90s"
    - name: logging.level.org.springframework.web
      value: debug

Configure Cross-Origin Resource Sharing (CORS)

You can define a global CORS behavior that will be applied to all route configurations mapped to it.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  api:
    cors:
      allowedOrigins:
        - "https://foo.example.com"
      allowedMethods:
        - "GET"
        - "PUT"
        - "POST"

The following parameters can be configured in the spec.api.cors block:

Parameter Function Example
allowedOrigins Allowed origins to make cross-site requests. The special value "*" allows all domains. allowedOrigins: https://example.com
allowedMethods Allowed HTTP methods on cross-site requests. The special value "*" allows all methods. If not set, "GET" and "HEAD" are allowed by default. allowedMethods:
  - GET
  - PUT
  - POST
allowedHeaders Allowed headers in cross-site requests. The special value "*" allows actual requests to send any header. allowedHeaders:
  - X-Custom-Header
maxAge How long, in seconds, the response from a pre-flight request can be cached by clients. maxAge: 300
allowCredentials Whether user credentials are supported on cross-site requests. Valid values: `true`, `false`. allowCredentials: true
exposedHeaders HTTP response headers to expose for cross-site requests. exposedHeaders:
  - X-Custom-Header

You can also configure CORS behavior per route. However, the global CORS configuration must not be set. Each route defined on the gateway should have a matching path predicate on the route config. The example below configures CORS behavior for the /get/** and /example/** routes:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  api:
    cors:
      perRoute:
        '[/get/**]':
          allowedOrigins:
            - "https://foo.example.com"
          allowedMethods:
            - "GET"
            - "PUT"
            - "POST"
        '[/example/**]':
          allowedOrigins:
            - "https://bar.example.com"
          allowedMethods:
            - "GET"
            - "POST"

Each route can be configured with the same parameters as in the table above.

Here is a matching route config:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGatewayRouteConfig
metadata:
  name: my-gateway-routes
spec:
  routes:
    - uri: https://httpbin.org
      predicates:
        - Path=/get/**
      filters:
        - StripPrefix=1
    - uri: https://httpbin.org
      predicates:
        - Path=/example/**
      filters:
        - StripPrefix=1

Configure Java Environment Options

For JVM tuning it is possible to define Java Environment Options (JAVA_OPTS) in the Spring Cloud Gateway for K8s configuration.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  count: 2
  java-opts: -XX:+PrintFlagsFinal -Xmx512m

This will restart the pods and apply the options to the underlying gateway instances.

Configure session expiration

If you need to be able to discard inactive sessions after a certain time (e.g 10 minutes), just add the inactive-session-expiration-in-minutes configuration.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  sso:
    secret: my-sso-credentials
    inactive-session-expiration-in-minutes: 10

This does not modify any authorization server token expiration (or ttl) configuration. It only affects the session information managed inside the gateway.

Configuring Hardware Resources

Similarly to other Kubernetes resources, you can optionally define the required memory (RAM) and CPU for a Gateway under spec.resources.

By default each instance is initialized with:

Resource Requested Limit
Memory 256Mi 512Mi
CPU 500m 2

But you can change it as seen in the example below. Note that less than the required may cause issues and is not recommended.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  resources:
    requests:
      memory: "512Mi"
      cpu: "1"
    limits:
      memory: "1Gi"
      cpu: "2"

Configure Observability

Spring Cloud Gateway for Kubernetes can be configured expose tracing and to generate a set of metrics and tracings based on different monitoring signals to help with understanding behaviour in aggregate.

Note: Metrics and Tracing are independent from each other.

Exposing Metrics to Wavefront

To expose metrics to Wavefront we need to create a Secret with the following data: wavefront.api-token and wavefront.uri, representing Wavefront's API token and Wavefront's URI endpoint respectively. For example:

apiVersion: v1
kind: Secret
metadata:
  name: metrics-wavefront-secret
data:
  wavefront.api-token: "NWU3ZCFmNjYtODlkNi00N2Y5LWE0YTMtM2U3OTVmM2Y3MTZk"
  wavefront.uri: "aHR0cHM6Ly92bAdhcmUud2F2ZWZyb250LmNvbQ=="

Then, in the SpringCloudGateway kind, reference the secret created in the step before under the metrics section. For example:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: test-gateway-metrics
spec:
  observability:
    metrics:
      wavefront:
        enabled: true
    wavefront:
      secret: metrics-wavefront-secret
      source: my-source
      application: my-shopping-application
      service: gateway-service

After applying the configuration, Wavefront will start receiving the metrics provided by default by Spring Cloud Gateway.

Note: If you are also using wavefront for tracing, ensure you specify the same secret and source in both specs.

Using the Spring Cloud Gateway for Kubernetes Dashboard for Wavefront

Spring Cloud Gateway for Kubernetes has a pre-built dashboard you can use in Wavefront.

If you are using VMware's Wavefront, then you can clone and customize the already created Spring Cloud Gateway for Kubernetes Dashboard.

Alternatively, the Spring Cloud Gateway for Kubernetes release artifacts contain a dashboard that can be found inside the dashboards release folder.

To import it, we need to create an API Token and execute the following command:

curl -XPOST 'https://vmware.wavefront.com/api/v2/dashboard' --header "Authorization: Bearer ${WAVEFRONT_API_TOKEN}" --header "Content-Type: application/json" -d "@wavefront-spring-cloud-gateway-for-kubernetes.json"

Exposing Metrics to Prometheus

To expose metrics to Prometheus we need to add a prometheus section in the SpringCloudGateway kind and if we want scrapping annotations to be added into the gateway pods, for example:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: test-gateway-metrics
spec:
  observability:
    metrics:
      prometheus:
        enabled: true

After applying the configuration, the Prometheus actuator endpoint will be available.

If, in addition to this, we want the scrapping annotations to be added to all the Spring Cloud Gateway Pods, we should create our Prometheus connfigurations with annotations set to true, for example:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: test-gateway-metrics-with-annotations
spec:
  observability:
    metrics:
      prometheus:
        enabled: true
        annotations:
          enabled: true

This will add the following annotations to every Spring Cloud Gateway Pod:

   annotations:
     prometheus.io/scrape: "true"
     prometheus.io/path: "/actuator/prometheus"
     prometheus.io/port: "8090"

Using the Spring Cloud Gateway for Kubernetes Dashboard for Grafana

Spring Cloud Gateway for Kubernetes release artifacts contains a Grafana dashboard that can be found inside the dashboards release folder. To import it you can follow the how to import guide.

Exposing Tracing to Wavefront

To expose tracing to Wavefront we need to create a Secret with the following data: wavefront.api-token and wavefront.uri, representing Wavefront's API token and Wavefront's URI endpoint respectively. For example:

apiVersion: v1
kind: Secret
metadata:
  name: tracing-wavefront-secret
data:
  wavefront.api-token: "NWU3ZCFmNjYtODlkNi00N2Y5LWE0YTMtM2U3OTVmM2Y3MTZk"
  wavefront.uri: "aHR0cHM6Ly92bAdhcmUud2F2ZWZyb250LmNvbQ=="

Then, in the SpringCloudGateway kind, reference the secret created in the step before under the tracing section. For example:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: test-gateway-tracing
spec:
  observability:
    tracing:
      wavefront:
        enabled: true
    wavefront:
      secret: tracing-wavefront-secret
      source: my-source
      application: my-shopping-application
      service: gateway-service

After applying the configuration, Wavefront will start receiving the traces

Note: If you are also using wavefront for metrics, ensure you specify the same secret and source in both specs.

Applying custom labels to the Gateway Pods

Custom labels can be added to the Gateway configuration. These labels will be propagated to the Pods created by the gateway operator For example:

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: test-gateway-tracing
  labels:
    test-label: test
spec:
  count: 2

Then the Pods can be listed by specifying the label:

 kubectl get pods -l test-label=test
check-circle-line exclamation-circle-line close-line
Scroll to top icon