Giter VIP home page Giter VIP logo

spring-microservices-refresher's Introduction

Spring Microservices Refresher (SMR)

Introduction

  • Spring boot
  • Spring Cloud
  • Spring Cloud Gateway
  • Resilience4j
  • Docker
  • Kubernetes

Microservices Overview

Screenshot

Naming Server

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.

Screenshot

In this example we use Eureka naming server.

Screenshot

Load Balancing

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.

Screenshot

API Gateway (Spring Cloud Gateway)

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.

Obeservability and OpenTelemetry

  • Obeservability is the ability to understand the internal state of a system by means of its external outputs.
    • Step 1 - gather data (metrics, logs, traces)
    • Step 2 - analyse data (dashboards, alerts, reports, AI/Ops, anomaly detection)
  • OpenTelemetry is a collection of tools, APIs, and SDKs. You can use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) for analysis in order to understand your software's performance and behavior.

Distributed Tracing (Zipkin)

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.

Screenshot

In this example we use Zipkin distributed tracing.

  1. docker run -d -p 9411:9411 openzipkin/zipkin
  2. http://localhost:9411/zipkin/

Spring Boot Actuator

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

Micrometer (Spring Boot Actuator)

  • Micrometer is a metrics instrumentation library for JVM-based applications. It provides a simple facade over the instrumentation clients for the most popular monitoring systems, allowing you to instrument your code without vendor lock-in. Think SLF4J, but for metrics.

OpenTelemetry (Spring Boot Actuator)

  • OpenTelemetry is a collection of tools, APIs, and SDKs. You can use it to instrument, generate, collect, and export telemetry data (metrics, logs, and traces) for analysis in order to understand your software's performance and behavior.

Docker

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

Screenshot

Docker Architecture

Screenshot

Docker example commands

  • docker events - show events
  • docker info - show info
  • docker stats - show stats metrics
  • docker system df - show disk usage of docker
  • docker inspect <container id> - show details of container
  • docker top <container id> - show processes running inside container
  • docker ps - list running containers
  • docker ps -a - list all containers
  • docker images - list images
  • docker run <image-name> - run image
  • docker 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 start
  • docker run -p 8080:8080 <image-name> - run image and map port 8080 to 8080
  • docker logs <container id> - show logs
  • docker logs <container id> -f - show logs and follows
  • docker image history <image-name> - show history of image
  • docker image inspect <image-name> - show details of image
  • docker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=dev" <image-name> - run image and map port 8080 to 8080 and set environment variable
  • docker 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 variable
  • docker 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 variable
  • docker 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 variable
  • docker 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 variable
  • docker 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 variable

Creating a container image with Maven

  • Add the following to the pom.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>

Creating images with Maven

  1. For each microservice repo: mvn spring-boot:build-image -DskipTests

Running images with Docker manually

  • 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

Running images with Docker Compose

  • Navigate to docker-compose.yaml and execute docker-compose up
  • docker-compose down - remove all containers, networks, and volumes

Spring Cloud Gateway

Screenshot

  • Simple effective way to route APIs
  • Provide cross-cutting concerns like:
    • security
    • monitoring/metrics
    • resiliency
  • Built on top of Spring WebFlux framework(non-blocking, reactive)
  • Features:
    • Matching routes on any request attribute
    • Dynamic routing
    • Predicates
    • Filters
    • Integrates with Spring Cloud DiscoveryClient (Load Balancing - Eureka, Consul, Zookeeper, etc)
    • Path Rewriting

Circuit Breaker (Resilience4j)

  • The library is inspired by Hystrix
  • but offers a much more convenient API and a number of other features:
    • Rate Limiter (block too frequent requests)
    • Bulkhead (avoid too many concurrent requests)
    • Retry (automatically retry failed requests)
    • Cache (avoid duplicate requests)
    • Circuit Breaker (avoid cascading failures)
    • Time Limiter (avoid too long running requests)
    • Event Listeners (monitoring)

Screenshot

