Note: This document is for users who are looking to understand the underlying APIs involved in making a bindable service instance using
SQLInstance
,SQLDatabase
,SQLUser
andSecretTemplate
resources. For a simpler user experience, the alternative Creating an CloudSQL service instance through a Carvel Package topic is recommended.
Meet the prerequisites and keep the following information to hand:
NAT-IP
- the cluster’s egress NAT IPAt a minimum, a useable database instance consists of a SQLInstance
, a SQLDatabase
, and a SQLUser
.
Realistically, in addition to that we will also want another set of Secrets
:
Secret
per SQLInstance
to hold the password for the instance’s admin roleSecret
per SQLUser
to hold that user’s passwordIn the simplest case, with one SQLInstance
, one SQLDatabase
, and one SQLUser
, we need to manage the following set of interrelated resources:
Secrets
for the Database admin & userFirst we need to ensure that the Secrets
which hold the admin’s and user’s password exist, so we can reference them in the SQLInstance
and SQLUser
objects.
Those secrets can be created by any means. In this guide will leverage the Password
API from Carvel’s secretgen controller, which will create the Secrets
for us. However, any other mechanism to manage those secrets works too.
kind: List
apiVersion: v1
items:
- kind: Password
apiVersion: secretgen.k14s.io/v1alpha1
metadata:
name: sql-admin-creds
namespace: service-instances
spec: &passwordSpec
length: 64
secretTemplate:
type: Opaque
stringData:
password: $(value)
- kind: Password
apiVersion: secretgen.k14s.io/v1alpha1
metadata:
name: sql-user-creds
namespace: service-instances
spec: *passwordSpec
Applying this will create two Passwords
which in turn will have two Secrets
created:
kubectl -n service-instances get passwords,secrets sql-user-creds sql-admin-creds
NAME DESCRIPTION AGE
password.secretgen.k14s.io/sql-user-creds Reconcile succeeded 4m41s
password.secretgen.k14s.io/sql-admin-creds Reconcile succeeded 4m41s
NAME TYPE DATA AGE
secret/sql-user-creds Opaque 1 4m41s
secret/sql-admin-creds Opaque 1 4m41s
Now we can reference those two secrets and use the Config Connector APIs to create our database objects:
Note: You need to allow access from the Kubernetes cluster’s NAT IP. You can get the NAT IP via the command described in the prerequisites. This NAT IP then needs to be used in the
SQLInstance
’sspec.settings.ipConfiguration.authorizedNetworks
.
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLInstance
metadata:
name: sql-instance
namespace: service-instances
spec:
databaseVersion: POSTGRES_14
#! If you have deployed your cluster into a different region, you might want
#! to change this and deploy the SQLInstance into the same region as the
#! cluster, to avoid traffic going across regions.
region: europe-west6
rootPassword:
valueFrom:
secretKeyRef:
key: password
name: sql-admin-creds
settings:
tier: db-g1-small
ipConfiguration:
authorizedNetworks:
- name: cluster-NAT-IP
#! Update this value with your NAT IP address in CIDR notation (e.g. 8.8.8.8/32). See above.
value: <NAT-IP>
ipv4Enabled: true
---
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLDatabase
metadata:
name: sql-database
namespace: service-instances
spec:
charset: UTF8
collation: en_US.UTF8
instanceRef:
name: sql-instance
---
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLUser
metadata:
name: sql-user
namespace: service-instances
spec:
instanceRef:
name: sql-instance
password:
valueFrom:
secretKeyRef:
key: password
name: sql-user-creds
Once those objects are committed to the Kubernetes API, the Config Connector will cause the creation of those resources on GCP. This will take a short amount of time.
The three resources report their status and potential problems/errors back. If all goes well we should see all of those resources as “Ready” & “UpToDate” after a couple of minutes.
# kubectl -n service-instances get sqlinstance,sqldatabase,sqluser
NAME AGE READY STATUS STATUS AGE
sqlinstance.sql.cnrm.cloud.google.com/sql-instance 3d20h True UpToDate 3d20h
NAME AGE READY STATUS STATUS AGE
sqldatabase.sql.cnrm.cloud.google.com/sql-database 3d20h True UpToDate 3d20h
NAME AGE READY STATUS STATUS AGE
sqluser.sql.cnrm.cloud.google.com/sql-user 3d20h True UpToDate 3d20h
You can also see this Cloud SQL instance in the Google Cloud Console.
Note: Cloud SQL does not allow you to reuse the name of a deleted instance for a week. If you try to create a new
SQLInstance
with a name you have already used previously, you will see an error likeNote[…] When you delete an instance, you can’t reuse the name of the deleted instance until one week from the deletion date. […]
You can use a different name for the
SQLInstance
; make sure to use replace that name in all examples going forward.
As pointed out, none of the created objects are compatible with the Service Binding Specification. To help with that, we can create a secret which holds the data we need to know to connect to and use the Cloud SQL instance and which allows the platform to discover the fact that this instance can be “claimed” and “bound” to application workloads.
For this to be an automated process, we can use the SecretTemplate
API of the secretgen controller. The secretgen controller needs to be able to read the resources created, thus we also need to deploy some RBAC rules to allow for that:
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretTemplate
metadata:
name: sql-instance-claimable
namespace: service-instances
spec:
inputResources:
- name: sqlInstance
ref:
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLInstance
name: sql-instance
- name: sqlDatabase
ref:
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLDatabase
name: sql-database
- name: sqlUser
ref:
apiVersion: sql.cnrm.cloud.google.com/v1beta1
kind: SQLUser
name: sql-user
- name: sqlUserSecret
ref:
apiVersion: v1
kind: Secret
name: $(.sqlUser.spec.password.valueFrom.secretKeyRef.name)
serviceAccountName: sql-objects-reader
template:
data:
password: $(.sqlUserSecret.data.password)
metadata:
labels:
app.kubernetes.io/component: cloudsql-postgres
app.kubernetes.io/instance: "$(.sqlInstance.metadata.name)"
services.apps.tanzu.vmware.com/class: cloudsql-postgres
stringData:
database: $(.sqlDatabase.metadata.name)
host: $(.sqlInstance.status.publicIpAddress)
port: "5432"
type: postgresql
username: $(.sqlUser.metadata.name)
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: sql-objects-reader
namespace: service-instances
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: sql-objects-reader
namespace: service-instances
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: sql-objects-reader
subjects:
- kind: ServiceAccount
name: sql-objects-reader
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: sql-objects-reader
namespace: service-instances
rules:
- apiGroups: [ "" ]
resources: [ "secrets" ]
verbs: &objReaderVerbs [ "get", "list", "watch" ]
resourceNames: [ "sql-user-creds", "sql-admin-creds" ]
- apiGroups: [ "sql.cnrm.cloud.google.com" ]
resources: [ "sqlinstances", "sqldatabases", "sqlusers" ]
verbs: *objReaderVerbs
resourceNames: [ "sql-instance", "sql-database", "sql-user" ]
Find the name of the secret produced by reading the status of SecretTemplate
. To do so, run:
kubectl get secrettemplate -n service-instances sql-instance-claimable -o jsonpath="{.status.secret.name}"
Delete an CloudSQL service instance and all additional and related objects by running:
kubectl -n service-instances delete \
sqlinstance/sql-instance \
sqldatabase/sql-database \
sqluser/sql-user \
secrettemplate/sql-instance-claimable \
password/sql-admin-creds \
password/sql-user-creds \
serviceaccount/sql-objects-reader \
rolebinding/sql-objects-reader \
roles/sql-objects-reader
You have learned how to use Carvel’s SecretTemplate
API to construct a secret that is compatible with the binding specification in order to create an Google CloudSQL service instance.
Now that you have this available in the cluster, you can learn how to make use of it by continuing where you left off in Consuming Google Cloud SQL on Tanzu Application Platform (TAP) with Config Connector.