Skip to content

Latest commit

 

History

History
228 lines (178 loc) · 8.67 KB

README.md

File metadata and controls

228 lines (178 loc) · 8.67 KB

notebook-deployment

This project manages the deployment of the notebook application to a kubernetes cluster.

Application Design

Application Design

The application has the following key points:

  1. Identity Authoriation Management (IAM) using an OAuth 2.0 service, in this case keycloak.
  2. An Rest API implmented using Spring Boot, Security, WebFlux.
  3. A MongoDB store to persist user notes.
  4. 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]
  5. A backend email service to listen and notify users of updates.
  6. 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:

Deployment Design

The deployment is designed to use kustomize to deploy multiple configuration from the same base kubernetes resource manifests.

Installing Required Tools

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/

Gettings Started with minikube

Here are the steps to start the service:

  1. 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
  2. Start minikube
    $ minikube start
    $ minikube addons enable ingress
    $ minikube addons enable dashboard
    $ sudo minikube tunnel --cleanup
  3. Open a new terminal and point docker to minikube
    $ eval $(minikube docker-env)
  4. 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"}'
  5. Build all service code
    $ (cd notebook-note-service && skaffold build)
    $ (cd notebook-email-service && skaffold build)
    $ (cd notebook-notes-app && skaffold build)
  6. Identify the minikube ingress ip
    $ export NOTEBOOK_INGRESS_DNS="notebook-$(minikube ip | sed 's/\./-/g').nip.io"
  7. 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
  8. Deploy the services on the cluster.
    $ (cd notebook-deployment && skaffold run)
    Note if the images fail to pull, repeat point the docker to minikube and rebuild the service code.
  9. Open a browser to http://$NOTEBOOK_INGRESS_DNS/ and you should be met with a login/register screen.
  10. Register as a user
  11. A JWT token is displayed in the text box on screen.
  12. 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)
  13. 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"}'
  14. The result should be a 201 Created. The location header returns the path to the created resource.
  15. If you get a 401 Unauthorized, check the response WWW-Authenticate header for details.
    • Usually the token has expired and needs to be refreshed.
  16. 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 
  17. 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" }'
  18. Note can be deleted using the following curl command:
    $ curl -s --request DELETE \
       --location "http://$NOTEBOOK_INGRESS_DNS/note/{noteId}" \
       --header 'Authorization: Bearer '"$JWT"''

Structure

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.

Deploying to a kubernetes cluster using kubectl

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

Deleting a deployment

$ skaffold delete
$ skaffold delete --profile=staging
$ skaffold delete --profile=prod

CI/CD deployment

A sample CI/CD deployment would be broken up into two tools:

  1. A CI tool to build and deploy the application images, such as, Jenkins, Google Cloud Build, Travis or Circle CI.
  2. A CD tool to deploy changes to the kubernetes deployment files, such as, ArgoCD

CI/CD Example

Building on CI

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>.

Deploying with ArgoCD

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.