Testing endpoint with multiple requests using Apache Bench

  • Open terminal
  • Run ab -n 1000 -c 100 http://localhost:8000/sample-api

Container Orchestration

  • Container orchestration is the process of managing containers at scale
  • Container orchestration tools help to automate the deployment, scaling, and management of containerized applications
  • Container orchestration tools are used to manage the lifecycle of containers

Screenshot

Kubernetes

  • Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications
  • Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation
  • Kubernetes is a production-ready platform that can be used to deploy and manage containerized applications in a cloud environment
  • Kubernetes is a container orchestration tool that is used to automate the deployment, scaling, and management of containerized applications

Screenshot

Kubernetes Architecture

  • Kubernetes is a cluster of nodes
  • A node is a worker machine in Kubernetes
  • A node may be a VM or physical machine, depending on the cluster
  • Each node has the services necessary to run Pods and is managed by the master components
  • The control plane's components make global decisions about the cluster (e.g., scheduling), as well as detecting and responding to cluster events (e.g., starting up a new pod when a deployment's replicas field is unsatisfied)
  • The control plane's components include the Kubernetes API server, scheduler, and core resource controllers
  • The node components run on every node, maintaining running pods and providing the Kubernetes runtime environment

Screenshot

Kuberenetes uses single responsibility (pods, services, deployments, etc) to manage containers

  • manage workloads
  • provide external access to workloads
  • enable scaling
  • enable zero downtime deployments
Kubernetes Master Node
  • The master node is responsible for managing the cluster
  • The master node runs the Kubernetes control plane
  • The Kubernetes control plane consists of the Kubernetes API server, scheduler, and core resource controllers

Api Server

  • The API server is the front end for the Kubernetes control plane
  • The API server is the only Kubernetes component that talks to the Kubernetes API
  • The API server is responsible for:
    • serving the Kubernetes API
    • scheduling workloads
    • controlling access to the cluster
    • maintaining the current state of the cluster
    • scaling the cluster

Distributed Database (etcd)

  • The distributed database is a highly available key-value store used as Kubernetes' backing store for all cluster data
  • The distributed database is used to store the state of the cluster

Scheduler

  • The scheduler is responsible for distributing workloads across the cluster
  • The scheduler watches newly created pods that have no node assigned
  • For every pod that the scheduler discovers, the scheduler becomes responsible for finding the best node for that pod to run on
  • The scheduler makes scheduling decisions based on the configured policies

