0%

A step-by-step guide to creating and deploying production-quality microservices-based applications

Key Features

  • Build cloud-native production-ready microservices with this comprehensively updated guide
  • Understand the challenges of building large-scale microservice architectures
  • Learn how to get the best out of Spring Cloud, Kubernetes, and Istio in combination

Book Description

With this book, you'll learn how to efficiently build and deploy microservices. This new edition has been updated for the most recent versions of Spring, Java, Kubernetes, and Istio, demonstrating faster and simpler handling of Spring Boot, local Kubernetes clusters, and Istio installation. The expanded scope includes native compilation of Spring-based microservices, support for Mac and Windows with WSL2, and an introduction to Helm 3 for packaging and deployment. A revamped security chapter now follows the OAuth 2.1 specification and makes use of the newly launched Spring Authorization Server from the Spring team.

Starting with a set of simple cooperating microservices, you'll add persistence and resilience, make your microservices reactive, and document their APIs using OpenAPI.

You'll understand how fundamental design patterns are applied to add important functionality, such as service discovery with Netflix Eureka and edge servers with Spring Cloud Gateway. You'll learn how to deploy your microservices using Kubernetes and adopt Istio. You'll explore centralized log management using the Elasticsearch, Fluentd, and Kibana (EFK) stack and monitor microservices using Prometheus and Grafana.

By the end of this book, you'll be confident in building microservices that are scalable and robust using Spring Boot and Spring Cloud.

What you will learn

  • Build reactive microservices using Spring Boot
  • Develop resilient and scalable microservices using Spring Cloud
  • Use OAuth 2.1/OIDC and Spring Security to protect public APIs
  • Implement Docker to bridge the gap between development, testing, and production
  • Deploy and manage microservices with Kubernetes
  • Apply Istio for improved security, observability, and traffic management
  • Write and run automated microservice tests with JUnit, testcontainers, Gradle, and bash

Who this book is for

This book is intended for Java and Spring developers and architects who want to learn how to build microservice landscapes from the ground up and deploy them either on-premises or in the cloud, using Kubernetes as a container orchestrator and Istio as a service mesh.

No familiarity with microservices architecture is required to get started with this book.

