Docker & Kubernetes with ScoutQuest
Learn how to containerize your ScoutQuest services with Docker and deploy them to Kubernetes clusters with automatic service discovery and health monitoring.
Overview
This tutorial covers deploying ScoutQuest in containerized environments:
- Dockerizing ScoutQuest services
- Creating Docker Compose deployments
- Deploying to Kubernetes
- Service discovery in container orchestration
- Health checks and monitoring
Dockerizing Services
Let's start by containerizing a Node.js service:
Dockerfile (Node.js Service)
# Use Node.js 22 Alpine for smaller image size
FROM node:22-alpine
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production && npm cache clean --force
# Copy application code
COPY . .
# Create non-root user for security
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js
# Start the application
CMD ["node", "index.js"]
healthcheck.js
const http = require('http');
const options = {
hostname: 'localhost',
port: process.env.PORT || 3000,
path: '/health',
method: 'GET',
timeout: 2000
};
const request = http.request(options, (res) => {
if (res.statusCode === 200) {
process.exit(0);
} else {
process.exit(1);
}
});
request.on('error', () => {
process.exit(1);
});
request.on('timeout', () => {
request.destroy();
process.exit(1);
});
request.end();
Dockerfile (Rust Service)
# Multi-stage build for Rust
FROM rust:1.70 as builder
WORKDIR /app
COPY . .
# Build the application
RUN cargo build --release
# Runtime stage
FROM debian:bookworm-slim
# Install ca-certificates for HTTPS requests
RUN apt-get update && apt-get install -y \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Create app user
RUN useradd -m -u 1001 appuser
WORKDIR /app
# Copy the binary from builder stage
COPY --from=builder /app/target/release/rust-service /app/rust-service
# Change ownership to app user
RUN chown -R appuser:appuser /app
USER appuser
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["./rust-service"]
Docker Compose Setup
Create a complete development environment with Docker Compose:
docker-compose.yml
version: '3.8'
services:
# ScoutQuest Server
scoutquest-server:
image: scoutquest/server:latest
ports:
- "8080:8080"
environment:
- RUST_LOG=info
- HOST=0.0.0.0
- PORT=8080
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- scoutquest-network
# User Service
user-service:
build:
context: ./user-service
dockerfile: Dockerfile
ports:
- "3001:3000"
environment:
- PORT=3000
- SCOUT_URL=http://scoutquest-server:8080
- NODE_ENV=production
depends_on:
scoutquest-server:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "healthcheck.js"]
interval: 30s
timeout: 10s
retries: 3
networks:
- scoutquest-network
# Product Service
product-service:
build:
context: ./product-service
dockerfile: Dockerfile
ports:
- "3002:3000"
environment:
- PORT=3000
- SCOUT_URL=http://scoutquest-server:8080
- NODE_ENV=production
depends_on:
scoutquest-server:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "healthcheck.js"]
interval: 30s
timeout: 10s
retries: 3
networks:
- scoutquest-network
# Order Service (Rust)
order-service:
build:
context: ./order-service
dockerfile: Dockerfile
ports:
- "3003:3000"
environment:
- PORT=3000
- SCOUT_URL=http://scoutquest-server:8080
- RUST_LOG=info
depends_on:
scoutquest-server:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
networks:
- scoutquest-network
# API Gateway
api-gateway:
build:
context: ./api-gateway
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- PORT=3000
- SCOUT_URL=http://scoutquest-server:8080
- NODE_ENV=production
depends_on:
- user-service
- product-service
- order-service
healthcheck:
test: ["CMD", "node", "healthcheck.js"]
interval: 30s
timeout: 10s
retries: 3
networks:
- scoutquest-network
networks:
scoutquest-network:
driver: bridge
Running with Docker Compose
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Check service health
docker-compose ps
# Stop all services
docker-compose down
Kubernetes Deployment
Deploy ScoutQuest to Kubernetes with proper service discovery:
k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: scoutquest
labels:
name: scoutquest
k8s/scoutquest-server.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: scoutquest-server
namespace: scoutquest
spec:
replicas: 2
selector:
matchLabels:
app: scoutquest-server
template:
metadata:
labels:
app: scoutquest-server
spec:
containers:
- name: scoutquest-server
image: scoutquest/server:latest
ports:
- containerPort: 8080
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "8080"
- name: RUST_LOG
value: "info"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: scoutquest-server
namespace: scoutquest
spec:
selector:
app: scoutquest-server
ports:
- port: 8080
targetPort: 8080
type: ClusterIP
k8s/user-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: scoutquest
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: scoutquest/user-service:latest
ports:
- containerPort: 3000
env:
- name: PORT
value: "3000"
- name: SCOUT_URL
value: "http://scoutquest-server:8080"
- name: NODE_ENV
value: "production"
- name: SERVICE_NAME
value: "user-service"
- name: SERVICE_HOST
valueFrom:
fieldRef:
fieldPath: status.podIP
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
---
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: scoutquest
spec:
selector:
app: user-service
ports:
- port: 3000
targetPort: 3000
type: ClusterIP
k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: scoutquest-ingress
namespace: scoutquest
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: scoutquest.local
http:
paths:
- path: /api/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 3000
- path: /api/products
pathType: Prefix
backend:
service:
name: product-service
port:
number: 3000
- path: /api/orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 3000
- path: /
pathType: Prefix
backend:
service:
name: api-gateway
port:
number: 3000
ConfigMaps and Secrets
Manage configuration and secrets in Kubernetes:
k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: scoutquest-config
namespace: scoutquest
data:
scout_url: "http://scoutquest-server:8080"
log_level: "info"
health_check_interval: "30"
service_timeout: "5000"
k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: scoutquest-secrets
namespace: scoutquest
type: Opaque
data:
# Base64 encoded values
api_key: Y2hhbmdlLW1lLXBsZWFzZQ==
db_password: c3VwZXItc2VjcmV0LXBhc3M=
Using ConfigMaps and Secrets
spec:
containers:
- name: user-service
image: scoutquest/user-service:latest
envFrom:
- configMapRef:
name: scoutquest-config
- secretRef:
name: scoutquest-secrets
env:
- name: SERVICE_HOST
valueFrom:
fieldRef:
fieldPath: status.podIP
Horizontal Pod Autoscaling
Automatically scale services based on resource usage:
k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: user-service-hpa
namespace: scoutquest
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: user-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
Monitoring and Observability
Set up monitoring with Prometheus and Grafana:
k8s/service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: scoutquest-metrics
namespace: scoutquest
labels:
app: scoutquest
spec:
selector:
matchLabels:
app: scoutquest-server
endpoints:
- port: metrics
interval: 30s
path: /metrics
Adding metrics to your service
const promClient = require('prom-client');
// Create metrics
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.1, 0.5, 1, 2, 5]
});
const serviceDiscoveryRequests = new promClient.Counter({
name: 'service_discovery_requests_total',
help: 'Total number of service discovery requests',
labelNames: ['service_name', 'operation']
});
// Middleware to collect metrics
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
httpRequestDuration
.labels(req.method, req.route?.path || req.path, res.statusCode)
.observe(duration);
});
next();
});
// Metrics endpoint
app.get('/metrics', async (req, res) => {
res.set('Content-Type', promClient.register.contentType);
res.end(await promClient.register.metrics());
});
Deployment Scripts
Automate deployment with scripts:
scripts/deploy.sh
#!/bin/bash
set -e
NAMESPACE="scoutquest"
CONTEXT="production"
echo "🚀 Deploying ScoutQuest to Kubernetes..."
# Set kubectl context
kubectl config use-context "$CONTEXT"
# Create namespace if it doesn't exist
kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
# Apply all Kubernetes manifests
echo "📦 Applying Kubernetes manifests..."
kubectl apply -f k8s/ -n "$NAMESPACE"
# Wait for deployments to be ready
echo "⏳ Waiting for deployments to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment/scoutquest-server -n "$NAMESPACE"
kubectl wait --for=condition=available --timeout=300s deployment/user-service -n "$NAMESPACE"
kubectl wait --for=condition=available --timeout=300s deployment/product-service -n "$NAMESPACE"
kubectl wait --for=condition=available --timeout=300s deployment/order-service -n "$NAMESPACE"
echo "✅ Deployment completed successfully!"
# Show status
echo "📊 Current status:"
kubectl get pods -n "$NAMESPACE"
kubectl get services -n "$NAMESPACE"
scripts/build-and-push.sh
#!/bin/bash
set -e
REGISTRY="your-registry.com"
TAG=${1:-latest}
services=("user-service" "product-service" "order-service" "api-gateway")
echo "🔨 Building and pushing Docker images..."
for service in "${services[@]}"; do
echo "Building $service..."
docker build -t "$REGISTRY/scoutquest/$service:$TAG" "./$service"
docker push "$REGISTRY/scoutquest/$service:$TAG"
echo "✅ $service pushed successfully"
done
echo "🎉 All images built and pushed successfully!"
Production Best Practices
- Multi-stage builds: Use multi-stage Dockerfiles for smaller images
- Health checks: Always implement proper health checks
- Resource limits: Set appropriate CPU and memory limits
- Secrets management: Use Kubernetes secrets for sensitive data
- Network policies: Implement network segmentation
- Monitoring: Set up comprehensive monitoring and alerting
- Backup strategy: Implement backup and disaster recovery
Troubleshooting
Common issues and their solutions:
Check service registration
# Check if services are registered
kubectl exec -it deployment/scoutquest-server -n scoutquest -- curl localhost:8080/services
# Check service logs
kubectl logs deployment/user-service -n scoutquest --tail=50
# Debug service connectivity
kubectl exec -it deployment/user-service -n scoutquest -- nslookup scoutquest-server
Port forwarding for local debugging
# Forward ScoutQuest server port
kubectl port-forward service/scoutquest-server 8080:8080 -n scoutquest
# Forward service port
kubectl port-forward service/user-service 3001:3000 -n scoutquest
Next Steps
- Set up CI/CD pipelines for automated deployment
- Implement comprehensive monitoring
- Configure service mesh (Istio/Linkerd) for advanced traffic management
- Set up centralized logging with ELK stack
- Implement canary deployments