Controller Manager

  • The controller manager is a daemon that embeds the core control loops
  • A control loop is a non-terminating loop that regulates the state of the cluster
  • The controller manager runs all the control loops in separate goroutines
  • The controller manager is responsible for:
    • maintaining the desired state of the cluster
    • responding to cluster events (e.g., starting up a new pod when a deployment's replicas field is unsatisfied)
    • managing the shared state of the cluster

Screenshot

Kubernetes Worker Node
  • The worker node is responsible for running the workloads
  • The worker node runs the Kubernetes node components
  • The Kubernetes node components include kubelet, kube-proxy, and container runtime

Kubelet

  • The kubelet is the primary "node agent" that runs on each node
  • The kubelet is responsible for:
    • ensuring that containers are running in a pod
    • reporting the node's health
    • handling node-level events (e.g., starting up a pod when a deployment's replicas field is unsatisfied)

Kube Proxy

  • The kube proxy is responsible for maintaining network rules on the node
  • The kube proxy maintains network rules on the node
  • These network rules allow network communication to your Pods from network sessions inside or outside of your cluster
  • The kube proxy uses the operating system packet filtering layer if there is one and it's available
  • The kube proxy maintains network rules on the node
  • These network rules allow network communication to your Pods from network sessions inside or outside of your cluster
  • The kube proxy uses the operating system packet filtering layer if there is one and it's available

Container Runtime

  • The container runtime is the software that is responsible for running containers

Screenshot

Kubernetes Pods!

  • A pod is the smallest deployable unit of computing that can be created and managed in Kubernetes
  • A pod (as in a pod of whales or pea pod) is a group of one or more containers (such as Docker containers), with shared storage/network, and a specification for how to run the containers
  • A pod's contents are always co-located and co-scheduled, and run in a shared context
  • A pod models an application-specific "logical host" - it contains one or more application containers which are relatively tightly coupled
  • A pod can contain different application containers which are relatively tightly coupled

Screenshot

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 pod

How to get a pod's shell?

  • kubectl exec -it <pod-name> -- /bin/bash - get a shell for a pod

How to describe a pod?

  • kubectl describe pod <pod-name> - get detailed information about a pod

Kubernetes ReplicaSets

  • A ReplicaSet's purpose is to maintain a stable set of replica Pods running at any given time
  • A ReplicaSet is defined with fields, including a selector which specifies how to identify Pods it can acquire, a number of replicas indicating how many Pods it should be maintaining, and a pod template specifying the data of new Pods it should create to meet the number of replicas criteria
  • A ReplicaSet is responsible for creating and deleting Pods as needed to reach the desired number of replicas
  • A ReplicaSet is often used to guarantee the availability of a specified number of identical Pods

How to get a ReplicaSets

  • kubectl get replicasets - get all ReplicaSets or kubectl get rs - get all ReplicaSets

Kubernetes Deployments

  • A Deployment provides declarative updates for Pods and ReplicaSets
  • You describe a desired state in a Deployment object, and the Deployment controller changes the actual state to the desired state at a controlled rate
  • You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments
  • A Deployment checks on the health of your Pods and makes sure that a specified number of them are always running
  • If a Pod fails, the Deployment controller replaces it with a new one
  • A Deployment can also be used to update the configuration of running Pods

Screenshot

How to scale a deployment?

  • kubectl scale deployment <deployment-name> --replicas=3 - scale a deployment to 3 replicas

How 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 image

How to get a deployment's history?

  • kubectl rollout history deployment <deployment-name> - get a deployment's history

How to rollback a deployment?

  • kubectl rollout undo deployment <deployment-name> - rollback a deployment

Kubernetes Services

  • A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them
  • Services enable a loose coupling between dependent Pods
  • A Service can be configured to route traffic to a set of Pods
  • A Service can be configured to proxy traffic to a set of Pods
  • A Service can be configured to proxy traffic to a single Pod
  • A Service can be configured to expose multiple identical Pods as a single virtual IP address
  • A Service can be configured to expose a set of Pods as a virtual IP address that is not managed by Kubernetes
  • A Service can be configured to expose a set of Pods as a DNS name that is not managed by Kubernetes
  • A Service can be configured to expose a set of Pods as a DNS name that is managed by Kubernetes
  • A Service can be configured to expose a set of Pods as a set of DNS records that are managed by Kubernetes
  • A Service can be configured to expose a set of Pods as a set of DNS records that are managed by Kubernetes and are resolvable from outside the cluster
  • A Service can be configured to expose a set of Pods as a set of DNS records that are managed by Kubernetes and are resolvable from outside the cluster and are load balanced
  • A Service can be configured to expose a set of Pods as a set of DNS records that are managed by Kubernetes and are resolvable from outside the cluster and are load balanced and are sticky (session-affinity)
  • A Service can be configured to expose a set of Pods as a set of DNS records that are managed by Kubernetes and are resolvable from outside the cluster and are load balanced and are sticky (session-affinity) and are load balanced across multiple ports
  • A Service can be configured to expose a set of Pods as a set of DNS records that are managed by Kubernetes and are resolvable from outside the cluster and are load balanced and are sticky (session-affinity) and are load balanced across multiple ports and are load balanced across multiple protocols
  • A Service can be configured to expose a set of Pods as a set of DNS records that are managed by Kubernetes and are resolvable from outside the cluster and are load balanced and are sticky (session-affinity) and are load balanced across multiple ports and are load balanced across multiple protocols and are load balanced across multiple ports and protocols

Kubernetes Responsibilities

  • Kubernetes is responsible for:
    • Scheduling
    • Scaling
    • Load balancing
    • Health checks
    • Rolling updates
    • Rollbacks
    • Service discovery
    • Secret and configuration management
    • Storage orchestration
    • Batch execution
    • Access control
    • Monitoring
    • Logging
    • Self-healing
    • Auto-scaling
    • Multi-tenancy
    • Multi-cloud support

Example kubectl commands

  • kubectl create deployment hello-world --image=gcr.io/google-samples/hello-app:1.0 - create a deployment
  • kubectl get deployments - list all deployments
  • kubectl expose deployment hello-world --type=LoadBalancer --port=8080 - expose a deployment
  • kubectl scale deployment hello-world --replicas=3 - scale a deployment
  • kubectl delete pod hello-world-xxxxx - delete a pod
  • kubectl autoscale deployment hello-world --min=3 --max=10 --cpu-percent=80 - autoscale a deployment

Edit deployment.extensions/hello-world

  • kubectl edit deployment.extensions/hello-world

Check events

  • kubectl get events
  • kubectl get events --sort-by=.metadata.creationTimestamp - sort events by creation timestamp

Check pods

  • kubectl get pods

Check replicasets

  • kubectl get replicasets

Check deployments

  • kubectl get deployments

Check services

  • 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

Cloud Orchestration Options

  • AWS
    • Elastic Container Service (ECS)
    • Elastic Kubernetes Service (EKS)
    • Fargate
  • Azure
    • Azure Kubernetes Service (AKS)
    • Azure Container Instances (ACI)
  • Google Cloud
    • Google Kubernetes Engine (GKE)
    • Google Cloud Run

Google Cloud Engine (GKE)

Install Google Cloud SDK

Quickstart with K8s/Docker/Maven

  1. Create Maven project images (/kubernetes/)
    • mvn clean package
    • Run docker daemon
    • mvn spring-boot:build-image -DskipTests
  2. 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
    • Check docker registry https://hub.docker.com/u/seanmayerz
  3. Create Kubernetes cluster in GKE
  • Login to https://cloud.google.com/ (using free trial credits)
  • Create new project
  • Enable Kubernetes Engine API
  • Create cluster Screenshot
  • Cluster configuration Screenshot
  • Cluster network configuration Screenshot
  1. Create/Connect to GKE Cluster
  • Install Google Cloud SDK
  • gcloud init
  • gcloud auth login
  • Create cluster (not autopilot)
    • gcloud container clusters create smr-cluster --zone europe-west2-a --num-nodes 1
  • Connect to GKE cluster using cloud shell (you can also use your local machine) Screenshot
  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 command
  • kubectl describe deployment currency-conversion-kubernetes - check environment variables
  1. Open GKE Kuberenetes GKE cloud shell
  • curl http://{{EXTERNAL-IP}}:8000/currency-exchange/from/USD/to/INR - get external ip from kubectl get svc command
  • curl http://{{EXTERNAL-IP}}:8100/currency-conversion-feign/from/USD/to/INR/quantity/10 - get external ip from kubectl get svc command
  1. Create declaritive configuration yaml for currency-exchange-service
  • kubectl get deployments
  • cd into /kubernetes/currency-exchange-service
  • kubectl get deployment currency-exchange-kubernetes -o yaml - get yaml for existing deployment
  • kubectl get deployment currency-exchange-kubernetes -o yaml > deployment.yaml - save yaml for existing deployment
  • kubectl 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)
  1. Create declaritive configuration yaml for currency-conversion-service
  • kubectl get deployments
  • cd into /kubernetes/currency-conversion-service
  • kubectl get deployment currency-conversion-kubernetes -o yaml > deployment.yaml - save yaml for existing deployment
  • kubectl 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)
  1. Deploy declaritive configuration yaml for currency-exchange-service
  • kubectl diff -f deployment.yaml - check diff
  • kubectl 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 action
  1. Deploy declaritive configuration yaml for currency-conversion-service
  • kubectl diff -f deployment.yaml - check diff
  • kubectl 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 action
  1. Enable Logging and Tracing in Google Cloud
  • In Google Cloud search API & Services
  • Enable API & Services Screenshot
  • Search Cloud Logging
  • Enable Cloud Logging Screenshot
  • Also search Stackdrivers
  • Enable all of these: Screenshot
  1. Deploying Microservice using YAML deployment
  • First delete the existing deployment and service
    • kubectl delete all -l app=currency-exchange-kubernetes
    • kubectl delete all -l app=currency-conversion-kubernetes
  • kubectl get all (should only see cluster-ip service)
  • Go to /kubernetes/currency-exchange-service and /kubernetes/currency-conversion-service and run kubectl apply -f deployment.yaml
  • kubectl get all (should see deployment, replicaset, pod, service)
  • kubectl get pods (should see 2 pods)
  • kubectl get rs (should see 2 replicasets)
  • kubectl get svc --watch (wait eventually should see 2 services)
  • curl http://{{EXTERNAL-IP}}:8000/currency-exchange/from/USD/to/INR - get external ip from kubectl get svc command
  1. Deploying Microservice using YAML deployment with ConfigMap
  • kubectl create configmap currency-conversion-kubernetes --from-literal=CURRENCY_EXCHANGE_SERVICE_URI=http://currency-exchange-kubernetes
  • kubectl get configmap
  • kubectl get configmap currency-conversion-kubernetes
  • kubectl get configmap currency-conversion-kubernetes -o yaml
  • kubectl get configmap currency-conversion-kubernetes -o yaml > configmap.yaml
  • copy the configmap yaml to the deployment yaml
  • kubectl apply -f deployment.yaml
  1. Monitoring centralised logging in GKE
  • Go to https://console.cloud.google.com/kubernetes/list/overview
  • Click on the cluster
  • Click on View Logs
  • Click on View GKE Dashboard
  • Click on Workloads
  • Click on currency-conversion-kubernetes
  • Click on currency-conversion-kubernetes-xxxxx
  • Click on View Logs
  • Click on Workloads
  • Click on currency-exchange-kubernetes
  • Click on currency-exchange-kubernetes-xxxxx
  1. 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)
  1. Deploying Microservice using YAML deployment with Secrets
  • 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
  • copy the secrets yaml to the deployment yaml
  • kubectl apply -f deployment.yaml
  1. Configuring Readiness and Liveness Probes

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.

  • /health/readiness - for readiness probe
  • /health/liveness - for liveness probe

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 ip
  • watch curl http://{{EXTERNAL-IP}}:8000/actuator/health - watch the health status
  • watch 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
  1. Scaling pods manually
  • kubectl get pods
  • kubectl scale --replicas=3 deployment currency-exchange-kubernetes - scale the deployment to 3 replicas
  1. Scaling pods automatically
  • kubectl get hpa - get the horizontal pod autoscaler
  • kubectl autoscale deployment currency-exchange-kubernetes --cpu-percent=50 --min=1 --max=3 - create the horizontal pod autoscaler
  1. Checking resources
  • kubectl top pods - get the cpu and memory usage of the pods
  • kubectl top nodes - get the cpu and memory usage of the nodes
  1. Deleting autoscaler
  • kubectl delete hpa currency-exchange-kubernetes
  1. Deleting Cluster in GKE

