This topic describes how to enable Tanzu Application Platform (TAP) or Tanzu Application Services (TAS) applications to connect and utilize VMware Postgres Operator database services.
The Postgres API provided by VMware Postgres Operator adheres to the Kubernetes Service Binding specification which allows Postgres to be a Provisioned Service for Tanzu Application Platform (TAP) applications. This allows VMware Postgres Operator instances to be part of TAP Service Offerings, via the Services Toolkit, that eliminates the manual management of the configuration steps needed to securely, and successfully bind a TAP Workload to a VMware Postgres Operator deployment.
This feature adds the .status.binding.name
field in the VMware Postgres Operator API, which points to a Secret
in the same namespace. The Secret
contains required credentials and connectivity information for the resource.
This topic covers the steps to provision VMware Postgres Operator using a TAP workload. For a similar process and updated TAP information, refer to Consuming services on Tanzu Application Platform.
The Services Toolkit offers a set of modular tools used to provide a self-service experience to application owners, who require Service Resources running on Tanzu.
Review Service Resource Claims for details on ResourceClaim
, ResourceClaimPolicy
, and RBAC ClusterRole
.
The Services Toolkit controller manager requires permissions to access Postgres resources. Create a ClusterRole
with the Role-based access control (RBAC), and save it in a file like resource-claims-postgres.yaml
:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: resource-claims-postgres
labels:
servicebinding.io/controller: "true"
rules:
- apiGroups: ["sql.tanzu.vmware.com"]
resources: ["postgres"]
verbs: ["get", "list", "watch"]
and then run:
kubectl apply -f resource-claims-postgres.yaml
The Services Toolkit will now be able to claim Postgres instances.
To make the Postgres instances discoverable via the Services Toolkit, create a ClusterInstanceClass
that refers to the Postgres API and save it in a file like cluster-instance-class-postgres.yaml
:
---
apiVersion: services.apps.tanzu.vmware.com/v1alpha1
kind: ClusterInstanceClass
metadata:
name: postgres
spec:
description:
short: It's a Postgres database!
pool:
group: sql.tanzu.vmware.com
kind: Postgres
and then run:
kubectl apply -f cluster-instance-class-postgres.yaml
Use the Services Toolkit plugin command tanzu service claimable list --class postgres
to return the previously created Postgres instance.
(Optional) If you are consuming the Postgres instance from a Workload
in another namespace, you will have to enable cross-namespace claims via a ResourceClaimPolicy
. If your Postgres instance resides in the default
namespace, save the following in a file like resource-claim-policy-postgres.yaml
:
---
apiVersion: services.apps.tanzu.vmware.com/v1alpha1
kind: ResourceClaimPolicy
metadata:
name: postgres-cross-namespace
namespace: default
spec:
consumingNamespaces:
- '*' # consumable from all namespaces
subject:
group: sql.tanzu.vmware.com
kind: Postgres
and then run:
kubectl apply -f resource-claim-policy-postgres.yaml
Resource Claims allow Application teams to "claim" resources, and Service Operators to provide resources to be "claimed". This provides a self-service experience for the developer, but gives the Service Operators ultimate control of the Service Resources.
To claim a Postgres instance:
Find the information needed to make a resource claim by running:
tanzu service claimable list --class postgres
#! `--class` is the name of the ClusterInstanceClass defined in the previous step
With an output similar to:
NAME NAMESPACE KIND APIVERSION
POSTGRES-NAME default Postgres sql.tanzu.vmware.com/v1
where POSTGRES-NAME
is the name of the previously created Postgres instance.
See Discover claimable service instances for more information on the different flags and options available.
Create a claim for the Postgres instance from the namespace of your Workload
by running:
tanzu service claims create CLAIM-NAME \
--resource-name POSTGRES-NAME \
--resource-namespace default \
--resource-kind Postgres \
--resource-api-version sql.tanzu.vmware.com/v1 \
--namespace WORKLOAD_NAMESPACE
where:
POSTGRES-NAME
is the name of the previously created Postgres instance.CLAIM-NAME
is the name you want to give to the resource claim instance.WORKLOAD_NAMESPACE
is the namespace of your Workload
.The next section shows how to inspect the claim and use it to bind to an application Workload
.
Use tanzu service claims create --help
for further usage and help information.
This topic covers:
To create an application Workload
bound to a Postgres instance:
Inspect the claims in your workload namespace to find the value to pass to --service-ref
command by running:
tanzu services claims list -n default
Expected output:
NAME READY REASON
CLAIM-NAME True Ready
Where CLAIM-NAME
is the name of the previously created resource claim instance.
See Listing and getting Resource Claims for more information on the different flags and options available.
Retrieve detailed information about the claim by running:
tanzu services claims get CLAIM-NAME
where CLAIM-NAME
is the name of the previously created resource claim instance.
The output is similar to:
Name: CLAIM-NAME
Status:
Ready: True
Namespace: default
Claim Reference: services.apps.tanzu.vmware.com/v1alpha1:ResourceClaim:CLAIM-NAME
Resource to Claim:
Name: POSTGRES-NAME
Namespace: default
Group: sql.tanzu.vmware.com
Version: v1
Kind: Postgres
Where:
POSTGRES-NAME
is the name of the previously created Postgres instance.CLAIM-NAME
is the name of the previously created resource claim instance.See Listing and getting Resource Claims for more information on the different flags and options available.
Record the value of Claim Reference
and pass it to --service-ref
to create the application Workload
by running:
tanzu apps workload create WORKLOAD-NAME [create flags] \
--service-ref "db=services.apps.tanzu.vmware.com/v1alpha1:ResourceClaim:CLAIM-NAME" \
--annotation autoscaling.knative.dev/minScale=1
where:
WORKLOAD-NAME
is the name that will be given to the workload.--service-ref
is the reference to the service using the format {key-name}={apiVersion}:{kind}:{instance-name}
.
CLAIM-NAME
is the name of the previously created resource claim instance.key-name
is a unique name given to service binding for the Workload.--annotation
value of autoscaling.knative.dev/minScale: "1"
prevents the auto-scaling down of pods done by the TAP components. This can help with debugging the Workload
.See Tanzu apps workload create for more information on the different flags and options available.
You can also create a Workload
yaml file where you can specify environment variables, build parameters, etc. that are required by your application to be built and run successfully. The example Workload
yaml below shows a spring-petclinic application that binds to a claim of a Postgres instance via a resource claim claim-1
.
---
apiVersion: carto.run/v1alpha1
kind: Workload
metadata:
name: pet-clinic
labels:
apps.tanzu.vmware.com/workload-type: web
app.kubernetes.io/part-of: pet-clinic
apps.tanzu.vmware.com/has-tests: "true"
spec:
params:
- name: annotations
value:
autoscaling.knative.dev/minScale: "1"
build:
env:
- name: BP_MAVEN_POM_FILE
value: skip-pom.xml
env:
- name: SPRING_PROFILES_ACTIVE
value: postgres
serviceClaims:
- name: db
ref:
apiVersion: services.apps.tanzu.vmware.com/v1alpha1
kind: ResourceClaim
name: CLAIM-NAME
source:
git:
ref:
branch: main
url: https://github.com/spring-projects/spring-petclinic
where:
BP_MAVEN_POM_FILE
needs to be set to some non-existent value (in this example, skip-pom.xml
) in order to build the upstream spring-petclinic app correctly. Refer to this open issue for more details.SPRING_PROFILES_ACTIVE
is set to Postgres to override the default application configuration.CLAIM-NAME
is claim-1
for this example.autoscaling.knative.dev/minScale: "1"
prevents the auto-scaling down of Pod
s done by the TAP components. This can help with debugging the Workload
.Save the above content in workload.yaml
file and then run kubectl apply -f workload.yaml
IMPORTANT: This example creates a workload with the sample Spring application spring-petclinic that is available on GitHub. The sample application is subject to change and may face issues during build and run steps in the TAP workflow. Consider specifying a commit sha to use an older state of the sample application as needed for demo and test purposes.
To update an existing TAP Workload
to connect and utilize a Postgres database instance, run a command similar to:
tanzu apps workload update WORKLOAD-NAME [update flags] --service-ref "db=services.apps.tanzu.vmware.com/v1alpha1:ResourceClaim:CLAIM-NAME"
where:
WORKLOAD-NAME
is the name of the Workload
.Workload
from source control, registry image, or local file.--service-ref
is the reference to the service using the format {key-name}={apiVersion}:{kind}:{name}
.
CLAIM-NAME
is the name of the previously created resource claim instance.key-name
is a unique name given to service binding for the Workload
.For example:
tanzu apps workload update pet-clinic --service-ref "db=services.apps.tanzu.vmware.com/v1alpha1:ResourceClaim:claim-1"
See Tanzu apps workload update for more information on the different flags available.
To check if the application has been successfully bound to the VMware Postgres Operator instance:
Check that the corresponding ResourceClaim
object is ready. The ResourceClaim
name follows the format <.metadata.name>-<.spec.serviceClaim[0].name>
as given in the Workload
yaml as shown above. In this example, it would be pet-clinic-db
.
kubectl get resourceclaims pet-clinic-db
NAME READY REASON
resourceclaim.services.apps.tanzu.vmware.com/pet-clinic-db True
Query the database using the Postgres application user .spec.pgConfig.appUser
.
Fetch the corresponding credentials and connection details from the Secret referenced in .status.binding.name field in the instance CR. With a Postgres called postgres-sample
, the Secret would be postgres-sample-app-user-db-secret
and the data can be verified in the postgres-sample
database.
dbname=$(kubectl get secrets postgres-sample-app-user-db-secret -o jsonpath='{.data.database}' | base64 -D)
username=$(kubectl get secrets postgres-sample-app-user-db-secret -o jsonpath='{.data.username}' | base64 -D)
password=$(kubectl get secrets postgres-sample-app-user-db-secret -o jsonpath='{.data.password}' | base64 -D)
host=$(kubectl get secrets postgres-sample-app-user-db-secret -o jsonpath='{.data.host}' | base64 -D)
port=$(kubectl get secrets postgres-sample-app-user-db-secret -o jsonpath='{.data.port}' | base64 -D)
Using the spring-petclinic app, use a psql
query similar to:
PGPASSWORD=$password psql -h $host -p $port -d $dbname -U $username
which should return an output similar to:
psql (14.2 (VMware Postgres 14.2.0))
Type "help" for help.
my-postgres=# SELECT COUNT(1) from vets;
count
-------
6
(1 row)
LoadBalancer
. See Deploying a Postgres Instance.Export the environment variables $dbname
, $username
, $password
, $host
, and $port
, described in Accessing Postgres with External Clients.
(Optional) From your computer validate that the Postgres instance is reachable from the location where TAS is deployed, by using a command similar to:
# create a CF SSH tunnel, this will hang and you need to leave it open until you're done with this step
cf ssh <appname> -L 54320:$host:$port
which returns similar to:
vcap@f00949bd-6601-4731-6f7e-e859:~$
where f00949bd-6601-4731-6f7e-e859
is an example GUID. In a new window or tab, use psql
to test the connection:
PGPASSWORD=$password psql -h 127.0.0.1 -p 54320 -U $username -d $dbname
psql (11.13 (VMware Postgres 11.13.1))
Type "help" for help.
postgres-sample=#
Choose a name and create the user provided service:
cf create-user-provided-service my-postgres-instance -p "{\"uri\":\"postgres://$username:$password@$host:$port/$dbname?sslmode=require\"}"
For more details, see User-Provided Service Instances.
Bind, restage, and use the service as you would normally with a "cf marketplace" provisioned SQL instance. See Bind a Service Instance to an App for an example of this process, and Restage Your App.
Like any data service, the application will automatically connect to the database instance depending on the buildpack. If autoconnect is not supported, the application will have to manually make use of the uri
service credential to make a connection.
Bound service credentials are available at runtime to TAS applications via the DATABASE_URL
and VCAP_SERVICES
environment variables. For further details see DATABASE_URL in TAS for VMs Environment Variables documentation.