Tanzu Application Platform operators can configure Namespace Provisioner to automatically provision Spring Cloud Gateway for Kubernetes instances into developer namespaces.

Automatically provisioning Spring Cloud Gateway using GitOps

In this guide, we'll describe a simple GitOps approach to templating Spring Cloud Gateway resources into namespaces. Using this approach, operators can easily deploy fleets of Spring Cloud Gateway instances across multiple namespaces, with Namespace Provisioner taking care of updates by pushing changes to Git.

Setting up a GitOps repository

  1. If you don't already have one, create a Git repository to hold the resource templates you would like to add to developer namespaces. For the purposes of this guide, we'll assume the repository is github.com/my-org/tap-gitops.
  2. If the repository is private, Namespace Provisioner will need credentials in order to authenticate. We would suggest using a SSH access with a public/private key pair, although HTTPS access with a username and password is also supported.

Creating a SpringCloudGateway CR template

  1. To get started, we'll create a simple SpringCloudGateway custom resource to be templated into namespaces:

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

    For more advanced requirements, please consult the SpringCloudGateway resource page and Namespace Provisioner templating guide for thorough descriptions of the resource and available templating options.

  2. Save your template to a file and add it to a well-known path within your local clone of the GitOps Git repository. For example, we will use the path namespace-provisioner-templates/spring-cloud-gateway/spring-cloud-gateway-cr.yaml.

  3. Commit the template and push to the remote GitOps repository

Setting up Git authentication

If your GitOps repository is private, then Namespace Provisioner will need credentials in order to authenticate with it and pull down your template changes. In this example we'll assume that access to the repository will be through SSH, so Namespace Provisioner will need a private key. This will be read from a Secret in the tap-namespace-provisioning namespace. In this example we'll call the Secret gitops-secret. To create it from a private key stored locally in a file called id_gitops, run:

kubectl create secret generic gitops-secret --from-file=ssh-privatekey=id_gitops --namespace tap-namespace-provisioning

Other authentication options are supported if required.

Configuring Namespace Provisioner

Next, we need to tell Namespace Provisioner about our GitOps repo and Secret, and also which namespaces to apply the templates to.

This is done by merging the following YAML fragment into tap-values.yaml, after adapting it to your environment:

namespace_provisioner:
  controller: true #1
  namespace_selector: #2
    matchExpressions:
      - key: apps.tanzu.vmware.com/tap-ns
        operator: Exists
  additional_sources:
    - git:
        url: [email protected]:my-org/tap-gitops.git #3
        ref: origin/main #4
        secretRef:
          name: gitops-secret #5
        subPath: namespace-provisioner-templates/spring-cloud-gateway #6
      path: _ytt_lib/spring-cloud-gateway #7

The numbered items, which may need to be adapted to your needs, are described fully in the Namespace Provisioner documentation, but in brief:

  1. Setting controller: true instructs Namespace Provisioner to watch the cluster for namespaces to provision. This is the default mode of operation.
  2. The namespace_selector is used to define the rules by which Namespace Provisioner will identify namespaces to provision. In this case, we're declaring that any namespace with the label apps.tanzu.vmware.com/tap-ns applied should be provisioned.
  3. Here we add our [email protected]:my-org/tap-gitops.git Git repository to the array of additional_sources for templates to provision.
  4. ref specifies the branch within the Git repository containing the templates.
  5. The secretRef.name key is used to locate the Secret containing the Git repository credentials, and must match the name of the Secret we created earlier for this purpose.
  6. subPath identifies the subdirectory within the Git repository that contains the templates. This is useful to organise larger repositories which may contain many templates.
  7. path identifies the ytt library the templates will be added to. The path of each additional source must be unique, and begin with the _ytt_lib prefix.

Once the updates to tap-values.yaml have been made locally, these need to be applied to the cluster by updating the tap package:

tanzu package installed update tap --values-file tap-values.yaml --namespace tap-install

Setting up the namespace