Screenshot

Bonus

Deleting pods

  • kubectl get pods
  • kubectl delete pod currency-exchange-kubernetes-xxxxx

Issues

Running multiple springboot microservice projects in VSCode (Without Docker)

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

spring-microservices-refresher's People

Contributors

seanmayer avatar

Stargazers

 avatar Thanawat avatar  avatar

Watchers

 avatar

spring-microservices-refresher's Issues

Docker microservice not connecting to eureka server

Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://localhost:8761/eureka/}, exception=I/O error on GET request for "http://localhost:8761/eureka/apps/": Connect to http://localhost:8761 [localhost/127.0.0.1] failed: Connection refused stacktrace=org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8761/eureka/apps/": Connect to http://localhost:8761 [localhost/127.0.0.1] failed: Connection refused

HTTP method names must be tokens

Error parsing HTTP request header
 Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.

java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x030x010xcb0x010x000x010xc70x030x030xed0x0er0x0f0xec0xb60xa8$r0xee0xd60x1cA0xd80xc1o0xc50x130xd50x0boo0xbd0x07+0x070xc20x1at0xc80xb30xb2 ]. HTTP method names must be tokens
        at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:419) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:271) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:891) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1784) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.71.jar:9.0.71]
        at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

Internal server error when calling currency conversion endpoint

