Tanzu Application Platform operators can configure Namespace Provisioner to automatically provision Spring Cloud Gateway for Kubernetes instances into developer namespaces.
In this guide, you will find a description of 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
.To get started, 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, see SpringCloudGateway resource and Namespace Provisioner templating for thorough descriptions and available templating options.
Save your template to a file and add it to a well-known path in your local clone of the GitOps Git repository. This example uses the path namespace-provisioner-templates/spring-cloud-gateway/spring-cloud-gateway-cr.yaml
.
Commit the template and push it to the remote GitOps repository.
If your GitOps repository is private, then Namespace Provisioner needs credentials to authenticate to it and pull down your template changes. In this example, assume that access to the repository will be through SSH, so Namespace Provisioner needs a private key. This will be read from a Secret in the tap-namespace-provisioning
namespace. In this example, the Secret is called 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, tell Namespace Provisioner about your GitOps repo and Secret, and also which namespaces to apply the templates to.
To do this, merge 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 in the sample above, which may need to be adapted to your needs, are described fully in the Namespace Provisioner documentation. 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. This example is 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 in 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 created earlier for this purpose.subPath
identifies the subdirectory in the Git repository that contains the templates. This is useful for organizing larger repositories, which might contain many templates.path
identifies the ytt library to which the templates will be added. The path
of each additional source must be unique, and begin with the _ytt_lib
prefix.After 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
Now you must identify the namespace(s) that Namespace Provisioner should apply the templates to. In the previous step, you configured Namespace Provisioner to watch for any namespace with the label apps.tanzu.vmware.com/tap-ns
, so you need to apply that label to your 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 (""
).
After 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 that everything is set up, making updates to the automatically provisioned Spring Cloud Gateway instances involves pushing template updates to your GitOps Git repository. As an example, you can scale the number of Gateway Pods for each provisioned instance, as described in this example.
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
After 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
Notice that the StatefulSet READY
count is now showing 2
, and an additional 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: