Configure Spring Cloud Gateway Instances

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)
spec:
  count:           # Number of container instances (pods) to scale Gateway for high availability (HA) configuration
  sso:
    secret:        # Secret name to be used for SSO configuration
    roles-attribute-name:
                   # Roles attribute name used to filter user attributes
    inactive-session-expiration-in-minutes:
                  # Time to life of inactive sessions in minutes, 0 means sessions won't expire.
  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

  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

  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:

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:
    spring.cloud.gateway.httpclient.connect-timeout: "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/v1beta1 
    kind: Ingress 
    metadata: 
      name: my-gateway-ingress
      namespace: my-namespace
      annotations: 
        kubernetes.io/ingress.class: contour 
    spec: 
      rules: 
        - host: my-gateway.spring.animalrescue.online 
          http: 
            paths: 
              - backend: 
                  serviceName: my-gateway 
                  servicePort: 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 that 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.spring.animalrescue.online     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.spring.animalrescue.online   
                                               /   my-gateway:80 () 
    

    As the example output shows, the my-gateway.spring.animalrescue.online 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.spring.animalrescue.online) 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.spring.animalrescue.online 
    

    For extended evaluation, you might create a wildcard DNS A record that maps any virtual host on the domain name (for example, *.spring.animalrescue.online) 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.spring.animalrescue.online/github
    $ http my-gateway.spring.animalrescue.online/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.spring.animalrescue.online/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.spring.animalrescue.online/github, you will be redirected to the SSO login page. After authenticating, you will be redirected to the GitHub home page.

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 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

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 OpenAPI Metadata

Spring Cloud Gateway for Kubernetes exposes part of its configurations and available endpoints using OpenAPI format. This way you can use API management tools to monitor and validate the status of routes, including API portal for VMware Tanzu.

You can access to the exposed information at the /openapi endpoint on the Spring Cloud Gateway operator service. The information available is an list of managed gateways and its respective routes. For each one:

  • API Gateway metadata information: serverUrl, title, description, version and documentation url for each of the gateways.
  • Paths: list of available routes. For each one, available HTTP methods, headers and a description of the request body objects (if defined in the route configuration).

Gateway(s) Metadata

As seen at the beginning, you can add the following descriptive metadata while configuring Spring SpringCloudGateway for k8s.

  • serverUrl: Publicly accessible user-facing URL of this Gateway instance. It is important to note that this configuration does not create an ingress for this URL, this is only for metadata purposes to display in the OpenAPI generated documentation.
  • 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.)
  • version: Version of APIs available on this Gateway instance (default: unspecified)
  • documentation: Location of additional documentation for the APIs available on the Gateway instance
apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
  name: my-gateway
spec:
  api:
    serverUrl: https://gateway.example.org
    title: My Exciting APIs
    description: Lots of new exciting APIs that you can use for examples!
    version: 0.1.0
    documentation: https://docs.example.org

This will be displayed in the /openapi endpoint of the operator as:

"info": {
  "title": "My Exciting APIs",
  "description": "Lots of new exciting APIs that you can use for examples!",
  "version": "0.1.0"
},
"externalDocs": {
  "url": "https://docs.example.org"
},
"servers": [
  {
    "url": "https://gateway.example.org"
  }
],

PUT/POST Request Body Schema

For PUT and POST operations, you may add the OpenAPI Schema of Request Body objects.

As in the example below, add model.requestBody property to a route with the proper information.

apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGatewayRouteConfig
metadata:
  name: myapp-route-config
spec:
  service:
    name: myapp-service
  routes:
    - id: example-route-id
      predicates:
        - Path=/users/**
      model:
        requestBody:
          description: User to add to the system
          content:
            'application/json':
              schema:
                type: object
                description: User schema
                properties:
                  name:
                    type: string
                  age:
                    type: integer
                    format: int32
                required:
                  - name

The model, alongside with the available HTTP methods and headers will be published under paths.

"paths": {
    "/example/**": {
        "summary": "example-route-id",
        "get": {
            "responses": {
                "200": {
                    "description": "Ok"
                }
            }
        },
        "post": {
            "requestBody": {
                "description": "User to add",
                "content": {
                    "application/json": {
                        "schema": {
                            "required": [
                                "name"
                            ],
                            "type": "object",
                            "properties": {
                                "name": {
                                    "type": "string"
                                },
                                "age": {
                                    "type": "integer",
                                    "format": "int32"
                                }
                            },
                            "description": "User schema"
                        }
                    }
                }
            },
            "responses": {
                "200": {
                    "description": "Ok"
                }
            }
        }