Error:

curl http://{{EXTERNAL-IP}}:8100/currency-conversion-feign/from/USD/to/INR/quantity/10
{"timestamp":"2023-05-03T06:24:26.730+00:00","status":500,"error":"Internal Server Error","path":              "/currency-conversion-feign/from/USD/to/INR/quantity/10"}Seans-MBP:spring-microservices-refresher

Pod logs:

Setting Active Processor Count to 2
Calculating JVM memory based on 2971752K available memory
For more information on this calculation, see https://paketo.io/docs/reference/java-reference/#memory-calculator
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx2567765K -XX:MaxMetaspaceSize=96786K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 2971752K, Thread Count: 50, Loaded Class Count: 14674, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 124 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX:+ExitOnOutOfMemoryError -XX:ActiveProcessorCount=2 -XX:MaxDirectMemorySize=10M -Xmx2567765K -XX:MaxMetaspaceSize=96786K -XX:ReservedCodeCacheSize=240M -Xss1M -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.3)
2023-05-03T06:19:38.716Z  INFO [currency-conversion,,] 1 --- [           main] m.c.CurrencyConversionServiceApplication : Starting CurrencyConversionServiceApplication v0.0.1-SNAPSHOT using Java 17.0.6 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2023-05-03T06:19:38.747Z  INFO [currency-conversion,,] 1 --- [           main] m.c.CurrencyConversionServiceApplication : No active profile set, falling back to 1 default profile: "default"
2023-05-03T06:19:43.861Z  INFO [currency-conversion,,] 1 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=9e10515f-68de-3827-8417-5a1010ea22b1
2023-05-03T06:19:44.741Z  INFO [currency-conversion,,] 1 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'com.microservices.currencyconversionservice.CurrencyExchangeProxy' of type [org.springframework.cloud.openfeign.FeignClientFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2023-05-03T06:19:45.913Z  INFO [currency-conversion,,] 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8100 (http)
2023-05-03T06:19:45.942Z  INFO [currency-conversion,,] 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-05-03T06:19:45.943Z  INFO [currency-conversion,,] 1 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.5]
2023-05-03T06:19:46.429Z  INFO [currency-conversion,,] 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-05-03T06:19:46.433Z  INFO [currency-conversion,,] 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 7204 ms
2023-05-03T06:19:50.599Z  WARN [currency-conversion,,] 1 --- [           main] iguration$LoadBalancerCaffeineWarnLogger : Spring Cloud LoadBalancer is currently working with the default cache. While this cache implementation is useful for development and tests, it's recommended to use Caffeine cache in production.You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2023-05-03T06:19:50.637Z  INFO [currency-conversion,,] 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint(s) beneath base path '/actuator'
2023-05-03T06:19:50.769Z  INFO [currency-conversion,,] 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8100 (http) with context path ''
2023-05-03T06:19:50.812Z  INFO [currency-conversion,,] 1 --- [           main] m.c.CurrencyConversionServiceApplication : Started CurrencyConversionServiceApplication in 14.414 seconds (process running for 15.823)
2023-05-03T06:24:26.450Z  INFO [currency-conversion,,] 1 --- [nio-8100-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-05-03T06:24:26.451Z  INFO [currency-conversion,,] 1 --- [nio-8100-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-05-03T06:24:26.456Z  INFO [currency-conversion,,] 1 --- [nio-8100-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms
2023-05-03T06:24:26.652Z  INFO [currency-conversion,65f6dc3206e60887a198c9894c04cbcb,3398e887aa81f8cb] 1 --- [nio-8100-exec-1] c.m.c.CurrencyConversionController       : calculateCurrencyConversion called with USD to INR
2023-05-03T06:24:26.711Z ERROR [currency-conversion,,] 1 --- [nio-8100-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: feign.RetryableException: Connection refused executing GET http://localhost:8000/currency-exchange/from/USD/to/INR] with root cause
java.net.ConnectException: Connection refused
	at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
	at java.base/sun.nio.ch.Net.pollConnectNow(Unknown Source) ~[na:na]
	at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(Unknown Source) ~[na:na]
	at java.base/sun.nio.ch.NioSocketImpl.connect(Unknown Source) ~[na:na]
	at java.base/java.net.Socket.connect(Unknown Source) ~[na:na]
	at java.base/sun.net.NetworkClient.doConnect(Unknown Source) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.openServer(Unknown Source) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.openServer(Unknown Source) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.<init>(Unknown Source) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.New(Unknown Source) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.New(Unknown Source) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source) ~[na:na]
	at java.base/java.net.HttpURLConnection.getResponseCode(Unknown Source) ~[na:na]
	at feign.Client$Default.convertResponse(Client.java:110) ~[feign-core-12.1.jar:na]
	at feign.Client$Default.execute(Client.java:106) ~[feign-core-12.1.jar:na]
	at feign.micrometer.MicrometerObservationCapability.lambda$enrich$1(MicrometerObservationCapability.java:53) ~[feign-micrometer-12.1.jar:na]
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:102) ~[feign-core-12.1.jar:na]
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:72) ~[feign-core-12.1.jar:na]
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:98) ~[feign-core-12.1.jar:na]
	at jdk.proxy2/jdk.proxy2.$Proxy86.retrieveExchangeValue(Unknown Source) ~[na:na]
	at com.microservices.currencyconversionservice.CurrencyConversionController.calculateCurrencyConversionFeign(CurrencyConversionController.java:65) ~[classes/:0.0.1-SNAPSHOT]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) ~[spring-web-6.0.5.jar:6.0.5]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) ~[spring-web-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:705) ~[tomcat-embed-core-10.1.5.jar:6.0]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.0.5.jar:6.0.5]
	at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) ~[tomcat-embed-core-10.1.5.jar:6.0]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.0.5.jar:6.0.5]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.5.jar:6.0.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.0.5.jar:6.0.5]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.5.jar:6.0.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:109) ~[spring-web-6.0.5.jar:6.0.5]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.5.jar:6.0.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.0.5.jar:6.0.5]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.5.jar:6.0.5]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:741) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-10.1.5.jar:10.1.5]
	at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]