Table of Contents

  1. Preface
    1. Who this book is for
    2. What this book covers
    3. To get the most out of this book
    4. Get in touch
  2. Part I: Getting Started with Microservice Development Using Spring Boot
    1. Introduction to Microservices
    2. Technical requirements
    3. My way into microservices
    4. Benefits of autonomous software components
    5. Challenges with autonomous software components
    6. Enter microservices
    7. A sample microservice landscape
    8. Defining a microservice
    9. Challenges with microservices
    10. Design patterns for microservices
    11. Service discovery
    12. Problem
    13. Solution
    14. Solution requirements
    15. Edge server
    16. Problem
    17. Solution
    18. Solution requirements
    19. Reactive microservices
    20. Problem
    21. Solution
    22. Solution requirements
    23. Central configuration
    24. Problem
    25. Solution
    26. Solution requirements
    27. Centralized log analysis
    28. Problem
    29. Solution
    30. Solution requirements
    31. Distributed tracing
    32. Problem
    33. Solution
    34. Solution requirements
    35. Circuit breaker
    36. Problem
    37. Solution
    38. Solution requirements
    39. Control loop
    40. Problem
    41. Solution
    42. Solution requirements
    43. Centralized monitoring and alarms
    44. Problem
    45. Solution
    46. Solution requirements
    47. Software enablers
    48. Other important considerations
    49. Summary
    50. Introduction to Spring Boot
    51. Technical requirements
    52. Spring Boot
    53. Convention over configuration and fat JAR files
    54. Code examples for setting up a Spring Boot application
    55. The magic @SpringBootApplication annotation
    56. Component scanning
    57. Java-based configuration
    58. Spring WebFlux
    59. Code examples of setting up a REST service
    60. Starter dependencies
    61. Property files
    62. Sample RestController
    63. springdoc-openapi
    64. Spring Data
    65. Entity
    66. Repositories
    67. Spring Cloud Stream
    68. Code examples for sending and receiving messages
    69. Docker
    70. Summary
    71. Questions
    72. Creating a Set of Cooperating Microservices
    73. Technical requirements
    74. Introducing the microservice landscape
    75. Information handled by the microservices
    76. Product service
    77. Review service
    78. Recommendation service
    79. Product composite service
    80. Infrastructure-related information
    81. Temporarily replacing service discovery
    82. Generating skeleton microservices
    83. Using Spring Initializr to generate skeleton code
    84. Setting up multi-project builds in Gradle
    85. Adding RESTful APIs
    86. Adding an API and a util project
    87. The API project
    88. The util project
    89. Implementing our API
    90. Adding a composite microservice
    91. API classes
    92. Properties
    93. Integration component
    94. Composite API implementation
    95. Adding error handling
    96. The global REST controller exception handler
    97. Error handling in API implementations
    98. Error handling in the API client
    99. Testing APIs manually
    100. Adding automated microservice tests in isolation
    101. Adding semi-automated tests of a microservice landscape
    102. Trying out the test script
    103. Summary
    104. Questions
    105. Deploying Our Microservices Using Docker
    106. Technical requirements
    107. Introduction to Docker
    108. Running our first Docker commands
    109. Challenges with running Java in Docker
    110. Limiting available CPUs
    111. Limiting available memory
    112. Using Docker with one microservice
    113. Changes in source code
    114. Building a Docker image
    115. Starting up the service
    116. Running the container detached
    117. Managing a landscape of microservices using Docker Compose
    118. Changes in the source code
    119. Starting up the microservice landscape
    120. Automating tests of cooperating microservices
    121. Troubleshooting a test run
    122. Summary
    123. Questions
    124. Adding an API Description Using OpenAPI
    125. Technical requirements
    126. Introduction to using springdoc-openapi
    127. Adding springdoc-openapi to the source code
    128. Adding dependencies to the Gradle build files
    129. Adding OpenAPI configuration and general API documentation to the ProductCompositeService
    130. Adding API-specific documentation to the ProductCompositeService interface
    131. Building and starting the microservice landscape
    132. Trying out the OpenAPI documentation
    133. Summary
    134. Questions
    135. Adding Persistence
    136. Technical requirements
    137. Chapter objectives
    138. Adding a persistence layer to the core microservices
    139. Adding dependencies
    140. Storing data with entity classes
    141. Defining repositories in Spring Data
    142. Writing automated tests that focus on persistence
    143. Using Testcontainers
    144. Writing persistence tests
    145. Using the persistence layer in the service layer
    146. Logging the database connection URL
    147. Adding new APIs
    148. Calling the persistence layer from the service layer
    149. Declaring a Java bean mapper
    150. Updating the service tests
    151. Extending the composite service API
    152. Adding new operations in the composite service API
    153. Adding methods in the integration layer
    154. Implementing the new composite API operations
    155. Updating the composite service tests
    156. Adding databases to the Docker Compose landscape
    157. The Docker Compose configuration
    158. Database connection configuration
    159. The MongoDB and MySQL CLI tools
    160. Manual tests of the new APIs and the persistence layer
    161. Updating the automated tests of the microservice landscape
    162. Summary
    163. Questions
    164. Developing Reactive Microservices
    165. Technical requirements
    166. Choosing between non-blocking synchronous APIs and event-driven asynchronous services
    167. Developing non-blocking synchronous REST APIs
    168. An introduction to Project Reactor
    169. Non-blocking persistence using Spring Data for MongoDB
    170. Changes in the test code
    171. Non-blocking REST APIs in the core services
    172. Changes in the APIs
    173. Changes in the service implementations
    174. Changes in the test code
    175. Dealing with blocking code
    176. Non-blocking REST APIs in the composite services
    177. Changes in the API
    178. Changes in the service implementation
    179. Changes in the integration layer
    180. Changes in the test code
    181. Developing event-driven asynchronous services
    182. Handling challenges with messaging
    183. Consumer groups
    184. Retries and dead-letter queues
    185. Guaranteed order and partitions
    186. Defining topics and events
    187. Changes in the Gradle build files
    188. Consuming events in the core services
    189. Declaring message processors
    190. Changes in the service implementations
    191. Adding configuration for consuming events
    192. Changes in the test code
    193. Publishing events in the composite service
    194. Publishing events in the integration layer
    195. Adding configuration for publishing events
    196. Changes in the test code
    197. Running manual tests of the reactive microservice landscape
    198. Saving events
    199. Adding a health API
    200. Using RabbitMQ without using partitions
    201. Using RabbitMQ with partitions
    202. Using Kafka with two partitions per topic
    203. Running automated tests of the reactive microservice landscape
    204. Summary
    205. Questions
  3. Part II: Leveraging Spring Cloud to Manage Microservices
    1. Introduction to Spring Cloud
    2. Technical requirements
    3. The evolution of Spring Cloud
    4. Using Netflix Eureka for service discovery
    5. Using Spring Cloud Gateway as an edge server
    6. Using Spring Cloud Config for centralized configuration
    7. Using Resilience4j for improved resilience
    8. Sample usage of the circuit breaker in Resilience4j
    9. Using Spring Cloud Sleuth and Zipkin for distributed tracing
    10. Summary
    11. Questions
    12. Adding Service Discovery Using Netflix Eureka
    13. Technical requirements
    14. Introducing service discovery
    15. The problem with DNS-based service discovery
    16. Challenges with service discovery
    17. Service discovery with Netflix Eureka in Spring Cloud
    18. Setting up a Netflix Eureka server
    19. Connecting microservices to a Netflix Eureka server
    20. Setting up the configuration for development use
    21. Eureka configuration parameters
    22. Configuring the Eureka server
    23. Configuring clients to the Eureka server
    24. Trying out the discovery service
    25. Scaling up
    26. Scaling down
    27. Disruptive tests with the Eureka server
    28. Stopping the Eureka server
    29. Stopping a review instance
    30. Starting up an extra instance of the product service
    31. Starting up the Eureka server again
    32. Summary
    33. Questions
    34. Using Spring Cloud Gateway to Hide Microservices behind an Edge Server
    35. Technical requirements
    36. Adding an edge server to our system landscape
    37. Setting up Spring Cloud Gateway
    38. Adding a composite health check
    39. Configuring a Spring Cloud Gateway
    40. Routing rules
    41. Trying out the edge server
    42. Examining what is exposed outside the Docker engine
    43. Trying out the routing rules
    44. Calling the product composite API through the edge server
    45. Calling the Swagger UI through the edge server
    46. Calling Eureka through the edge server
    47. Routing based on the host header
    48. Summary
    49. Questions
    50. Securing Access to APIs
    51. Technical requirements
    52. Introduction to OAuth 2.0 and OpenID Connect
    53. Introducing OAuth 2.0
    54. Introducing OpenID Connect
    55. Securing the system landscape
    56. Protecting external communication with HTTPS
    57. Replacing a self-signed certificate at runtime
    58. Securing access to the discovery server
    59. Changes in the Eureka server
    60. Changes in Eureka clients
    61. Adding a local authorization server
    62. Protecting APIs using OAuth 2.0 and OpenID Connect
    63. Changes in both the edge server and the product-composite service
    64. Changes in the product-composite service only
    65. Changes to allow Swagger UI to acquire access tokens
    66. Changes in the test script
    67. Testing with the local authorization server
    68. Building and running the automated tests
    69. Testing the protected discovery server
    70. Acquiring access tokens
    71. Acquiring access tokens using the client credentials grant flow
    72. Acquiring access tokens using the authorization code grant flow
    73. Calling protected APIs using access tokens
    74. Testing Swagger UI with OAuth 2.0
    75. Testing with an external OpenID Connect provider
    76. Setting up and configuring an account in Auth0
    77. Applying the required changes to use Auth0 as an OpenID provider
    78. Changing the configuration in the OAuth resource servers
    79. Changing the test script so it acquires access tokens from Auth0
    80. Running the test script with Auth0 as the OpenID Connect provider
    81. Acquiring access tokens using the client credentials grant flow
    82. Acquiring access tokens using the authorization code grant flow
    83. Calling protected APIs using the Auth0 access tokens
    84. Getting extra information about the user
    85. Summary
    86. Questions
    87. Centralized Configuration
    88. Technical requirements
    89. Introduction to the Spring Cloud Configuration server
    90. Selecting the storage type of the configuration repository
    91. Deciding on the initial client connection
    92. Securing the configuration
    93. Securing the configuration in transit
    94. Securing the configuration at rest
    95. Introducing the config server API
    96. Setting up a config server
    97. Setting up a routing rule in the edge server
    98. Configuring the config server for use with Docker
    99. Configuring clients of a config server
    100. Configuring connection information
    101. Structuring the configuration repository
    102. Trying out the Spring Cloud Configuration server
    103. Building and running automated tests
    104. Getting the configuration using the config server API
    105. Encrypting and decrypting sensitive information
    106. Summary
    107. Questions
    108. Improving Resilience Using Resilience4j
    109. Technical requirements
    110. Introducing the Resilience4j resilience mechanisms
    111. Introducing the circuit breaker
    112. Introducing the time limiter
    113. Introducing the retry mechanism
    114. Adding the resilience mechanisms to the source code
    115. Adding programmable delays and random errors
    116. Changes in the API definitions
    117. Changes in the product-composite microservice
    118. Changes in the product microservice
    119. Adding a circuit breaker and a time limiter
    120. Adding dependencies to the build file
    121. Adding annotations in the source code
    122. Adding fail-fast fallback logic
    123. Adding configuration
    124. Adding a retry mechanism
    125. Adding the retry annotation
    126. Adding configuration
    127. Adding automated tests
    128. Trying out the circuit breaker and retry mechanism
    129. Building and running the automated tests
    130. Verifying that the circuit is closed under normal operations
    131. Forcing the circuit breaker to open when things go wrong
    132. Closing the circuit breaker again
    133. Trying out retries caused by random errors
    134. Summary
    135. Questions
    136. Understanding Distributed Tracing
    137. Technical requirements
    138. Introducing distributed tracing with Spring Cloud Sleuth and Zipkin
    139. Adding distributed tracing to the source code
    140. Adding dependencies to build files
    141. Adding configuration for Spring Cloud Sleuth and Zipkin
    142. Adding Zipkin to the Docker Compose files
    143. Trying out distributed tracing
    144. Starting up the system landscape with RabbitMQ as the queue manager
    145. Sending a successful API request
    146. Sending an unsuccessful API request
    147. Sending an API request that triggers asynchronous processing
    148. Monitoring trace information passed to Zipkin in RabbitMQ
    149. Using Kafka as a message broker
    150. Summary
    151. Questions
  4. Part III: Developing Lightweight Microservices Using Kubernetes
    1. Introduction to Kubernetes
    2. Technical requirements
    3. Introducing Kubernetes concepts
    4. Introducing Kubernetes API objects
    5. Introducing Kubernetes runtime components
    6. Creating a Kubernetes cluster using Minikube
    7. Working with Minikube profiles
    8. Working with the Kubernetes CLI, kubectl
    9. Working with kubectl contexts
    10. Creating a Kubernetes cluster
    11. Trying out a sample deployment
    12. Managing a local Kubernetes cluster
    13. Hibernating and resuming a Kubernetes cluster
    14. Terminating a Kubernetes cluster
    15. Summary
    16. Questions
    17. Deploying Our Microservices to Kubernetes
    18. Technical requirements
    19. Replacing Netflix Eureka with Kubernetes Services
    20. Introducing how Kubernetes will be used
    21. Using Spring Boot's support for graceful shutdown and probes for liveness and readiness
    22. Introducing Helm
    23. Running Helm commands
    24. Looking into a Helm chart
    25. Helm templates and values
    26. The common library chart
    27. The ConfigMap template
    28. The Secrets template
    29. The Service template
    30. The Deployment template
    31. The components charts
    32. The environment charts
    33. Deploying to Kubernetes for development and test
    34. Building Docker images
    35. Resolving Helm chart dependencies
    36. Deploying to Kubernetes
    37. Changes in the test script for use with Kubernetes
    38. Testing the deployment
    39. Testing Spring Boot's support for graceful shutdown and probes for liveness and readiness
    40. Deploying to Kubernetes for staging and production
    41. Changes in the source code
    42. Deploying to Kubernetes
    43. Cleaning up
    44. Summary
    45. Questions
    46. Implementing Kubernetes Features to Simplify the System Landscape
    47. Technical requirements
    48. Replacing the Spring Cloud Config Server
    49. Changes required to replace the Spring Cloud Config Server
    50. Replacing the Spring Cloud Gateway
    51. Changes required to replace the Spring Cloud Gateway
    52. Automating certificate provisioning
    53. Testing with Kubernetes ConfigMaps, Secrets, Ingress, and the cert-manager
    54. Rotating certificates
    55. Deploying to Kubernetes for staging and production
    56. Verifying that the microservices work without Kubernetes
    57. Changes in the Docker Compose files
    58. Testing with Docker Compose
    59. Summary
    60. Questions
    61. Using a Service Mesh to Improve Observability and Management
    62. Technical requirements
    63. Introducing service meshes using Istio
    64. Introducing Istio
    65. Injecting Istio proxies into microservices
    66. Introducing Istio API objects
    67. Simplifying the microservice landscape
    68. Replacing Kubernetes Ingress controller with Istio ingress gateway
    69. Replacing the Zipkin server with Istio's Jaeger component
    70. Deploying Istio in a Kubernetes cluster
    71. Setting up access to Istio services
    72. Creating the service mesh
    73. Source code changes
    74. Content in the _istio_base.yaml template
    75. Content in the _istio_dr_mutual_tls.yaml template
    76. Running commands to create the service mesh
    77. Observing the service mesh
    78. Securing a service mesh
    79. Protecting external endpoints with HTTPS and certificates
    80. Authenticating external requests using OAuth 2.0/OIDC access tokens
    81. Protecting internal communication using mutual authentication (mTLS)
    82. Ensuring that a service mesh is resilient
    83. Testing resilience by injecting faults
    84. Testing resilience by injecting delays
    85. Performing zero-downtime updates
    86. Source code changes
    87. Virtual services and destination rules
    88. Deployments and services
    89. Tying things together in the prod-env Helm chart
    90. Deploying v1 and v2 versions of the microservices with routing to the v1 version
    91. Verifying that all traffic initially goes to the v1 version of the microservices
    92. Running canary tests
    93. Running blue/green deployment
    94. A short introduction to the kubectl patch command
    95. Performing the blue/green deployment
    96. Running tests with Docker Compose
    97. Summary
    98. Questions
    99. Centralized Logging with the EFK Stack
    100. Technical requirements
    101. Introducing Fluentd
    102. Overview of Fluentd
    103. Configuring Fluentd
    104. Deploying the EFK stack on Kubernetes
    105. Building and deploying our microservices
    106. Deploying Elasticsearch and Kibana
    107. A walkthrough of the manifest files
    108. Running the deploy commands
    109. Deploying Fluentd
    110. A walkthrough of the manifest files
    111. Running the deploy commands
    112. Trying out the EFK stack
    113. Initializing Kibana
    114. Analyzing the log records
    115. Discovering the log records from microservices
    116. Performing root cause analyses
    117. Summary
    118. Questions
    119. Monitoring Microservices
    120. Technical requirements
    121. Introduction to performance monitoring using Prometheus and Grafana
    122. Changes in source code for collecting application metrics
    123. Building and deploying the microservices
    124. Monitoring microservices using Grafana dashboards
    125. Installing a local mail server for tests
    126. Starting up the load test
    127. Using Kiali's built-in dashboards
    128. Importing existing Grafana dashboards
    129. Developing your own Grafana dashboards
    130. Examining Prometheus metrics
    131. Creating the dashboard
    132. Trying out the new dashboard
    133. Exporting and importing Grafana dashboards
    134. Setting up alarms in Grafana
    135. Setting up a mail-based notification channel
    136. Setting up an alarm on the circuit breaker
    137. Trying out the circuit breaker alarm
    138. Summary
    139. Questions
    140. Installation Instructions for macOS
    141. Technical requirements
    142. Installing tools
    143. Installing Homebrew
    144. Using Homebrew to install tools
    145. Install tools without Homebrew
    146. Post-installation actions
    147. Verifying the installations
    148. Accessing the source code
    149. Using an IDE
    150. The structure of the code
    151. Installation Instructions for Microsoft Windows with WSL 2 and Ubuntu
    152. Technical requirements
    153. Installing tools
    154. Installing tools on Windows
    155. Installing WSL 2 – Windows Subsystem for Linux v2
    156. Installing Ubuntu 20.04 on WSL 2
    157. Installing Windows Terminal
    158. Installing Docker Desktop for Windows
    159. Installing Visual Studio Code and its extension for Remote WSL
    160. Installing tools on the Linux server in WSL 2
    161. Installing tools using apt install
    162. Installing the Spring Boot CLI using sdk install
    163. Installing the remaining tools using curl and install
    164. Verifying the installations
    165. Accessing the source code
    166. The structure of the code
    167. Native Compiled Java Microservices
    168. Technical requirements
    169. When to native compile Java source code
    170. Introducing the GraalVM project
    171. Introducing the Spring Native project
    172. Compiling source code to a native image
    173. Changes in the source code
    174. Updates to the Gradle build files
    175. Providing native hints as annotations
    176. When underlying frameworks and libraries don't support native compilation
    177. Installing the tracing agent
    178. Installing the tracing agent on macOS
    179. Installing the tracing agent on Ubuntu under WSL 2 in Microsoft Windows
    180. Running the tracing agent
    181. Creating the native images
    182. Testing with Docker Compose
    183. Testing with Kubernetes
    184. Summary
    185. Questions
  5. Other Books You May Enjoy
  6. Index
13.59.113.226