Tanzu Application Platform operators can configure Namespace Provisioner to automatically provision Spring Cloud Gateway for Kubernetes instances into developer namespaces.
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.
github.com/my-org/tap-gitops
.SpringCloudGateway
CR templateTo 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.
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
.
Commit the template and push to the remote GitOps repository
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.
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:
controller: true
instructs Namespace Provisioner to watch the cluster for namespaces to provision. This is the default mode of operation.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.[email protected]:my-org/tap-gitops.git
Git repository to the array of additional_sources
for templates to provision.ref
specifies the branch within the Git repository containing the templates.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.subPath
identifies the subdirectory within the Git repository that contains the templates. This is useful to organise larger repositories which may contain many templates.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
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 (""
).
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
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:
First, update the template:
apiVersion: "tanzu.vmware.com/v1"
kind: SpringCloudGateway
metadata:
name: test-gateway
spec:
# count updated from 1 to 2
count: 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
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
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.
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: