Spring PetClinic is a sample Spring Boot web application. This article shows how to connect the application to an Amazon Relational Database Service using AWS Controllers for Kubernetes and an operator that implements the Service Binding Specification for Kubernetes.
- Kubernetes cluster with RDS Controller installed.
- An operator that implements the Service Binding Specification for Kubernetes. You can use one of these:
I created a repository for the container image in the quay.io. Then I ran these commands to create the container image and push to the repository. This container image is going to be used to deploy the application.
$ git clone https://github.com/spring-projects/spring-petclinic.git
$ spring-petclinic
$ sudo apt-get install openjdk-11-jdk -y
$ export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
$ ./mvnw spring-boot:build-image
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
spring-petclinic 2.7.0-SNAPSHOT 73e160e426ea 42 years ago 266MB
$ docker tag spring-petclinic:2.7.0-SNAPSHOT quay.io/bmuthuka/spring-petclinic:2.7.0-SNAPSHOT
$ docker login quay.io # enter credentials when propmted
$ docker push quay.io/bmuthuka/spring-petclinic:2.7.0-SNAPSHOT
The container image is built with Spring Cloud Bindings. This makes the application to read database connection configuration values from the file system. The Service Binding website has a good explanation about how the application consume bindings. I have written a blog post about how to enable Spring Cloud Bindings for a Spring Boot application.
You need a Secret resource with type
, provider
and password
data entries. This Secret resource is used in the DBInstance
resource to specify the password field. Later the same Secret resource can be used as the target in the FieldExport
resources. Finally ServiceBinding
resource can use the Secret resource for Direct Secret Reference.
apiVersion: v1
kind: Secret
metadata:
name: rds-postgres-field-exports
namespace: ack-system
stringData:
type: postgresql
provider: aws
password: "secret123"
The Spring Cloud Bindings expects the value for type
as postgresql
. Note: The provider
field is not used by the Spring PetClinic application.
The DBInstance
custom resource can be used to define the RDS database. Since I need a PostgreSQL database, I specified the engine as postgres
in the .spec.engine
field.
apiVersion: rds.services.k8s.aws/v1alpha1
kind: DBInstance
metadata:
name: rds-postgres-dbinstance
namespace: ack-system
spec:
allocatedStorage: 20
dbInstanceClass: db.t3.micro
dbInstanceIdentifier: rds-postgres-demo
engine: postgres
engineVersion: "14"
masterUsername: dbuser
masterUserPassword:
namespace: ack-system
name: rds-postgres-field-exports
key: password
To export the fields, you can create multiple FieldExport custom resources with the values required for database connectivity. Here is the resource that I defined:
---
apiVersion: services.k8s.aws/v1alpha1
kind: FieldExport
metadata:
name: rds-postgres-field-exports-host
namespace: ack-system
spec:
to:
name: rds-postgres-field-exports
kind: secret
key: host
from:
path: ".status.endpoint.address"
resource:
group: rds.services.k8s.aws
kind: DBInstance
name: rds-postgres-dbinstance
---
apiVersion: services.k8s.aws/v1alpha1
kind: FieldExport
metadata:
name: rds-postgres-field-exports-database
namespace: ack-system
spec:
to:
name: rds-postgres-field-exports
kind: secret
key: database
from:
path: ".spec.engine"
resource:
group: rds.services.k8s.aws
kind: DBInstance
name: rds-postgres-dbinstance
---
apiVersion: services.k8s.aws/v1alpha1
kind: FieldExport
metadata:
name: rds-postgres-field-exports-port
namespace: ack-system
spec:
to:
name: rds-postgres-field-exports
kind: secret
key: port
from:
path: ".status.endpoint.port"
resource:
group: rds.services.k8s.aws
kind: DBInstance
name: rds-postgres-dbinstance
---
apiVersion: services.k8s.aws/v1alpha1
kind: FieldExport
metadata:
name: rds-postgres-field-exports-user
namespace: ack-system
spec:
to:
name: rds-postgres-field-exports
kind: secret
key: username
from:
path: ".spec.masterUsername"
resource:
group: rds.services.k8s.aws
kind: DBInstance
name: rds-postgres-dbinstance
The .spec.to
refers to the Secret resource created in previous section. The .spec.to.key
refers to the target key name required for the PostgreSQL database connection. The .spec.from
points to the DBInstance
resource.
In the Deployment, there is a special label psql.provider: aws
added. This label is later used in the ServiceBinding
resource to refer the workload. An environment variable SPRING_PROFILES_ACTIVE
with value as postgres
is required to activate the profile. This will make the application to look for PostgreSQL specific database configuration values. The container image should point to the newly updated location of the Spring PetClinic container image.
You can also create a Service pointing to the Deployment. Later it can be used to access the application.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-petclinic
namespace: ack-system
labels:
app: spring-petclinic
psql.provider: aws
spec:
replicas: 1
selector:
matchLabels:
app: spring-petclinic
template:
metadata:
labels:
app: spring-petclinic
spec:
containers:
- name: app
image: quay.io/bmuthuka/spring-petclinic:2.7.0-SNAPSHOT
imagePullPolicy: Always
env:
- name: SPRING_PROFILES_ACTIVE
value: postgres
ports:
- name: http
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
labels:
app: spring-petclinic
name: spring-petclinic
namespace: ack-system
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: spring-petclinic
Service Binding Specification for Kubernetes standardizes exposing backing service secrets to application workloads. A backing service is any process that the application consumes over the network as part of its regular operation.
In the ServiceBiding
resource, the Secret resource represents the RDS PostgreSQL service. And the workload is identified through a label selector (psql.provider: aws
).
apiVersion: servicebinding.io/v1beta1
kind: ServiceBinding
metadata:
name: servicebinding-rds-demo
namespace: ack-system
spec:
service:
apiVersion: v1
kind: Secret
name: rds-postgres-field-exports
workload:
selector:
matchLabels:
psql.provider: aws
apiVersion: apps/v1
kind: Deployment
You can read more about Service Biding in the application operator documentation.
To verify the application, you can forward the port of the application service:
kubectl port-forward --address 0.0.0.0 svc/spring-petclinic 8080:80 -n ack-system
Now you can access Spring PetClinic application from a web browser at http://localhost:8080
TBD
typo: Section "Spring PetClinic Container Image"
The contailer image -> The container image