Lastly, we need to identify the namespace(s) that Namespace Provisioner should apply the templates to. In the previous step we configured Namespace Provisioner to watch for any namespace with the label apps.tanzu.vmware.com/tap-ns, so we need to apply that label to our namespaces:

kubectl create namespace my-namespace-with-api-gateway
kubectl label namespace my-namespace-with-api-gateway apps.tanzu.vmware.com/tap-ns=""

The label can have any value, even the empty value ("").

Checking the results

Once everything has reconciled, you should see the results of the SpringCloudGateway CR being applied to the developer namespace. Alongside the CR itself, you will also find the other components that are created and managed by the Spring Cloud Gateway operator as a result:

$ kubectl --namespace my-namespace-with-api-gateway get all,springcloudgateway

NAME                 READY   STATUS    RESTARTS   AGE
pod/api-gateway-0    1/1     Running   0          2m31s

NAME                            TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)             AGE
service/api-gateway             ClusterIP   10.0.223.96   <none>        80/TCP              3m
service/api-gateway-headless    ClusterIP   None          <none>        5701/TCP,8090/TCP   3m

NAME                            READY   AGE
statefulset.apps/api-gateway    1/1     3m

NAME                                               READY   REASON
springcloudgateway.tanzu.vmware.com/api-gateway    True    Updated

Making updates

Now everything is set up, making updates to the automatically provisioned Spring Cloud Gateway instances now involves pushing template updates to your GitOps Git repository. As an example, we can scale the number of Gateway Pods for each provisioned instance:

  1. First, update the template:

    apiVersion: "tanzu.vmware.com/v1"
    kind: SpringCloudGateway
    metadata:
      name: test-gateway
    spec:
      # count updated from 1 to 2
      count: 2
    
  2. Commit and push the template change:

    $ git add namespace-provisioner-templates/spring-cloud-gateway/spring-cloud-gateway-cr.yaml
    
    $ git commit --message 'update pod count to 2'
    [main 0a77099] update replicas to 2
    1 file changed, 1 insertion(+), 1 deletion(-)
    
    $ git push
    Enumerating objects: 7, done.
    Counting objects: 100% (7/7), done.
    Delta compression using up to 10 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (4/4), 368 bytes | 368.00 KiB/s, done.
    Total 4 (delta 1), reused 0 (delta 0), pack-reused 0
    remote: Resolving deltas: 100% (1/1), completed with 1 local object.
    To github.com:my-org/tap-gitops
      ce14145..0a77099  main -> main
    
  3. Your changes will be picked up in the next Namespace Provisioner reconciliation cycle. To trigger one immediately, you can 'kick' the application using kctrl:

    kctrl --namespace tap-namespace-provisioning app kick --app provisioner
    
  4. Once the reconciliation is complete, you will see the results of your update in your provisioned namespaces:

    ➜  gitops git:(main) k -n my-apps get all
    NAME                 READY   STATUS    RESTARTS   AGE
    pod/api-gateway-0    1/1     Running   0          13m
    pod/api-gateway-1    1/1     Running   0          14m
    
    NAME                            TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)             AGE
    service/api-gateway             ClusterIP   10.0.55.245   <none>        80/TCP              24h
    service/api-gateway-headless    ClusterIP   None          <none>        5701/TCP,8090/TCP   24h
    
    NAME                            READY   AGE
    statefulset.apps/api-gateway    2/2     24h
    

    Note the StatefulSet READY count is now showing 2, and an addtional api-gateway Pod is running.

Extending with Namespace Provisioner templates

Namespace Provisioner combined with GitOps is a powerful tool for controlled, automated provisioning of cluster resources. This simple example shows how easily Spring Cloud Gateway instances can be deployed and made ready for use by application developers, but far more advanced configurations can be built by adding further templates, and optionally making use of Namespace Provisioner's ytt templating support. For information about this templating support, see the Namespace Provisioner documentation.

Further possibilities for provisioning might include:

check-circle-line exclamation-circle-line close-line
Scroll to top icon