Sup! This application manifests a microservices infrastructure using Docker and Kubernetes in NODE/React environment. It features a series of interconnected microservices that together form a robust and scalable application.
- Architecture
- Microservices Overview
- Event Bus System
- Database Per Service Pattern
- Asynchronous Communication
- Technologies Used
- Local Development
- Deployment
- Kubernetes Configuration
- Ingress Controller
- Skaffold Configuration
- Culmination
- Screenshots
The architecture of this application is based on the microservices pattern, where each service is independently deployable and scalable. The key components include:
- Client Service: A React application that interacts with various backend services.
- Posts Service: Manages the creation of posts.
- Comments Service: Handles comments on posts.
- Moderation Service: Moderates comments based on predefined rules.
- Query Service: Aggregates data from other services to serve the client.
- Event Bus: Manages events and ensures asynchronous communication between services.
- Technology: React
- Port: 3000
- Description: The frontend of the application, created with React, providing the user interface for creating posts and comments.
- Technology: Node.js, Express
- Port: 4000
- Description: Manages post creation and stores posts in an in-memory data structure.
- Technology: Node.js, Express
- Port: 4001
- Description: Handles comment creation and stores comments in an in-memory data structure associated with posts.
- Technology: Node.js, Express
- Port: 4003
- Description: Moderates comments by setting their status based on predefined rules.
- Technology: Node.js, Express
- Port: 4002
- Description: Aggregates data from other services to provide a consolidated view of posts and comments to the client.
- Technology: Node.js, Express
- Port: 4005
- Description: Facilitates asynchronous communication between services by handling events.
The custom event bus system is a critical component of this architecture. It ensures that events generated by one service are propagated to other services. Each event is broadcasted to all services, allowing them to take appropriate actions based on the event type.
- Event Storage: Events are stored to ensure reliability. If the event bus or any service goes down, events are replayed when they come back up.
- Asynchronous Communication: Services communicate asynchronously via the event bus, decoupling them and allowing independent scaling and deployment.
Each microservice follows the database per service pattern, maintaining its own data store. This isolation ensures that services remain decoupled and can evolve independently.
- Scalability: Each service can scale independently based on its load.
- Fault Isolation: Issues in one service do not affect others.
- Data Sovereignty: Each service owns its data, enabling it to choose the most appropriate storage technology and schema.
Asynchronous communication is achieved through the event bus. Events such as PostCreated
, CommentCreated
, and CommentModerated
are emitted by services and handled by others.
The query service plays a crucial role in maintaining data consistency and availability. It listens to events and maintains a synchronized view of the data. This ensures that even if the posts or comments service goes down, the client can still fetch the latest data from the query service.
- React: Frontend framework for building user interfaces.
- Node.js: JavaScript runtime for server-side applications.
- Express: Web framework for Node.js.
- Docker: Containerization platform for packaging applications.
- Kubernetes: Container orchestration platform for managing deployments.
- Skaffold: Tool for continuous development on Kubernetes.
- Minikube: Tool for running Kubernetes locally.
To run the project locally, ensure you have Docker and Minikube installed. Follow these steps:
Make sure hosts i.e etc/hosts is configured to server posts.com concurrently running Ingress NGINX at 127.0.0.1
127.0.0.1 posts.com
-
Start Minikube:
minikube start
-
Enable IP Tunneling:
$ eval $(minikube docker-env) $ minikube tunnel
-
Install Skaffold:
- macOS
brew install skaffold
- Arch Linux or other Linux based distributions
# For Linux x86_64 (amd64) curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64 && \ sudo install skaffold /usr/local/bin/
-
Run Skaffold: On
Microservices
root dir i.e where skaffold.yaml is located, run:skaffold dev
Access the app at http://posts.com on your local machine!
Kubernetes manifests are located in the infrastructure/k8s
directory. These manifests define the deployments, services, and other resources required to run the application in a Kubernetes cluster.
An Ingress Controller, ingress-nginx
, is used to manage access to the services. It provides load balancing and SSL termination.
$ minikube addons enable ingress
The Skaffold configuration is defined in skaffold.yaml
. It automates the build, push, and deployment process, enabling continuous development and integration.
Initially, ClusterIP and NodePort services were created to expose the microservices within the cluster and externally for development purposes.
For production-grade deployment, a Load Balancer service is configured to provide a stable IP and DNS name, ensuring reliable access to the services.
The Ingress Controller is configured using ingress-nginx
, providing a unified entry point for all services. It handles routing, SSL termination, and more.
-
Install Ingress-NGINX:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml
-
Configure Ingress: Define the ingress rules in the Kubernetes manifests located in
infrastructure/k8s
.
The skaffold.yaml
file defines the build and deployment pipelines. It ensures that changes are automatically built, pushed, and deployed to the Kubernetes cluster.
apiVersion: skaffold/v4beta3
kind: Config
manifests:
rawYaml:
- ./infrastructure/k8s/*
build:
local:
push: false
artifacts:
- image: colson0x1/client
context: client
docker:
dockerfile: Dockerfile
sync:
manual:
- src: 'src/**/*.js'
dest: .
- src: 'src/**/*.jsx'
dest: .
- image: colson0x1/comments
context: comments
docker:
dockerfile: Dockerfile
sync:
manual:
- src: '*.js'
dest: .
- image: colson0x1/event-bus
context: event-bus
docker:
dockerfile: Dockerfile
sync:
manual:
- src: '*.js'
dest: .
- image: colson0x1/moderation
context: moderation
docker:
dockerfile: Dockerfile
sync:
manual:
- src: '*.js'
dest: .
- image: colson0x1/posts
context: posts
docker:
dockerfile: Dockerfile
sync:
manual:
- src: '*.js'
dest: .
- image: colson0x1/query
context: query
docker:
dockerfile: Dockerfile
sync:
manual:
- src: '*.js'
dest: .
I've written this microservices infrastructure using modern technologies and best practices for building scalable and resilient applications. By leveraging Docker, Kubernetes, and an event-driven architecture, I ensure high availability and fault tolerance. One specific thing is that I would recommend using production-grade event brokers like NATS, Apache Kafka or RabbitMQ rather than implementing the event bus system from scratch like I did!
Happy coding!