Learn microservices architecture, service communication, API gateway patterns, and container orchestration for scalable Node.js applications.
Learn microservices architecture, service communication, API gateway patterns, and container orchestration for scalable Node.js applications.
Master microservices architecture principles, design patterns, and implementation strategies for building scalable Node.js applications.
Content by: Praveen Kumar
MERN Stack Developer
Microservices architecture is an approach to building applications as a collection of loosely coupled, independently deployable services that communicate over well-defined APIs.
// Monolithic architecture example
const express = require('express');
const app = express();
// All services in one application
app.use('/users', userRoutes);
app.use('/orders', orderRoutes);
app.use('/payments', paymentRoutes);
app.use('/inventory', inventoryRoutes);
app.listen(3000, () => {
console.log('Monolithic app running on port 3000');
});
// Microservices architecture
// user-service/index.js
const express = require('express');
const app = express();
app.use('/users', userRoutes);
app.listen(3001, () => {
console.log('User service running on port 3001');
});
// order-service/index.js
const express = require('express');
const app = express();
app.use('/orders', orderRoutes);
app.listen(3002, () => {
console.log('Order service running on port 3002');
});// Domain-driven design for microservices
// user-service/domain/User.js
class User {
constructor(id, email, name) {
this.id = id;
this.email = email;
this.name = name;
this.createdAt = new Date();
}
validate() {
if (!this.email || !this.email.includes('@')) {
throw new Error('Invalid email');
}
if (!this.name || this.name.length < 2) {
throw new Error('Invalid name');
}
}
toJSON() {
return {
id: this.id,
email: this.email,
name: this.name,
createdAt: this.createdAt
};
}
}
// user-service/repository/UserRepository.js
class UserRepository {
constructor(database) {
this.db = database;
}
async findById(id) {
const user = await this.db.users.findById(id);
return user ? new User(user.id, user.email, user.name) : null;
}
async save(user) {
user.validate();
return await this.db.users.create(user.toJSON());
}
}// Synchronous communication with HTTP
const axios = require('axios');
class UserService {
constructor() {
this.baseURL = process.env.USER_SERVICE_URL || 'http://user-service:3001';
}
async getUser(id) {
try {
const response = await axios.get(`${this.baseURL}/users/${id}`);
return response.data;
} catch (error) {
if (error.response?.status === 404) {
return null;
}
throw new Error('Failed to fetch user');
}
}
}
// Asynchronous communication with message queues
const amqp = require('amqplib');
class OrderService {
constructor() {
this.connection = null;
this.channel = null;
}
async connect() {
this.connection = await amqp.connect(process.env.RABBITMQ_URL);
this.channel = await this.connection.createChannel();
// Declare queues
await this.channel.assertQueue('order.created', { durable: true });
await this.channel.assertQueue('order.updated', { durable: true });
}
async publishOrderCreated(order) {
await this.channel.sendToQueue(
'order.created',
Buffer.from(JSON.stringify(order)),
{ persistent: true }
);
}
}// Complete microservices implementation
// api-gateway/index.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const rateLimit = require('express-rate-limit');
const app = express();
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use(limiter);
app.use(express.json());
// Service discovery and routing
const services = {
user: process.env.USER_SERVICE_URL || 'http://user-service:3001',
product: process.env.PRODUCT_SERVICE_URL || 'http://product-service:3002',
order: process.env.ORDER_SERVICE_URL || 'http://order-service:3003',
payment: process.env.PAYMENT_SERVICE_URL || 'http://payment-service:3004'
};
// Proxy middleware for each service
Object.entries(services).forEach(([service, target]) => {
app.use(`/${service}`, createProxyMiddleware({
target,
changeOrigin: true,
pathRewrite: {
[`^/${service}`]: ''
},
onError: (err, req, res) => {
res.status(503).json({
error: 'Service unavailable',
service,
message: err.message
});
}
}));
});
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
services: Object.keys(services)
});
});
app.listen(3000, () => {
console.log('API Gateway running on port 3000');
});
// user-service/index.js
const express = require('express');
const mongoose = require('mongoose');
const User = require('./models/User');
const app = express();
app.use(express.json());
// Database connection
mongoose.connect(process.env.MONGODB_URL || 'mongodb://localhost:27017/users');
// Routes
app.get('/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
} catch (error) {
res.status(500).json({ error: 'Internal server error' });
}
});
app.post('/users', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
app.listen(3001, () => {
console.log('User service running on port 3001');
});Test your understanding of this topic:
Learn different communication patterns between microservices including synchronous HTTP, asynchronous messaging, and event-driven architecture.
Content by: Sachin Patel
Node.js Developer
Microservices can communicate through various patterns including synchronous HTTP calls, asynchronous messaging, and event-driven architecture.
// HTTP client for service-to-service communication
const axios = require('axios');
const circuitBreaker = require('opossum');
class ServiceClient {
constructor(serviceUrl, options = {}) {
this.serviceUrl = serviceUrl;
this.timeout = options.timeout || 5000;
this.retries = options.retries || 3;
// Circuit breaker pattern
this.circuitBreaker = circuitBreaker(this.makeRequest.bind(this), {
timeout: this.timeout,
errorThresholdPercentage: 50,
resetTimeout: 30000
});
this.circuitBreaker.on('open', () => {
console.log('Circuit breaker opened for', serviceUrl);
});
}
async makeRequest(method, path, data = null) {
const config = {
method,
url: `${this.serviceUrl}${path}`,
timeout: this.timeout,
headers: {
'Content-Type': 'application/json'
}
};
if (data) {
config.data = data;
}
return await axios(config);
}
async get(path) {
return await this.circuitBreaker.fire('GET', path);
}
async post(path, data) {
return await this.circuitBreaker.fire('POST', path, data);
}
}
// Usage
const userService = new ServiceClient('http://user-service:3001');
const productService = new ServiceClient('http://product-service:3002');// RabbitMQ implementation for async communication
const amqp = require('amqplib');
class MessageBroker {
constructor(connectionString) {
this.connectionString = connectionString;
this.connection = null;
this.channel = null;
}
async connect() {
this.connection = await amqp.connect(this.connectionString);
this.channel = await this.connection.createChannel();
// Enable publisher confirms
await this.channel.confirmSelect();
}
async publish(exchange, routingKey, message) {
if (!this.channel) {
throw new Error('Not connected to message broker');
}
const messageBuffer = Buffer.from(JSON.stringify(message));
return this.channel.publish(
exchange,
routingKey,
messageBuffer,
{
persistent: true,
messageId: require('uuid').v4(),
timestamp: Date.now()
}
);
}
async subscribe(queue, handler) {
if (!this.channel) {
throw new Error('Not connected to message broker');
}
await this.channel.assertQueue(queue, { durable: true });
this.channel.consume(queue, async (msg) => {
if (msg) {
try {
const message = JSON.parse(msg.content.toString());
await handler(message);
this.channel.ack(msg);
} catch (error) {
console.error('Error processing message:', error);
this.channel.nack(msg, false, false);
}
}
});
}
}
// Event-driven service
class OrderService {
constructor() {
this.messageBroker = new MessageBroker(process.env.RABBITMQ_URL);
}
async start() {
await this.messageBroker.connect();
// Subscribe to events
await this.messageBroker.subscribe('order.created', this.handleOrderCreated.bind(this));
await this.messageBroker.subscribe('payment.processed', this.handlePaymentProcessed.bind(this));
}
async handleOrderCreated(orderData) {
console.log('Processing order:', orderData);
// Process order logic
}
async handlePaymentProcessed(paymentData) {
console.log('Payment processed:', paymentData);
// Update order status
}
}// Event sourcing implementation
class EventStore {
constructor() {
this.events = [];
}
append(streamId, event) {
const eventRecord = {
streamId,
eventId: require('uuid').v4(),
eventType: event.constructor.name,
eventData: event,
timestamp: new Date(),
version: this.getNextVersion(streamId)
};
this.events.push(eventRecord);
return eventRecord;
}
getEvents(streamId) {
return this.events.filter(e => e.streamId === streamId);
}
getNextVersion(streamId) {
const streamEvents = this.getEvents(streamId);
return streamEvents.length;
}
}
// Aggregate root
class Order {
constructor(id) {
this.id = id;
this.status = 'pending';
this.items = [];
this.version = 0;
}
addItem(productId, quantity, price) {
const event = new OrderItemAdded(this.id, productId, quantity, price);
this.apply(event);
return event;
}
apply(event) {
switch (event.constructor.name) {
case 'OrderItemAdded':
this.items.push({
productId: event.productId,
quantity: event.quantity,
price: event.price
});
break;
case 'OrderConfirmed':
this.status = 'confirmed';
break;
}
this.version++;
}
}
// Events
class OrderItemAdded {
constructor(orderId, productId, quantity, price) {
this.orderId = orderId;
this.productId = productId;
this.quantity = quantity;
this.price = price;
}
}// Complete event-driven microservices system
const express = require('express');
const { EventEmitter } = require('events');
// Event bus
class EventBus extends EventEmitter {
constructor() {
super();
this.setMaxListeners(100);
}
publish(event) {
this.emit(event.type, event);
}
subscribe(eventType, handler) {
this.on(eventType, handler);
}
}
// Event types
const EventTypes = {
USER_CREATED: 'user.created',
ORDER_CREATED: 'order.created',
PAYMENT_PROCESSED: 'payment.processed',
INVENTORY_UPDATED: 'inventory.updated'
};
// User service
class UserService {
constructor(eventBus) {
this.eventBus = eventBus;
this.users = new Map();
}
createUser(userData) {
const user = {
id: require('uuid').v4(),
...userData,
createdAt: new Date()
};
this.users.set(user.id, user);
// Publish event
this.eventBus.publish({
type: EventTypes.USER_CREATED,
data: user,
timestamp: new Date()
});
return user;
}
getUser(id) {
return this.users.get(id);
}
}
// Order service
class OrderService {
constructor(eventBus, userService) {
this.eventBus = eventBus;
this.userService = userService;
this.orders = new Map();
// Subscribe to events
this.eventBus.subscribe(EventTypes.USER_CREATED, this.handleUserCreated.bind(this));
this.eventBus.subscribe(EventTypes.PAYMENT_PROCESSED, this.handlePaymentProcessed.bind(this));
}
createOrder(orderData) {
const order = {
id: require('uuid').v4(),
...orderData,
status: 'pending',
createdAt: new Date()
};
this.orders.set(order.id, order);
// Publish event
this.eventBus.publish({
type: EventTypes.ORDER_CREATED,
data: order,
timestamp: new Date()
});
return order;
}
handleUserCreated(event) {
console.log('New user created, setting up welcome order:', event.data.id);
}
handlePaymentProcessed(event) {
console.log('Payment processed for order:', event.data.orderId);
// Update order status
}
}
// Main application
const app = express();
app.use(express.json());
const eventBus = new EventBus();
const userService = new UserService(eventBus);
const orderService = new OrderService(eventBus, userService);
// API endpoints
app.post('/users', (req, res) => {
const user = userService.createUser(req.body);
res.status(201).json(user);
});
app.post('/orders', (req, res) => {
const order = orderService.createOrder(req.body);
res.status(201).json(order);
});
app.listen(3000, () => {
console.log('Event-driven microservices running on port 3000');
});Test your understanding of this topic:
Learn API Gateway patterns for microservices including routing, load balancing, authentication, and rate limiting.
Content by: Parth Patel
Node.js Developer
An API Gateway is a single entry point for all client requests to microservices, providing routing, load balancing, authentication, and other cross-cutting concerns.
// Express-based API Gateway
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const app = express();
// Security middleware
app.use(helmet());
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use(limiter);
// Service registry
const services = {
user: {
url: process.env.USER_SERVICE_URL || 'http://localhost:3001',
health: '/health'
},
product: {
url: process.env.PRODUCT_SERVICE_URL || 'http://localhost:3002',
health: '/health'
},
order: {
url: process.env.ORDER_SERVICE_URL || 'http://localhost:3003',
health: '/health'
}
};
// Health check for all services
app.get('/health', async (req, res) => {
const healthStatus = {};
for (const [serviceName, service] of Object.entries(services)) {
try {
const response = await fetch(`${service.url}${service.health}`);
healthStatus[serviceName] = {
status: response.ok ? 'healthy' : 'unhealthy',
responseTime: Date.now() - startTime
};
} catch (error) {
healthStatus[serviceName] = {
status: 'unhealthy',
error: error.message
};
}
}
res.json(healthStatus);
});// JWT-based authentication middleware
const jwt = require('jsonwebtoken');
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid token' });
}
req.user = user;
next();
});
};
// Role-based authorization
const authorize = (roles) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Authentication required' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
};
// Usage
app.use('/api/users', authenticateToken);
app.use('/api/admin', authenticateToken, authorize(['admin']));// Advanced routing with load balancing
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
class LoadBalancer {
constructor(services) {
this.services = services;
this.currentIndex = 0;
}
getNextService() {
const service = this.services[this.currentIndex];
this.currentIndex = (this.currentIndex + 1) % this.services.length;
return service;
}
getHealthyServices() {
return this.services.filter(service => service.healthy);
}
}
// Service discovery and health checking
class ServiceRegistry {
constructor() {
this.services = new Map();
}
register(serviceName, serviceUrl) {
this.services.set(serviceName, {
url: serviceUrl,
healthy: true,
lastCheck: Date.now()
});
}
async checkHealth(serviceName) {
const service = this.services.get(serviceName);
if (!service) return false;
try {
const response = await fetch(`${service.url}/health`);
service.healthy = response.ok;
service.lastCheck = Date.now();
return service.healthy;
} catch (error) {
service.healthy = false;
service.lastCheck = Date.now();
return false;
}
}
getHealthyServices(serviceName) {
const service = this.services.get(serviceName);
return service && service.healthy ? [service] : [];
}
}
// API Gateway with load balancing
const registry = new ServiceRegistry();
registry.register('user', 'http://user-service-1:3001');
registry.register('user', 'http://user-service-2:3001');
app.use('/api/users', (req, res, next) => {
const healthyServices = registry.getHealthyServices('user');
if (healthyServices.length === 0) {
return res.status(503).json({ error: 'Service unavailable' });
}
const loadBalancer = new LoadBalancer(healthyServices);
const targetService = loadBalancer.getNextService();
const proxy = createProxyMiddleware({
target: targetService.url,
changeOrigin: true,
onError: (err, req, res) => {
res.status(503).json({ error: 'Service unavailable' });
}
});
proxy(req, res, next);
});// Advanced rate limiting
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const Redis = require('ioredis');
const redis = new Redis(process.env.REDIS_URL);
// Different rate limits for different endpoints
const createRateLimit = (windowMs, max, message) => {
return rateLimit({
store: new RedisStore({
sendCommand: (...args) => redis.call(...args),
}),
windowMs,
max,
message: { error: message },
standardHeaders: true,
legacyHeaders: false,
});
};
// Global rate limit
app.use(createRateLimit(15 * 60 * 1000, 100, 'Too many requests from this IP'));
// User-specific rate limit
app.use('/api/users', createRateLimit(15 * 60 * 1000, 50, 'Too many user requests'));
// Admin rate limit
app.use('/api/admin', createRateLimit(15 * 60 * 1000, 200, 'Too many admin requests'));// Complete API Gateway implementation
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const jwt = require('jsonwebtoken');
const Redis = require('ioredis');
const app = express();
const redis = new Redis(process.env.REDIS_URL);
// Middleware
app.use(helmet());
app.use(express.json());
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
});
app.use(limiter);
// Service registry
class ServiceRegistry {
constructor() {
this.services = new Map();
}
register(name, url, healthEndpoint = '/health') {
if (!this.services.has(name)) {
this.services.set(name, []);
}
this.services.get(name).push({ url, healthEndpoint, healthy: true });
}
async checkHealth() {
for (const [serviceName, instances] of this.services) {
for (const instance of instances) {
try {
const response = await fetch(`${instance.url}${instance.healthEndpoint}`);
instance.healthy = response.ok;
} catch (error) {
instance.healthy = false;
}
}
}
}
getHealthyInstances(serviceName) {
const instances = this.services.get(serviceName) || [];
return instances.filter(instance => instance.healthy);
}
}
const registry = new ServiceRegistry();
// Register services
registry.register('user', 'http://user-service:3001');
registry.register('product', 'http://product-service:3002');
registry.register('order', 'http://order-service:3003');
// Health check every 30 seconds
setInterval(() => {
registry.checkHealth();
}, 30000);
// Authentication middleware
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid token' });
}
req.user = user;
next();
});
};
// Load balancer
class LoadBalancer {
constructor(instances) {
this.instances = instances;
this.currentIndex = 0;
}
getNextInstance() {
if (this.instances.length === 0) {
throw new Error('No healthy instances available');
}
const instance = this.instances[this.currentIndex];
this.currentIndex = (this.currentIndex + 1) % this.instances.length;
return instance;
}
}
// Proxy middleware factory
const createProxy = (serviceName) => {
return (req, res, next) => {
const healthyInstances = registry.getHealthyInstances(serviceName);
if (healthyInstances.length === 0) {
return res.status(503).json({
error: 'Service unavailable',
service: serviceName
});
}
const loadBalancer = new LoadBalancer(healthyInstances);
const targetInstance = loadBalancer.getNextInstance();
const proxy = createProxyMiddleware({
target: targetInstance.url,
changeOrigin: true,
onError: (err, req, res) => {
res.status(503).json({
error: 'Service unavailable',
service: serviceName
});
}
});
proxy(req, res, next);
};
};
// Routes
app.get('/health', (req, res) => {
const healthStatus = {};
for (const [serviceName, instances] of registry.services) {
healthStatus[serviceName] = instances.map(instance => ({
url: instance.url,
healthy: instance.healthy
}));
}
res.json(healthStatus);
});
// Service routes
app.use('/api/users', authenticateToken, createProxy('user'));
app.use('/api/products', createProxy('product'));
app.use('/api/orders', authenticateToken, createProxy('order'));
// Error handling
app.use((err, req, res, next) => {
console.error('Gateway error:', err);
res.status(500).json({ error: 'Internal gateway error' });
});
app.listen(3000, () => {
console.log('API Gateway running on port 3000');
});Test your understanding of this topic:
Learn container orchestration with Docker Compose and Kubernetes for managing microservices deployments.
Content by: Bansi Patel
Node.js Developer
Docker Compose allows you to define and run multi-container Docker applications, perfect for local microservices development.
# docker-compose.yml
version: '3.8'
services:
# API Gateway
api-gateway:
build: ./api-gateway
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- USER_SERVICE_URL=http://user-service:3001
- PRODUCT_SERVICE_URL=http://product-service:3002
- ORDER_SERVICE_URL=http://order-service:3003
depends_on:
- user-service
- product-service
- order-service
networks:
- microservices
# User Service
user-service:
build: ./user-service
ports:
- "3001:3001"
environment:
- NODE_ENV=production
- MONGODB_URL=mongodb://mongo:27017/users
depends_on:
- mongo
networks:
- microservices
# Product Service
product-service:
build: ./product-service
ports:
- "3002:3002"
environment:
- NODE_ENV=production
- MONGODB_URL=mongodb://mongo:27017/products
depends_on:
- mongo
networks:
- microservices
# Order Service
order-service:
build: ./order-service
ports:
- "3003:3003"
environment:
- NODE_ENV=production
- MONGODB_URL=mongodb://mongo:27017/orders
- RABBITMQ_URL=amqp://rabbitmq:5672
depends_on:
- mongo
- rabbitmq
networks:
- microservices
# Database
mongo:
image: mongo:5.0
ports:
- "27017:27017"
volumes:
- mongo_data:/data/db
networks:
- microservices
# Message Queue
rabbitmq:
image: rabbitmq:3-management
ports:
- "5672:5672"
- "15672:15672"
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=admin
volumes:
- rabbitmq_data:/var/lib/rabbitmq
networks:
- microservices
# Redis for caching
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- microservices
volumes:
mongo_data:
rabbitmq_data:
redis_data:
networks:
microservices:
driver: bridge# user-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
labels:
app: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:latest
ports:
- containerPort: 3001
env:
- name: NODE_ENV
value: "production"
- name: MONGODB_URL
valueFrom:
secretKeyRef:
name: mongodb-secret
key: url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- protocol: TCP
port: 80
targetPort: 3001
type: ClusterIP# istio-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: microservices-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "microservices.local"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: microservices-routes
spec:
hosts:
- "microservices.local"
gateways:
- microservices-gateway
http:
- match:
- uri:
prefix: /api/users
route:
- destination:
host: user-service
port:
number: 80
- match:
- uri:
prefix: /api/products
route:
- destination:
host: product-service
port:
number: 80# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'microservices'
static_configs:
- targets: ['user-service:3001', 'product-service:3002', 'order-service:3003']
metrics_path: /metrics
scrape_interval: 5s# Complete Kubernetes deployment for microservices
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: microservices
---
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: microservices-config
namespace: microservices
data:
NODE_ENV: "production"
LOG_LEVEL: "info"
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: microservices-secrets
namespace: microservices
type: Opaque
data:
mongodb-url: <base64-encoded-url>
jwt-secret: <base64-encoded-secret>
---
# api-gateway-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
namespace: microservices
spec:
replicas: 2
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
spec:
containers:
- name: api-gateway
image: api-gateway:latest
ports:
- containerPort: 3000
envFrom:
- configMapRef:
name: microservices-config
- secretRef:
name: microservices-secrets
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
---
# api-gateway-service.yaml
apiVersion: v1
kind: Service
metadata:
name: api-gateway
namespace: microservices
spec:
selector:
app: api-gateway
ports:
- port: 80
targetPort: 3000
type: LoadBalancer
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: microservices-ingress
namespace: microservices
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: microservices.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-gateway
port:
number: 80Test your understanding of this topic:
Continue your learning journey and master the next set of concepts.
Continue to Module 11