This project manages the deployment of the notebook application to a kubernetes cluster.
The application has the following key points:
- Identity Authoriation Management (IAM) using an OAuth 2.0 service, in this case keycloak.
- An Rest API implmented using Spring Boot, Security, WebFlux.
- A MongoDB store to persist user notes.
- An AMQP compatible messaging service, in this case RabbitMQ.
- An exchange
notes
with bindings to the following queues is used:- [
notes.event.created
] -> [notes-event-created
] - [
notes.event.updated
] -> [notes-event-updated
] - [
notes.event.deleted
] -> [notes-event-deleted
]
- [
- An exchange
- A backend email service to listen and notify users of updates.
- A frontend SPWA implemented using Reactjs
Please note, the front end is a work in progress and currently only provides authentication and displays the users JWT token.
The service code is located in the following repositories:
The deployment is designed to use kustomize to deploy multiple configuration from the same base kubernetes resource manifests.
Installing kustomize
Installation instructions can be found @ https://kubernetes-sigs.github.io/kustomize/installation.
curl -s "https://raw.githubusercontent.com/\
kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo install kustomize /usr/local/bin
Installing skaffold
Installation instructions can be found @ https://skaffold.dev/docs/install/.
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 && \
sudo install skaffold /usr/local/bin/
Here are the steps to start the service:
- Clone the git repositories
$ mkdir notebook; cd notebook $ git clone https://github.com/fbyrne/notebook-note-service.git $ git clone https://github.com/fbyrne/notebook-email-service.git $ git clone https://github.com/fbyrne/notebook-notes-app.git $ git clone https://github.com/fbyrne/notebook-deployment.git
- Start minikube
$ minikube start $ minikube addons enable ingress $ minikube addons enable dashboard $ sudo minikube tunnel --cleanup
- Open a new terminal and point docker to minikube
$ eval $(minikube docker-env)
- Patch the kubernetes nginx ingress controller config to resolve a problem with keycloak running behind the ingress.
$ kubectl patch configmap/nginx-load-balancer-conf \ -n kube-system \ --type merge \ -p '{"proxy-buffer-size": "16k"}'
- Build all service code
$ (cd notebook-note-service && skaffold build) $ (cd notebook-email-service && skaffold build) $ (cd notebook-notes-app && skaffold build)
- Identify the minikube ingress ip
$ export NOTEBOOK_INGRESS_DNS="notebook-$(minikube ip | sed 's/\./-/g').nip.io"
- At this time, I could not find a way to update the ingress host references via a variable. So this needs to be replaced with the value of environment variable NOTEBOOK_INGRESS_DNS in:
- base/notes-application.properties
- overlays/dev/ingress-sethost-patch.yaml
- overlays/dev/notes-app-keycloak.json
- Deploy the services on the cluster.
Note if the images fail to pull, repeat point the docker to minikube and rebuild the service code.
$ (cd notebook-deployment && skaffold run)
- Open a browser to
http://$NOTEBOOK_INGRESS_DNS/
and you should be met with a login/register screen. - Register as a user
- A JWT token is displayed in the text box on screen.
- Once a user has been created you can login from the command-line using
$ JWT=$(curl -s "http://$NOTEBOOK_INGRESS_DNS/auth/realms/notebook/protocol/openid-connect/token" \ -d "client_id=notebook-frontend" \ -d "username=<user>" -d "password=<plain-password>" \ -d "grant_type=password" | jq -r .access_token)
- Use this JWT token in POSTMAN or cURL to issue requests to the API
$ JWT='ABC.DEF.XYZ' $ curl -i --request POST \ --location "http://$NOTEBOOK_INGRESS_DNS/note" \ --header 'Authorization: Bearer '"$JWT"'' \ --header 'Content-Type: application/json' \ --data-raw '{"content":"My first note"}'
- The result should be a 201 Created. The location header returns the path to the created resource.
- If you get a 401 Unauthorized, check the response
WWW-Authenticate
header for details.- Usually the token has expired and needs to be refreshed.
- Note can be retrieved using the following curl command:
$ curl -s --request GET \ --location "http://$NOTEBOOK_INGRESS_DNS/note/{noteId}" \ --header 'Authorization: Bearer '"$JWT"'' \ --header 'Accept: application/json' | jq
- Note can be updated using the following curl command:
$ curl -s --request PUT \ --location "http://$NOTEBOOK_INGRESS_DNS/note/{noteId}" \ --header 'Authorization: Bearer '"$JWT"'' \ --header 'Accept: application/json' \ --data-raw '{ "version": 1, content": "My updated note" }'
- Note can be deleted using the following curl command:
$ curl -s --request DELETE \ --location "http://$NOTEBOOK_INGRESS_DNS/note/{noteId}" \ --header 'Authorization: Bearer '"$JWT"''
The base resources are contained within the '/base' directory. The base kustomize file defines which resources to include and any common customization to apply to the resources.
The overlays folder contains a folder for each deployment types that are defined.
Using kustomize many different types of deployments (dev, staging, prod) can be managed for a common set of kubernetes resources. The deployments are deployed to the cluster using kubectl
as follows:
kustomize build ./overlays/dev | kubectl apply -f -
Deploying to a kubernetes cluster using Skaffold
Skaffold handles the workflow for building, pushing and deploying your application, allowing you to focus on what matters most: writing code.
To deploy for development purposes, and watching for changes:
$ skaffold dev
To deploy for development purposes:
$ kubectl create namespace notebook-dev
$ skaffold run
To deploy for staging:
$ kubectl create namespace notebook-staging
$ skaffold run --profile=staging
To deploy for production:
$ kubectl create namespace notebook-prod
$ skaffold run --profile=prod
$ skaffold delete
$ skaffold delete --profile=staging
$ skaffold delete --profile=prod
A sample CI/CD deployment would be broken up into two tools:
- A CI tool to build and deploy the application images, such as, Jenkins, Google Cloud Build, Travis or Circle CI.
- A CD tool to deploy changes to the kubernetes deployment files, such as, ArgoCD
The CI pipeline should use the usual build, test and analyse using the language/framework specific tools.
For deploying the image skaffold
can be used to build the container images and deploy them to the container registry using deployment specific tags.
$ cd ./notebook-note-service; skaffold build --profile=staging
This will produce a container image which is tagged notebook/note-service:staging-<git-tag>
and notebook/note-service:staging-<commit-sha>
.
The same example works for the production profile, which will produce a container image which is tagged notebook/note-service:production-<git-tag>
and notebook/note-service:production-<commit-sha>
.
ArgoCD can be setup to listen to triggers from the git source repository.
For staging
continuous deployment, the argocd pipeline can be triggered on push events for the staging
branch or tag.
For production
continuous deployment, the ArgoCD pipeline can be triggered on push events for the production
branch or tag.