RouteLocator not rerouting requests

Whitelabel Error Page
This application has no configured error view, so you are seeing this as a fallback.

Tue Feb 14 07:42:57 GMT 2023
[da2b2d12-15] There was an unexpected error (type=Not Found, status=404).
org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND
	at org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$1(ResourceWebHandler.java:408)
	Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ HTTP GET "/currency-exchange/from/USD/to/INR" [ExceptionHandlingWebHandler]
Original Stack Trace:
		at org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$1(ResourceWebHandler.java:408)
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)
		at reactor.core.publisher.Mono.subscribe(Mono.java:4490)
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:82)
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:181)
		at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:102)
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:368)
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:219)
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201)
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83)
		at reactor.core.publisher.Mono.subscribe(Mono.java:4490)
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263)
		at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51)
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
		at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74)
		at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:282)
		at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863)
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
		at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2400)
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171)
		at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2196)
		at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2070)
		at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
		at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)
		at reactor.core.publisher.Mono.subscribe(Mono.java:4490)
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:451)
		at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:219)
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201)
		at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83)
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
		at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
		at reactor.core.publisher.Mono.subscribe(Mono.java:4490)
		at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263)
		at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51)
		at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
		at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
		at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:1002)
		at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:707)
		at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:477)
		at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:593)
		at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:223)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
		at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
		at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
		at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
		at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
		at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
		at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
		at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
		at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
		at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
		at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
		at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
		at java.base/java.lang.Thread.run(Thread.java:833)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.