Checking Out the Kubernetes Service Catalog

The Service Catalog provides a way for developers, ISVs, and SaaS vendors to provision instances of services that can be consumed by applications in a standard way. Originally designed for the CloudFoundry platform, the Open Service Broker project was recently founded to standardise the specification and open it up to other platforms such as Kubernetes and OpenShift. The Kubernetes Special Interest Group for Service Catalog has been working on integrating the Open Service Broker API with the Kubernetes ecosystem.

Using the Service Catalog, an application developer has the ability to request services from a catalog without worrying about how and where they are provisioned. Once the service is available, they can bind the service to their application and consume any associated credentials. These provisioning and binding requests are made to Service Brokers, which are registered with the Service Catalog and act as the glue code between the services and applications.

As an example, say you’re writing a web application and you need a database. You’re not a database admin and don’t know how to setup a database server, but you do know that your application needs a MySQL database. Luckily for you, your cloud platform of choice has a managed database service that allows you to provision instances of databases with just a few clicks. In order for you to automate your application deployments, you need a way to provision and teardown database instances on-demand. You can use the Service Catalog, along with a Service Broker for the managed database service, to manage the lifecycle of your database instances and consume the database host, port and credentials in a standard way.

As a service vendor, you will want to develop a Service Broker to offer your services in the Service Catalog. A Service Broker is fairly simple to implement and only needs to conform to the Open Service Broker API specification. To try this out, I created an example Service Broker that creates MariaDB databases (installed using the Helm Chart).

Before giving this a run, it’s a good idea to step through the walkthrough to get your environment setup on Kubernetes (you can use Minikube) and learn more about some of the Service Catalog concepts.

Creating a Service Broker

To start off, I simply copied the boilerplate from the User Provided Service example in the Service Catalog repository. The controller and the server entrypoint are the only things I needed to get started. These import the packages from the Service Broker repository to serve the API, and all I needed to do was to write the logic for managing the MariaDB chart instances in the controller.

Once my Broker was ready, I built a Docker image (using multi-stage builds!) and a chart to deploy the Broker server in my cluster.

$ git clone https://github.com/prydonius/mariadb-broker.git
$ cd mariadb-broker/
$ helm install --name mariadb-broker --namespace mariadb-broker charts/mariadb-broker

Registering the MariaDB Service Broker

Before a Service Broker can be used, it needs to be registered with the catalog. To do this, I had to create a Broker resource using the Service Catalog API. The Broker resource simply tells the Service Catalog where the Broker server is located.

apiVersion: servicecatalog.k8s.io/v1alpha1
kind: Broker
metadata:
name: mariadb-broker
spec:
url: http://mariadb-broker-mariadb-broker.mariadb-broker.svc.cluster.local

I’m pointing to the in-cluster address for my MariaDB Broker, but I could also point to an external server if my Broker server was deployed outside of my cluster.

After creating this resource, the Service Catalog controller requests the available plans from the Broker server and populates Service Classes, an API entity that represents an offering in the catalog.

$ kubectl --context service-catalog create -f examples/mariadb-broker.yaml
$ kubectl --context service-catalog get serviceclasses
NAME KIND
mariadb ServiceClass.v1alpha1.servicecatalog.k8s.io

(note: without API aggregation I needed to create these resources using the Service Catalog API — see the walkthrough to get the Service Catalog API setup correctly)

If I inspect the Service Class, I can see that the controller has successfully interacted with my Broker server.

$ kubectl --context service-catalog get serviceclasses mariadb -o yaml
...
bindable: true
description: MariaDB database
osbGuid: 3533e2f0-6335-4a4e-9d15-d7c0b90b75b5
plans:
- description: MariaDB database
name: default
osbFree: true
osbGuid: b9600ecb-d511-4621-b450-a0fa1738e632
osbMetadata: null

This output matches the definition in the MariaDB Broker controller.

Provisioning and binding to MariaDB instances

Now that I have my MariaDB service in the catalog, I can go ahead and setup instances of MariaDB servers for my applications by creating an Instance resource with the Service Catalog API. In the Instance resource, I need to specify the Service Class and plan from the catalog. The MariaDB Broker only offers a single plan, named default, and the name of the Service Class is mariadb.

apiVersion: servicecatalog.k8s.io/v1alpha1
kind: Instance
metadata:
name: mariadb-instance
spec:
serviceClassName: mariadb
planName: default

After creating the instance, the MariaDB Broker will receive the provisioning request and install a new MariaDB chart release for it.

