Why AKS for microservices?
Microservices increase the number of deployable units, but they also increase the operational surface area: networking, scaling, rollouts, failures, and observability become harder. AKS (Azure Kubernetes Service) gives you the missing platform layer:
- <strong>Scheduling & isolation</strong>: run many microservices with different resource needs on shared infrastructure.
- <strong>Declarative deployments</strong>: the desired state of each microservice (image, config, replicas) lives in manifests.
- <strong>Horizontal scaling</strong>: autoscale per service instead of scaling whole applications.
- <strong>Service discovery & routing</strong>: stable service endpoints and controlled ingress.
- <strong>Day-2 operations</strong>: rolling updates, rollbacks, health checks, and monitoring integrations.
What AKS actually is (in plain terms)
AKS is a managed Kubernetes control plane on Azure, plus the worker infrastructure (nodes) where your workloads run. Key parts you’ll see in the Azure portal and in day-to-day operations:
- <strong>Resource Group</strong>: where AKS resources live.
- <strong>Virtual Network (VNet)</strong>: your cluster’s network boundary.
- <strong>Node Pools</strong>: groups of nodes with similar VM sizes / scaling settings.
- <strong>Kubernetes control plane (managed by Microsoft)</strong>: the API server, etcd, and core control components.
- <strong>Ingress / Load Balancing</strong>: how external traffic gets into your services.
Microservices architecture mapping (Kubernetes mental model)
A microservices system maps cleanly onto Kubernetes primitives:
- <strong>Service</strong> (Kubernetes object) → stable internal endpoint for a microservice
- <strong>Deployment</strong> → how a microservice runs (replicas, rollout strategy)
- <strong>Ingress</strong> → HTTP(S) routing to microservices
- <strong>ConfigMap / Secret</strong> → configuration and credentials
- <strong>HPA</strong> → scaling rules per microservice
- <strong>Namespace</strong> (optional but common) → environment separation (dev/stage/prod) or domain separation
- <strong>PodDisruptionBudget / readiness+liveness probes</strong> → reliability during upgrades and node maintenance
A useful rule: treat each microservice as a <strong>small, replaceable unit</strong> that should survive redeploys and scale events without manual intervention.
Node Pools and environments: a practical setup
For microservices, node pools help you separate concerns:
- <strong>System pool</strong>: nodes reserved for cluster-critical components (often you don’t touch this).
- <strong>Application pools</strong>: your services.
- <strong>Specialized pool (optional)</strong>: dedicated nodes for GPU workloads, batch jobs, or different scaling patterns.
Typical “good enough” starting point:
- One application node pool for most services
- Separate pool for workloads that require different VM sizes or isolation
You’ll also want to plan capacity:
- <strong>Node auto-provisioning</strong> (cluster autoscaler) to reduce overprovisioning
- <strong>Min/Max node bounds</strong> to control cost
Networking basics: VNet, Ingress, and service-to-service traffic
Microservices networking usually has two paths:
1) North-South traffic (outside → inside)
Ingress is where you route incoming traffic to services. A common pattern:
- <code>api.company.com</code> routes to <code>/users</code> → <code>users-service</code>
- <code>api.company.com</code> routes to <code>/orders</code> → <code>orders-service</code>
Implementation options:
- <strong>Ingress Controller</strong> (e.g., NGINX ingress)
- <strong>Azure Load Balancer</strong> integration (varies by AKS networking mode)
2) East-West traffic (service → service)
Inside the cluster, microservices talk to each other via Kubernetes Services. Important operational points:
- Use <strong>readiness probes</strong> so services only receive traffic when they’re ready.
- Prefer <strong>timeouts and retries</strong> in clients (and avoid retry storms).
- If you later introduce service mesh or mTLS, plan the migration path early.
Deploying microservices on AKS (end-to-end workflow for rookies)
This section is a “do it step-by-step” path you can follow to deploy your <strong>first microservice</strong> to <strong>AKS</strong>.
What you will build
- An AKS cluster (small demo)
- A Kubernetes Deployment (runs your microservice)
- A Kubernetes Service (gives it a stable internal IP/DNS)
- An Ingress (routes traffic from <code>api.example.com</code> to your service)
> Assumption: your microservice is already containerized (has a Docker image).
Prerequisites
- Azure CLI installed (<code>az</code>)
- Docker installed + logged in to a container registry
- <code>kubectl</code> installed
- (Recommended) an Azure Container Registry (ACR)
Step 1: Create an AKS cluster (demo-friendly)
Run a command like this (customize names):
az group create --name rg-aks-microservices --location eastus
az aks create \
--resource-group rg-aks-microservices \
--name aks-microservices-demo \
--node-count 2 \
--enable-managed-identity \
--generate-cert \
--node-vm-size Standard_B2s \
--enable-cluster-autoscaler \
--min-count 1 \
--max-count 5What this does (rookie translation):
- Creates a Kubernetes cluster in Azure.
- Uses <strong>2 nodes</strong> to start so you can schedule your microservice.
- Enables <strong>cluster autoscaler</strong> so AKS can add/remove nodes automatically.
Step 2: Get cluster credentials so <code>kubectl</code> can talk to AKS
az aks get-credentials \
--resource-group rg-aks-microservices \
--name aks-microservices-demo \
--overwrite-existingNow test access:
kubectl get nodes
kubectl get namespacesStep 3: Prepare your container image
You need one image like:
- <code>myregistry.azurecr.io/orders:1.0.0</code>
Build and push (example):
# build
docker build -t orders:1.0.0 .
# tag for your registry
docker tag orders:1.0.0 myregistry.azurecr.io/orders:1.0.0
# push
docker push myregistry.azurecr.io/orders:1.0.0> If you don’t have ACR, you can use Docker Hub or another registry-just update the image name.
Step 4: Create a Kubernetes namespace (optional, but recommended)
Namespace helps separate environments and keeps things tidy.
kubectl create namespace microservices
kubectl config set-context --current --namespace=microservicesStep 5: Create your Deployment (the microservice runtime)
Create a file <code>orders-deployment.yaml</code>:
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders
spec:
replicas: 2
selector:
matchLabels:
app: orders
template:
metadata:
labels:
app: orders
spec:
containers:
- name: orders
image: yourregistry.azurecr.io/orders:1.0.0
ports:
- containerPort: 8080
# Health checks let Kubernetes know when it is safe to send traffic
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1
memory: 512MiApply it:
kubectl apply -f orders-deployment.yamlCheck status:
kubectl get deployments
kubectl get pods
kubectl describe pod -l app=ordersCommon rookie issue:
- Pods in <code>CrashLoopBackOff</code> → check logs.
kubectl logs -l app=orders --tail=200Step 6: Create a Service (stable network identity)
Create a file <code>orders-service.yaml</code>:
apiVersion: v1
kind: Service
metadata:
name: orders
spec:
selector:
app: orders
ports:
- name: http
port: 80
targetPort: 8080
# You can keep this default ClusterIP for internal routingApply it:
kubectl apply -f orders-service.yamlVerify:
kubectl get svc ordersStep 7: Add Ingress (route external traffic to the Service)
Ingress depends on your environment and an ingress controller. In AKS, you typically install NGINX Ingress Controller (or rely on an AKS default). For rookies, here’s the Ingress manifest: Create <code>orders-ingress.yaml</code>:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: orders-ingress
spec:
rules:
- host: api.example.com
http:
paths:
- path: /orders
pathType: Prefix
backend:
service:
name: orders
port:
number: 80Apply it:
kubectl apply -f orders-ingress.yamlVerify ingress resources:
kubectl get ingress
kubectl describe ingress orders-ingress> You will still need DNS (or a local hosts entry) to point <code>api.example.com</code> to your ingress load balancer.
Step 8: Test your microservice locally (from inside the cluster)
A simple first test is <code>kubectl port-forward</code>.
# forward local port 8081 to service port 80
kubectl port-forward svc/orders 8081:80Then call:
curl -v http://localhost:8081/orders(If your app doesn’t include <code>/orders</code> path internally, adjust the route.)
Step 9: Deploy more microservices consistently
Once your first service is working, repeat the same pattern:
- Deployment (image + probes + resources)
- Service (ClusterIP for internal routing)
- Ingress (for external access)
A huge rookie win: use the same label conventions everywhere (<code>app: <service-name></code>).
Troubleshooting quick checklist
- <code>kubectl get pods</code> → are containers running?
- <code>kubectl logs</code> → is your app healthy or crashing?
- <code>kubectl get svc</code> → does the Service exist and target the right pods?
- <code>kubectl get ingress</code> → is the ingress controller routing?
- <code>kubectl describe</code> → check Events at the bottom (this often tells you the exact failure).
Example: manifests for one microservice
Deployment + Service (simplified):
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders
spec:
replicas: 2
selector:
matchLabels:
app: orders
template:
metadata:
labels:
app: orders
spec:
containers:
- name: orders
image: yourregistry.azurecr.io/orders:1.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1
memory: 512Mi
---
apiVersion: v1
kind: Service
metadata:
name: orders
spec:
selector:
app: orders
ports:
- name: http
port: 80
targetPort: 8080Add Ingress to route traffic:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway
spec:
rules:
- host: api.example.com
http:
paths:
- path: /orders
pathType: Prefix
backend:
service:
name: orders
port:
number: 80Health endpoints you should implement
For microservices, “health” isn’t just up/down. It’s about *traffic safety*:
- <code>/health/live</code>: the process is running; if this fails, Kubernetes should restart the container.
- <code>/health/ready</code>: dependencies are reachable (DB, cache, required external services). When readiness fails, Kubernetes stops sending traffic.
Autoscaling: scale like a platform, not like a monolith
Autoscaling usually involves three layers:
1) Pod scaling (HPA)
HPA adjusts replicas of a microservice based on metrics (CPU, memory, or custom metrics). Example:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: orders
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: orders
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 702) Node scaling (Cluster Autoscaler)
If HPA needs more pods than existing capacity allows, the cluster autoscaler can add nodes. Operational tip: set <strong>min/max node counts</strong> to avoid runaway cost.
3) Application-level throttling
Even with autoscaling, you still need guardrails:
- rate limiting
- backpressure
- circuit breakers
For rate limiting and resilience patterns, see: <strong>system-design-rate-limiter</strong>.
Observability: logging, metrics, and traces (minimum viable)
A microservices platform fails silently if you can’t answer three questions quickly:
- <strong>Is it healthy?</strong> (metrics + health)
- <strong>Why is it slow?</strong> (logs + traces)
- <strong>Which service is causing failures?</strong> (correlated traces)
Practical minimum for AKS day-to-day:
- <strong>Centralized logs</strong> (stdout/stderr from containers)
- <strong>Metrics dashboards</strong> (request rate, error rate, latency percentiles)
- <strong>Tracing</strong> (propagate trace IDs across services)
Rollouts and reliability: making updates boring
Microservices require safe deployment strategies:
- Prefer rolling updates with readiness probes
- Use <strong>maxUnavailable</strong> and <strong>maxSurge</strong> to control rollout pressure
- Avoid updating too many services at once
For added resilience, consider:
- <strong>PodDisruptionBudget</strong> to protect availability during node maintenance
- <strong>Resource requests/limits</strong> to prevent “noisy neighbor” effects
Security basics (pragmatic)
Start with foundational controls:
- Use Kubernetes <strong>Secrets</strong> for credentials (and rotate them)
- Use namespaces to separate environments
- Prefer least-privilege service accounts
- Plan ingress TLS early
If you’re using microservices heavily, consider auth consistency:
- standardize auth headers
- centralize token validation logic (or use a gateway)
Cost management for AKS microservices
Cost surprises often come from:
- overprovisioned nodes
- long-running dev/test workloads
- no resource requests (leading to inefficient scheduling)
- excessive replica counts
Operational checklist:
- set min/max for node pools
- define CPU/memory requests & limits
- review HPA behavior under load tests
- use autoscaling (both pods and nodes) with sensible bounds
Suggested microservices on-boarding checklist (day 1 → day 7)
Day 1: Make it deployable
- container image built and pushed
- Deployment + Service manifests
- readiness/liveness endpoints
Day 2: Make it routable
- Ingress route (if external)
- stable service DNS inside the cluster
Day 3: Make it observable
- standardized logging format
- metrics emitted
- tracing context propagation
Day 4: Make it scalable
- HPA configured per microservice
- resource requests set
Day 5: Make it resilient
- timeouts, retries policy, and rate limiting
- graceful shutdown behavior
Day 6: Make it safe to update
- rollout strategy configured
- verify rollback procedure
Day 7: Make it secure
- least privilege service account
- secret management and rotation plan