In a microservice architecture, a naming server serves as a registry for service discovery. Each microservice in the system has a unique name and runs on its own address, and the naming server maintains a mapping between the service names and their addresses. When a client wants to access a certain microservice, it can query the naming server to find the address of the service it needs. This eliminates the need for hard-coded addresses and allows for dynamic reconfiguration of the system as services come and go. The naming server plays a crucial role in the seamless functioning of a microservice-based system.
In this example we use Eureka naming server.
In a microservice architecture, a load balancer is an important component that sits between the client and the microservices. Its primary function is to distribute incoming requests to multiple instances of a microservice, improving system reliability and scalability.
When a client makes a request, the load balancer routes it to one of the available instances of the target microservice. This helps to evenly distribute the incoming request load, avoid overloading any single instance, and prevent a single point of failure. In case an instance of the microservice fails, the load balancer can detect this and redirect requests to other healthy instances.
By using a load balancer, microservice-based systems can dynamically scale up or down the number of instances of a service based on the incoming request volume, ensuring that the system remains responsive and resilient even under high load.
An API gateway is a single entry point for all requests from clients to the backend services in a microservice architecture. It sits between the client and the microservices and routes requests to the appropriate microservice. It also provides a single place to apply common cross-cutting concerns such as security, monitoring, and resiliency.
Distributed tracing is a technique that helps to monitor and troubleshoot complex distributed systems. It allows developers to trace the flow of a request as it is processed by multiple microservices. This helps to identify performance bottlenecks and errors in the system.
In this example we use Zipkin distributed tracing.
docker run -d -p 9411:9411 openzipkin/zipkin
Spring Boot Actuator provides production-ready features to help you monitor and manage your application. You can choose to manage and monitor your application by using HTTP endpoints or with JMX. For example, you can choose to expose health, metrics, and trace information over HTTP or to JMX.
Spring Boot Actuator provides a number of additional features to help you monitor and manage your application when it’s pushed to production. You can choose to manage and monitor your application by using HTTP endpoints or with JMX. For example, you can choose to expose health, metrics, and trace information over HTTP or to JMX.
Docker is a tool designed to make it easier to create, deploy, and run applications by using containers.
A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another.
A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.
docker events
- show eventsdocker info
- show infodocker stats
- show stats metricsdocker system df
- show disk usage of dockerdocker inspect <container id>
- show details of containerdocker top <container id>
- show processes running inside containerdocker ps
- list running containersdocker ps -a
- list all containersdocker images
- list imagesdocker run <image-name>
- run imagedocker run <image-name> -m 512m --cpu-quota 50000
- run image with memory and cpu limits (512mb and 50% of cpu)docker run -p 8080:8080 -d <image-name>
- detach flag (run container in background - no terminal)docker run -p 8080:8080 --restart=always <image-name>
- docker container will auto run on docker engine startdocker run -p 8080:8080 <image-name>
- run image and map port 8080 to 8080docker logs <container id>
- show logsdocker logs <container id> -f
- show logs and followsdocker image history <image-name>
- show history of imagedocker image inspect <image-name>
- show details of imagedocker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" <image-name>
- run image and map port 8080 to 8080 and set environment variabledocker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" -e "SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/currency_exchange" <image-name>
- run image and map port 8080 to 8080 and set environment variabledocker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" -e "SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/currency_exchange" -e "SPRING_DATASOURCE_USERNAME=root" -e "SPRING_DATASOURCE_PASSWORD=root" <image-name>
- run image and map port 8080 to 8080 and set environment variabledocker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" -e "SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/currency_exchange" -e "SPRING_DATASOURCE_USERNAME=root" -e "SPRING_DATASOURCE_PASSWORD=root" -e "SPRING_DATASOURCE_DRIVER-CLASS-NAME=com.mysql.cj.jdbc.Driver" <image-name>
- run image and map port 8080 to 8080 and set environment variabledocker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" -e "SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/currency_exchange" -e "SPRING_DATASOURCE_USERNAME=root" -e "SPRING_DATASOURCE_PASSWORD=root" -e "SPRING_DATASOURCE_DRIVER-CLASS-NAME=com.mysql.cj.jdbc.Driver" -e "SPRING_JPA_HIBERNATE_DDL-AUTO=update" <image-name>
- run image and map port 8080 to 8080 and set environment variabledocker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" -e "SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/currency_exchange" -e "SPRING_DATASOURCE_USERNAME=root" -e "SPRING_DATASOURCE_PASSWORD=root" -e "SPRING_DATASOURCE_DRIVER-CLASS-NAME=com.mysql.cj.jdbc.Driver" -e "SPRING_JPA_HIBERNATE_DDL-AUTO=update" -e "SPRING_JPA_SHOW-SQL=true" <image-name>
- run image and map port 8080 to 8080 and set environment variablepom.xml
file
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>seanmayerz/smr-${project.artifactId}:${project.version}</name>
</image>
<pullPolicy>IF_NOT_PRESENT</pullPolicy>
</configuration>
</plugin>
</plugins>
</build>
mvn spring-boot:build-image -DskipTests
docker network create smr-network
docker run --name eureka-server --network smr-network -p 8761:8761 seanmayerz/smr-naming-server:0.0.1-SNAPSHOT
docker run -e JAVA_OPTS="-Dserver.port=8000" --name currency-exchange-service --network smr-network -p 8000:8000 seanmayerz/smr-currency-exchange-service:0.0.1-SNAPSHOT
docker-compose up
docker-compose down
- remove all containers, networks, and volumes ab -n 1000 -c 100 http://localhost:8000/sample-api
replicas
field is unsatisfied)Kuberenetes uses single responsibility (pods, services, deployments, etc) to manage containers
Api Server
Distributed Database (etcd)
Scheduler
Controller Manager
replicas
field is unsatisfied)Kubelet
replicas
field is unsatisfied)Kube Proxy
Container Runtime
How to get a pod's IP address?
kubectl get pods -o wide
- get all pods with IP address (each pod has a unique IP address)How to get a pod's logs?
kubectl logs <pod-name>
- get logs for a podHow to get a pod's shell?
kubectl exec -it <pod-name> -- /bin/bash
- get a shell for a podHow to describe a pod?
kubectl describe pod <pod-name>
- get detailed information about a podHow to get a ReplicaSets
kubectl get replicasets
- get all ReplicaSets or kubectl get rs
- get all ReplicaSetsHow to scale a deployment?
kubectl scale deployment <deployment-name> --replicas=3
- scale a deployment to 3 replicasHow to set a deployment's image? (Rolling update) - zero downtime deployment (blue/green deployment)
kubectl set image deployment <deployment-name> <container-name>=<image-name>
- set a deployment's imageHow to get a deployment's history?
kubectl rollout history deployment <deployment-name>
- get a deployment's historyHow to rollback a deployment?
kubectl rollout undo deployment <deployment-name>
- rollback a deploymentkubectl create deployment hello-world --image=gcr.io/google-samples/hello-app:1.0
- create a deploymentkubectl get deployments
- list all deploymentskubectl expose deployment hello-world --type=LoadBalancer --port=8080
- expose a deploymentkubectl scale deployment hello-world --replicas=3
- scale a deploymentkubectl delete pod hello-world-xxxxx
- delete a podkubectl autoscale deployment hello-world --min=3 --max=10 --cpu-percent=80
- autoscale a deploymentkubectl edit deployment.extensions/hello-world
kubectl get events
kubectl get events --sort-by=.metadata.creationTimestamp
- sort events by creation timestampkubectl get pods
kubectl get replicasets
kubectl get deployments
kubectl get services
Example file contents:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
creationTimestamp: "2020-10-03T20:47:39Z"
generation: 1
labels:
app: hello-world
name: hello-world
namespace: default
resourceVersion: "1000"
selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/hello-world
uid: 3b5b5b5b-5b5b-5b5b-5b5b-5b5b5b5b5b5b
spec:
progressDeadlineSeconds: 600
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
app: hello-world
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: hello-world
spec:
containers:
- image: gcr.io/google-samples/hello-app:1.0
imagePullPolicy: Always
name: hello-world
ports:
- containerPort: 8080
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
Install Google Cloud SDK
Create Maven project images (/kubernetes/
)
mvn clean package
mvn spring-boot:build-image -DskipTests
Add to docker registry
docker push seanmayerz/smr-currency-exchange-service-kubernetes:0.0.1-SNAPSHOT
docker push seanmayerz/smr-currency-conversion-service-kubernetes:0.0.1-SNAPSHOT
Create Kubernetes cluster in GKE
Create/Connect to GKE Cluster
gcloud init
gcloud auth login
gcloud container clusters create smr-cluster --zone europe-west2-a --num-nodes 1
Prepare to deploy microservices to Kubernetes
kubectl version
kubectl create deployment currency-exchange-kubernetes --image=seanmayerz/smr-currency-exchange-service-kubernetes:0.0.1-SNAPSHOT
kubectl create deployment currency-conversion-kubernetes --image=seanmayerz/smr-currency-conversion-service-kubernetes:0.0.1-SNAPSHOT
kubectl expose deployment currency-exchange-kubernetes --type=LoadBalancer --port=8000
kubectl expose deployment currency-conversion-kubernetes --type=LoadBalancer --port=8100
kubectl get svc
or kubectl get services
kubectl get pods
kubectl get rs
or kubectl get replicasets
kubectl get all
set env deployment/currency-conversion-kubernetes CURRENCY_EXCHANGE_SERVICE_HOST={{EXTERNAL-IP}}
- get external ip from kubectl get svc
commandkubectl describe deployment currency-conversion-kubernetes
- check environment variablesOpen GKE Kuberenetes GKE cloud shell
curl http://{{EXTERNAL-IP}}:8000/currency-exchange/from/USD/to/INR
- get external ip from kubectl get svc
commandcurl http://{{EXTERNAL-IP}}:8100/currency-conversion-feign/from/USD/to/INR/quantity/10
- get external ip from kubectl get svc
commandCreate declaritive configuration yaml for currency-exchange-service
kubectl get deployments
/kubernetes/currency-exchange-service
kubectl get deployment currency-exchange-kubernetes -o yaml
- get yaml for existing deploymentkubectl get deployment currency-exchange-kubernetes -o yaml > deployment.yaml
- save yaml for existing deploymentkubectl get service currency-exchange-kubernetes -o yaml > service.yaml
- save yaml for existing service (copy the service yaml from the file to the deployment yaml, then delete the service yaml)Create declaritive configuration yaml for currency-conversion-service
kubectl get deployments
/kubernetes/currency-conversion-service
kubectl get deployment currency-conversion-kubernetes -o yaml > deployment.yaml
- save yaml for existing deploymentkubectl get service currency-conversion-kubernetes -o yaml > service.yaml
- save yaml for existing service (copy the service yaml from the file to the deployment yaml, then delete the service yaml)Deploy declaritive configuration yaml for currency-exchange-service
kubectl diff -f deployment.yaml
- check diffkubectl apply -f deployment.yaml
- apply changes
You could update the replicas here and then use watch curl http://{{EXTERNAL-IP}}:8000/currency-exchange/from/USD/to/INR
to see load balancing in actionDeploy declaritive configuration yaml for currency-conversion-service
kubectl diff -f deployment.yaml
- check diffkubectl apply -f deployment.yaml
- apply changes
You could update the replicas here and then use watch curl http://{{EXTERNAL-IP}}:8100/currency-conversion-feign/from/USD/to/INR/quantity/10
to see load balancing in actionEnable Logging and Tracing in Google Cloud
API & Services
Cloud Logging
Stackdrivers
Deploying Microservice using YAML deployment
kubectl delete all -l app=currency-exchange-kubernetes
kubectl delete all -l app=currency-conversion-kubernetes
/kubernetes/currency-exchange-service
and /kubernetes/currency-conversion-service
and run kubectl apply -f deployment.yaml
curl http://{{EXTERNAL-IP}}:8000/currency-exchange/from/USD/to/INR
- get external ip from kubectl get svc
commandDeploying Microservice using YAML deployment with ConfigMap
Monitoring centralised logging in GKE
https://console.cloud.google.com/kubernetes/list/overview
View Logs
View GKE Dashboard
Workloads
currency-conversion-kubernetes
currency-conversion-kubernetes-xxxxx
View Logs
Workloads
currency-exchange-kubernetes
currency-exchange-kubernetes-xxxxx
Deployments and Rollbacks
kubectl rollout history deployment currency-exchange-kubernetes
(shows the rollout history)
REVISION CHANGE-CAUSE
1 <none>
2 <none>
kubectl rollout history deployment currency-exchange-kubernetes --revision=1
(shows the details of the revision)
deployment.apps/currency-exchange-kubernetes with revision #1
Pod Template:
Labels: app=currency-exchange-kubernetes
pod-template-hash=747c98bcf7
Containers:
smr-currency-exchange-service-kubernetes:
Image: seanmayerz/smr-currency-exchange-service-kubernetes:0.0.1-SNAPSHOT
Port: <none>
Host Port: <none>
Limits:
cpu: 500m
ephemeral-storage: 1Gi
memory: 2Gi
Requests:
cpu: 500m
ephemeral-storage: 1Gi
memory: 2Gi
Environment: <none>
Mounts: <none>
Volumes: <none>
kubectl rollout undo deployment currency-exchange-kubernetes
(roll back to previous version)kubectl create secret generic currency-conversion-kubernetes --from-literal=CURRENCY_EXCHANGE_SERVICE_URI=http://currency-exchange-kubernetes
kubectl get secrets
kubectl get secrets currency-conversion-kubernetes
kubectl get secrets currency-conversion-kubernetes -o yaml
kubectl get secrets currency-conversion-kubernetes -o yaml > secrets.yaml
kubectl apply -f deployment.yaml
Kuberentes will check the health of the pod and if it's not healthy, it will restart the pod, and if it's still not healthy, it will restart the pod again and again. This is called Liveness Probe
.
Kubernetes will check if the pod is ready to serve the request. If it's not ready, it will not send the request to the pod. This is called Readiness Probe
.
Spring Boot Actuator provides /actuator/health
endpoint which can be used for readiness and liveness probes.
We have this configured in application.properties
file.
management.endpoint.health.probes.enabled=true
management.health.livenessState.enabled=true
management.health.readinessState.enabled=true
How to test this?
kubectl get svc
- get the external ipwatch curl http://{{EXTERNAL-IP}}:8000/actuator/health
- watch the health statuswatch curl http://{{EXTERNAL-IP}}:8000/actuator/health/liveness
- watch the liveness status
{
"status": "UP"
}
watch curl http://{{EXTERNAL-IP}}:8000/actuator/health/readiness
- watch the readiness status
{
"status": "UP"
}
Add to deployment.yaml
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8000
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8000
kubectl apply -f deployment.yaml
kubectl get pods
kubectl scale --replicas=3 deployment currency-exchange-kubernetes
- scale the deployment to 3 replicaskubectl get hpa
- get the horizontal pod autoscalerkubectl autoscale deployment currency-exchange-kubernetes --cpu-percent=50 --min=1 --max=3
- create the horizontal pod autoscalerkubectl top pods
- get the cpu and memory usage of the podskubectl top nodes
- get the cpu and memory usage of the nodeskubectl delete hpa currency-exchange-kubernetes
kubectl get pods
kubectl delete pod currency-exchange-kubernetes-xxxxx
Current workaround is reload VS Code window, or F1 ->Clean the java language server workspace.
Reference: https://stackoverflow.com/questions/57857855/could-not-find-or-load-main-class-vs-code