$ kubectl --context service-catalog create -f examples/mariadb-instance.yaml
$ kubectl --context service-catalog get instances mariadb-instance -o yaml
...
spec:
checksum: 719629d5d0ac887f9bbc03e57f53f118cebe00890a057c6d76ac77c33457a1f7
osbGuid: 3e0e9973-a072-49ba-8308-19568e7f4669
planName: default
serviceClassName: mariadb
status:
asyncOpInProgress: false
conditions:
- lastTransitionTime: 2017-05-13T16:28:35Z
message: The instance was provisioned successfully
reason: ProvisionedSuccessfully
status: "True"
type: Ready

If I inspect the Instance I just created, I can see that it was successfully provisioned. The output of helm list also displays the chart release that was created, matching the GUID (osbGuid) of the Instance.

$ helm list
NAME REVISION UPDATED STATUS CHART NAMESPACE
i-3e0e9973-a072-49ba-8308-19568e7f4669 1 Sat May 13 17:28:35 2017 DEPLOYED mariadb-0.6.1 3e0e9973-a072-49ba-8308-19568e7f4669

The final step was to bind the Instance with an application. To get the connection details for the database, I needed to create a Binding resource using the Service Catalog API. This resource indicates that an application is bound to an Instance, and holds the name of the Secret I want to populate with the connection details.

apiVersion: servicecatalog.k8s.io/v1alpha1
kind: Binding
metadata:
name: mariadb-binding
spec:
instanceRef:
name: mariadb-instance
secretName: mariadb-instance-credentials

After creating this resource, the controller will make the bind request to fetch the connection details from the Broker server and generate the Secret.

$ kubectl --context service-catalog create -f examples/mariadb-binding.yaml
$ kubectl --context service-catalog get bindings mariadb-binding -o yaml
...
status:
conditions:
- lastTransitionTime: 2017-05-13T16:33:17Z
message: Injected bind result
reason: InjectedBindResult
status: "True"
type: Ready

If I inspect the generated Secret, I can see the keys I need to use to connect to the database server from the application.

$ kubectl get secrets mariadb-instance-credentials -o yaml
apiVersion: v1
data:
database: ZGJuYW1l
host: aS0zZTBlOTk3My1hMDcyLTQ5YmEtODMwOC0xOTU2OGU3ZjQ2NjktbWFyaWFkYi4zZTBlOTk3My1hMDcyLTQ5YmEtODMwOC0xOTU2OGU3ZjQ2Njkuc3ZjLmNsdXN0ZXIubG9jYWw=
password: MmlrRnJHZDh6RjJvZ0tvVA==
port: MzMwNg==
uri: bXlzcWw6Ly9yb290OjJpa0ZyR2Q4ekYyb2dLb1RAaS0zZTBlOTk3My1hMDcyLTQ5YmEtODMwOC0xOTU2OGU3ZjQ2NjktbWFyaWFkYi4zZTBlOTk3My1hMDcyLTQ5YmEtODMwOC0xOTU2OGU3ZjQ2Njkuc3ZjLmNsdXN0ZXIubG9jYWw6MzMwNi9kYm5hbWU=
username: cm9vdA==
kind: Secret
...

To test the connection, I used the Bitnami WordPress container and set the database environment variables to use values from the Secret.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: wordpress
spec:
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: wordpress
image: "bitnami/wordpress:latest"
env:
- name: MARIADB_HOST
valueFrom:
secretKeyRef:
name: mariadb-instance-credentials
key: host
- name: MARIADB_PORT
valueFrom:
secretKeyRef:
name: mariadb-instance-credentials
key: port
- name: WORDPRESS_DATABASE_USER
valueFrom:
secretKeyRef:
name: mariadb-instance-credentials
key: username
- name: WORDPRESS_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-instance-credentials
key: password
- name: WORDPRESS_DATABASE_NAME
valueFrom:
secretKeyRef:
name: mariadb-instance-credentials
key: database
...

After creating the Deployment and Service, I could access WordPress in my browser and visit the sample “Hello World!” blog post.

$ kubectl create -f examples/wordpress.yaml
WordPress using a MariaDB server from the Service Catalog

Going to production

The MariaDB Service Broker creates local, single node, MariaDB servers. In production, my applications need to use a more reliable managed database service. With the Service Catalog, all I would need to do to move to a more reliable database service is upgrade the plan or switch out the Broker. Since all Service Brokers speak a standard API, I don’t need to change my application definitions — they would consume the connection details in the same way.

This flexibility makes the Service Catalog a powerful way for application developers to abstract away the details of database administration in multiple different environments, and allows them to focus on building their application.

Community

The Kubernetes Service Catalog is currently in the Kubernetes Incubator, and is quickly approaching a beta release. Check out the design documentation for an overview and glossary of the different concepts. To get involved in the project, join the #sig-service-catalog Slack channel, the mailing group or the weekly SIG meetings.