This topic is for users who want to understand the underlying APIs involved in making a bindable service instance using DBInstance
and SecretTemplate
resources. For a simpler user experience, see Creating an RDS service instance through a Carvel Package.
Meet the prerequisites in Consuming AWS RDS on Tanzu Application Platform (TAP) with AWS Controllers for Kubernetes (ACK) and keep the following information to hand:
DB-SUBNET-GROUP-NAME
- the name of the DBSubnetGroup
resource previously createdSECURITY-GROUP-ID
- the security group ID to use for this RDS instanceFollow these procedures to create an RDS service instance by using kubectl.
DBInstance
resourceThis example uses secret-gen to generate a Password
for the DBInstance
. You can also provide an explicit password through a Secret
.
Create Kubernetes resources on your EKS cluster by using the following example. This YAML creates the DBInstance
resource in the default
namespace.
# dbinstance.yaml
---
apiVersion: secretgen.k14s.io/v1alpha1
kind: Password
metadata:
name: rds-psql-password
namespace: default
spec:
length: 64
secretTemplate:
type: Opaque
stringData:
password: $(value) # do not edit, this will auto generate a password.
---
apiVersion: rds.services.k8s.aws/v1alpha1
kind: DBInstance
metadata:
name: rds-psql-1
namespace: default
spec:
allocatedStorage: 20
dbInstanceClass: db.t3.micro
dbInstanceIdentifier: rds-psql-1
dbName: postgres
engine: postgres
engineVersion: "14.1"
masterUsername: adminUser
masterUserPassword:
namespace: default
name: rds-psql-password
key: password
vpcSecurityGroupIDs:
- SECURITY-GROUP-ID # modify value
dbSubnetGroupName: DB-SUBNET-GROUP-NAME # modify value
# note: due to an issue in the RDS ACK controller, it is recommended to explicitly set the
# following optional spec fields.
# default values for the optional fields are provided below.
# https://github.com/aws-controllers-k8s/community/issues/1346
autoMinorVersionUpgrade: true
backupRetentionPeriod: 1
copyTagsToSnapshot: false
deletionProtection: false
licenseModel: postgresql-license
monitoringInterval: 0
multiAZ: false
preferredBackupWindow: 23:00-23:30
preferredMaintenanceWindow: wed:23:34-thu:00:04
publiclyAccessible: false
storageEncrypted: false
storageType: gp2
Where:
DB-SUBNET-GROUP-NAME
is the name of the DBSubnetGroup
resource previously createdSECURITY-GROUP-ID
is the security group ID to use for this RDS instanceRun:
kubectl apply -f dbinstance.yaml
Verify the creation status of the DBInstance
by inspecting the conditions in the Kubernetes API. To do so, run:
kubectl get DBInstance rds-psql-1 -o yaml -n default
As mentioned in Creating service instances that are compatible with Tanzu Application Platform, for Tanzu Application Platform workloads to be able to claim and bind to services such as RDS, a resource compatible with Service Binding Specification must exist in the cluster.
This can take the form of either a ProvisionedService
or a Kubernetes Secret
with some known keys. Both are defined in the specification.
The RDS DBInstance
you created does not adhere to ProvisionedService
and does not create a spec-compatible secret. So, you must create one using the resources you have available.
In this topic, you create a Kubernetes secret in the necessary format using the secret-gen tooling. You do so by using the SecretTemplate
API to extract values from the DBInstance
resource and populate a new spec-compatible secret with the values.
As part of using the SecretTemplate
API, a Kubernetes ServiceAccount
must be provided. The ServiceAccount
is used for reading the DBInstance
resource and the Secret
created from the Password
resource.
Create the following Kubernetes resources on your EKS cluster:
# secrettemplate-sa.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: rds-resources-reader
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: rds-resources-reading
namespace: default
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- watch
resourceNames:
- rds-psql-password
- apiGroups:
- rds.services.k8s.aws
resources:
- dbinstances
verbs:
- get
- list
- watch
resourceNames:
- rds-psql-1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: rds-resources-reader-to-read
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: rds-resources-reading
subjects:
- kind: ServiceAccount
name: rds-resources-reader
namespace: default
Run:
kubectl apply -f secrettemplate-sa.yaml
In combination with the ServiceAccount
you created, a SecretTemplate
can be used to declaratively create a secret that is compatible with the service binding specification.
The .spec.inputResources
fields list the resources with information needed to create the secret. The .spec.template
field defines how that information is interpolated as a secret.
To specify fields on an input resource, you can use JSONPath syntax that is very similar to kubectl syntax. The only difference is the delimiters, which are \$(
and )
instead of {
and }
.
For example, $(.rds.status.endpoint.address)
produces the host address of an RDS instance if the input resource is an ACK controller DBInstance
resource.
This syntax can currently be used in the following fields of the SecretTemplate
API:
.spec.inputResource[].ref.name
for dynamically loading input resources of the APIs of input resources previously in the list.spec.template
values for taking values from the input resources and interpolating them into the secret you createIn this case, you directly reference the DBInstance
resource and then dynamically load the secret containing the password from its specification.
You then create a Secret
conforming to the Postgres auto-configuration for Spring Cloud Bindings to enable a fully automated, end-to-end binding experience for application workloads on Tanzu Application Platform.
Create the following Kubernetes resources on your EKS cluster:
# bindable-rds-secrettemplate.yaml
---
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretTemplate
metadata:
name: rds-bindable
namespace: default
spec:
serviceAccountName: rds-resources-reader
inputResources:
- name: rds
ref:
apiVersion: rds.services.k8s.aws/v1alpha1
kind: DBInstance
name: rds-psql-1
- name: creds
ref:
apiVersion: v1
kind: Secret
name: "$(.rds.spec.masterUserPassword.name)"
template:
metadata:
labels:
app.kubernetes.io/component: rds-postgres
app.kubernetes.io/instance: "$(.rds.metadata.name)"
services.apps.tanzu.vmware.com/class: rds-postgres
type: postgresql
stringData:
type: postgresql
port: "$(.rds.status.endpoint.port)"
database: "$(.rds.spec.dbName)"
host: "$(.rds.status.endpoint.address)"
username: "$(.rds.spec.masterUsername)"
data:
password: "$(.creds.data.password)"
Run:
kubectl apply -f bindable-rds-secrettemplate.yaml
Find the name of the secret produced by reading the status of SecretTemplate
. To do so, run:
kubectl get secrettemplate -n default rds-bindable -o jsonpath="{.status.secret.name}"
Delete an RDS service instance by running:
kubectl delete DBInstance rds-psql-1 -n default
kubectl delete SecretTemplate rds-bindable -n default
kubectl delete Password rds-psql-password -n default
kubectl delete ServiceAccount rds-resources-reader -n default
kubectl delete RoleBinding rds-resources-reader-to-read -n default
kubectl delete Role rds-resources-reading -n default
You learned how to use Carvel’s SecretTemplate
API to construct a secret that is compatible with the binding specification to create an AWS RDS 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 AWS RDS on Tanzu Application Platform (TAP) with AWS Controllers for Kubernetes (ACK).