diff --git a/README.adoc b/README.adoc index 7973e74..48384e4 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,8 @@ = Overview -This project implements a sample service broker that adheres to the https://www.openservicebrokerapi.org/[Open Service Broker API] using the https://cloud.spring.io/spring-cloud-open-service-broker/[Spring Cloud Open Service Broker] framework. It can be deployed to either Cloud Foundry or Kubernetes, and can be registered as a service broker to either platform. +This project demonstrates how the https://cloud.spring.io/spring-cloud-open-service-broker/[Spring Cloud Open Service Broker] +framework can be used to easily build an https://www.openservicebrokerapi.org/[Open Service Broker API] compliant service broker. +It can be deployed and registered as a service broker using either Cloud Foundry or Kubernetes. == Compatibility @@ -27,7 +29,7 @@ The project is built with Gradle. The https://docs.gradle.org/current/userguide/ ./gradlew build == Deploy - + Once the project is built, it can be deployed and registered to either Cloud Foundry or Kubernetes. * link:deploy/cloudfoundry/README.adoc[deploy to Cloud Foundry] diff --git a/build.gradle b/build.gradle index bbcc875..a6c6f67 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ dependencies { runtime('org.springframework.boot:spring-boot-devtools') compile('org.springframework.cloud:spring-cloud-open-service-broker-starter-webmvc:2.0.0.BUILD-SNAPSHOT') - + compile('org.springframework.data:spring-data-keyvalue') testCompile('org.springframework.boot:spring-boot-starter-test') @@ -75,4 +75,5 @@ docker { dockerfile file('deploy/docker/Dockerfile') files jar.archivePath buildArgs(['JAR_FILE': "${jar.archiveName}"]) + } diff --git a/deploy/kubernetes/README.adoc b/deploy/kubernetes/README.adoc index 218be0a..02d9b5c 100644 --- a/deploy/kubernetes/README.adoc +++ b/deploy/kubernetes/README.adoc @@ -18,12 +18,23 @@ A Kubernetes cluster will be used to deploy the service broker application and r The `minikube` project can be used to run a small Kubernetes cluster on a development workstation. Follow the https://kubernetes.io/docs/getting-started-guides/minikube[Kubernetes documentation] to install `minikube`, start a cluster, and target the cluster with `kubectl`. +=== jq (optional) + +`jq` is useful for extracting data from `kubecl` output, it can be downloaded from https://stedolan.github.io/jq/download/ + === Pivotal Container Service (PKS) Pivotal Container Service (PKS) can be used to deploy and manage production-quality Kubernetes clusters on Pivotal Cloud Foundry. Follow the https://docs.pivotal.io/runtimes/pks/[PKS documentation] to install the product, create a cluster, and target the cluster with `kubectl`. *NOTE*: Ensure that post-deploy scripts have been enabled in PCF Ops Manager as described on the https://docs.pivotal.io/runtimes/pks/1-0/troubleshoot-issues.html#timeouts[PKS Troubleshooting page]. +=== Google Kubernetes Engine (GKE) + +Google Cloud Platform provides a Kubernetes Engine (GKE) and installer tool for setting up the Service Catalog extension API. + +The process of setting up GKE is documented at https://cloud.google.com/kubernetes-engine/docs/quickstart +The service catalog installation tool can be installed here https://github.com/GoogleCloudPlatform/k8s-service-catalog#installation + == Service Catalog Kubernetes support for service brokers via the Open Service Broker API is provided by the https://kubernetes.io/docs/concepts/service-catalog/[Service Catalog] project. Follow the https://github.com/kubernetes-incubator/service-catalog/blob/master/docs/install.md[project documentation] to install the service catalog into your Kubernetes cluster. @@ -134,12 +145,13 @@ Namespace: bookstore-broker Labels: run=bookstore-broker Annotations: Selector: run=bookstore-broker -Type: NodePort -IP: 10.107.161.81 +Type: LoadBalancer +IP: 10.47.247.7 +LoadBalancer Ingress: {{EXTERNAL_IP}} Port: 80/TCP TargetPort: 8080/TCP -NodePort: 32248/TCP -Endpoints: +NodePort: 30789/TCP +Endpoints: 10.44.4.8:8080 Session Affinity: None External Traffic Policy: Cluster Events: @@ -161,7 +173,7 @@ http://192.168.99.100:31742 Use the provided URL to access the `/v2/catalog` endpoint of the service broker application: ---- -$ curl http://192.168.99.100:31742/v2/catalog -u admin:supersecret +$ curl http://{{EXTERNAL_IP}}/v2/catalog -u admin:supersecret {"services":[{"id":"bdb1be2e-360b-495c-8115-d7697f9c6a9e","name":"bookstore","description":"A simple book store service","bindable":true,"plan_updateable":false,"plans":[{"id":"b973fb78-82f3-49ef-9b8b-c1876974a6cd","name":"standard","description":"A simple book store plan","free":true}],"tags":["book-store","books","sample"]}]} ---- @@ -171,50 +183,28 @@ Show the details of the service broker application service again: ---- $ kubectl describe service bookstore-broker -n bookstore-broker -Name: bookstore-broker Namespace: bookstore-broker Labels: run=bookstore-broker Annotations: Selector: run=bookstore-broker -Type: NodePort -IP: 10.107.161.81 +Type: LoadBalancer +IP: 10.47.247.7 +LoadBalancer Ingress: {{EXTERNAL_IP}} Port: 80/TCP TargetPort: 8080/TCP -NodePort: 32248/TCP -Endpoints: +NodePort: 30789/TCP +Endpoints: 10.44.4.8:8080 Session Affinity: None External Traffic Policy: Cluster Events: ---- -Note the value of the `NodePort` row. - -Show a list of Kubernetes pods running in the cluster: - ----- -$ kubectl get pods -n bookstore-broker -o=wide -NAME READY STATUS IP NODE -bookstore-broker-68f88cbbfb-vvmn4 1/1 Running 10.200.37.3 8ce76de4-4cfc-4bcd-b860-043a69cd2402 ----- - -Note the value in the `NODE` column for the `bookstore-broker` pod. - -Show a list of Kubernetes nodes running in the cluster: - ----- -$ kubectl get nodes -n bookstore-broker -o=wide -NAME STATUS AGE VERSION EXTERNAL-IP -2e45b4e3-1f9a-439e-b830-e051135f9e52 Ready 1d v1.9.2 192.168.1.236 -8ce76de4-4cfc-4bcd-b860-043a69cd2402 Ready 1d v1.9.2 192.168.1.235 -cf353f58-bb1a-45cf-8b18-96976f818c5f Ready 1d v1.9.2 192.168.1.234 ----- - -Note the value in the `EXTERNAL-IP` column of the node whose `NAME` matches the node for the `bookstore-broker` pod. +Note the value for `LoadBalancer Ingress` column and `Port` in the output above. Construct a URL using the IP address of the node and the port of the service, and use the this URL to access the `/v2/catalog` endpoint of the service broker application: ---- -$ curl http://192.168.1.235:32248/v2/catalog -u admin:supersecret +$ curl http://{{EXTERNAL_IP}}:{{PORT}}/v2/catalog -u admin:supersecret {"services":[{"id":"bdb1be2e-360b-495c-8115-d7697f9c6a9e","name":"bookstore","description":"A simple book store service","bindable":true,"plan_updateable":false,"plans":[{"id":"b973fb78-82f3-49ef-9b8b-c1876974a6cd","name":"standard","description":"A simple book store plan","free":true}],"tags":["book-store","books","sample"]}]} ---- @@ -224,7 +214,8 @@ $ curl http://192.168.1.235:32248/v2/catalog -u admin:supersecret Now that the application has been deployed and verified, it can be registered to the Service Catalog. -The Open Service Broker API endpoints in the service broker application are secured with a basic auth username and password. Create a Kubernetes secret to store these credentials: +The Open Service Broker API endpoints in the service broker application are secured with a basic auth username and password. +Create a Kubernetes secret to store these credentials (the username and password values in the deployment file are base64 encoded): ---- $ kubectl create -f deploy/kubernetes/service-broker-secret.yml @@ -481,4 +472,19 @@ uri: 67 bytes username: 4 bytes ---- +To test the Service Instance API, the URL can be constructed from the binding credentials; + +---- +export SI_URI=$(kubectl get secret bookstore-binding -n test -o json | jq -r '.data.uri' | base64 --decode) +export SI_USER=$($ kubectl get secret bookstore-binding -n test -o json | jq -r '.data.username' | base64 --decode) +export SI_PASSWORD=$(kubectl get secret bookstore-binding -n test -o json | jq -r '.data.password' | base64 --decode) + +export GET_BOOKS_URI=$(curl ${SI_URI} -u ${SI_USER}:${SI_PASSWORD} -H "Content-Type: application/json" -X PUT -d '{"isbn":"978-1617292545","title":"Spring Boot in Action", "author":"Craig Walls"}' | jq -r '.links | first | .href') +curl ${GET_BOOKS_URI} -u ${SI_USER}:${SI_PASSWORD} +---- + +== Current Issues +* On GKE with a service catalog installed using `sc`, the service instance API only works when no authentication is provided +* The service binding returns `localhost:8080` for the URI instead of the External IP address from the LoadBalancer service + diff --git a/deploy/kubernetes/service-broker-secret.yml b/deploy/kubernetes/service-broker-secret.yml index f49e678..5aaa8de 100644 --- a/deploy/kubernetes/service-broker-secret.yml +++ b/deploy/kubernetes/service-broker-secret.yml @@ -8,4 +8,4 @@ metadata: type: Opaque data: username: YWRtaW4= - password: c3VwZXJzZWNyZXQ= \ No newline at end of file + password: c3VwZXJzZWNyZXQ= diff --git a/deploy/kubernetes/service-broker.yml b/deploy/kubernetes/service-broker.yml index 626e07e..82eddaa 100644 --- a/deploy/kubernetes/service-broker.yml +++ b/deploy/kubernetes/service-broker.yml @@ -5,7 +5,7 @@ metadata: labels: run: bookstore-broker spec: - url: http://bookstore-broker.bookstore-broker.svc.cluster.local + url: http://bookstore-broker.service-catalog.svc.cluster.local authInfo: basic: secretRef: diff --git a/deploy/kubernetes/service.yml b/deploy/kubernetes/service.yml index eca964d..aa1b145 100644 --- a/deploy/kubernetes/service.yml +++ b/deploy/kubernetes/service.yml @@ -12,4 +12,4 @@ spec: targetPort: 8080 selector: run: bookstore-broker - type: NodePort \ No newline at end of file + type: LoadBalancer \ No newline at end of file