AWS App Mesh is a service mesh that helps you manage microservices. It makes it easier to observe, route, and secure your services. Here’s how to connect your EKS microservices with App Mesh.
Let’s say you have two services: frontend and backend. The frontend service needs to call the backend service. We’ll use App Mesh to manage this communication.
First, we need to set up App Mesh itself. This involves creating a Mesh object.
aws appmesh create-mesh --mesh-name my-app-mesh
This my-app-mesh is a logical proxy for your microservices. Think of it as a network boundary for your services.
Next, we define how our frontend service will be represented in App Mesh. This is a VirtualNode.
aws appmesh create-virtual-node \
--mesh-name my-app-mesh \
--virtual-node-name frontend-node \
--spec '{
"serviceDiscovery": {
"dns": {
"hostname": "frontend.my-namespace.svc.cluster.local"
}
},
"listeners": [
{
"portMapping": {
"port": 8080,
"protocol": "http"
}
}
]
}'
The serviceDiscovery.dns.hostname is the Kubernetes DNS name for your frontend service. The listeners section tells App Mesh which ports and protocols the service listens on.
Now, we need to tell App Mesh how to route traffic to the frontend service. This is a VirtualRouter and Route.
aws appmesh create-virtual-router \
--mesh-name my-app-mesh \
--virtual-router-name frontend-router \
--spec '{
"listeners": [
{
"portMapping": {
"port": 8080,
"protocol": "http"
}
}
]
}'
aws appmesh create-route \
--mesh-name my-app-mesh \
--virtual-router-name frontend-router \
--route-name frontend-route \
--spec '{
"httpRoute": {
"action": {
"weightedTargets": [
{
"virtualNode": "frontend-node",
"weight": 1
}
]
},
"match": {
"prefix": "/"
}
}
}'
The VirtualRouter acts as a single entry point for traffic destined for the frontend service. The Route defines rules for directing that traffic to specific VirtualNodes. Here, all traffic (prefix: "/") goes to the frontend-node.
We repeat this for the backend service.
aws appmesh create-virtual-node \
--mesh-name my-app-mesh \
--virtual-node-name backend-node \
--spec '{
"serviceDiscovery": {
"dns": {
"hostname": "backend.my-namespace.svc.cluster.local"
}
},
"listeners": [
{
"portMapping": {
"port": 9090,
"protocol": "http"
}
}
]
}'
aws appmesh create-virtual-router \
--mesh-name my-app-mesh \
--virtual-router-name backend-router \
--spec '{
"listeners": [
{
"portMapping": {
"port": 9090,
"protocol": "http"
}
}
]
}'
aws appmesh create-route \
--mesh-name my-app-mesh \
--virtual-router-name backend-router \
--route-name backend-route \
--spec '{
"httpRoute": {
"action": {
"weightedTargets": [
{
"virtualNode": "backend-node",
"weight": 1
}
]
},
"match": {
"prefix": "/"
}
}
}'
Now, the frontend service needs to call the backend service. We need to configure the frontend service to use App Mesh for this outbound call. This involves deploying the App Mesh envoy proxy alongside your frontend service and configuring your frontend service to send traffic to the proxy.
First, apply the App Mesh controller to your EKS cluster. This controller watches for App Mesh resources and configures Envoy sidecars.
apiVersion: apps/v1
kind: Deployment
metadata:
name: appmesh-controller
namespace: appmesh-system
spec:
# ... deployment details ...
Then, you need to annotate your frontend Kubernetes deployment to tell App Mesh to inject the Envoy sidecar.
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
annotations:
appmesh.eks.amazonaws.com/mesh: my-app-mesh
appmesh.eks.amazonaws.com/virtual-node: frontend-node
spec:
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: your-frontend-image:latest
ports:
- containerPort: 8080
# App Mesh controller will inject the envoy sidecar here
The appmesh.eks.amazonaws.com/mesh annotation specifies the mesh to join, and appmesh.eks.amazonaws.com/virtual-node specifies the virtual node this pod represents.
The Envoy proxy will be injected as a second container in your frontend pod. Your frontend application should now make its calls to http://backend-router.my-app-mesh.svc.cluster.local:9090 instead of directly to the backend service’s Kubernetes DNS name. The Envoy proxy intercepts this call, consults the App Mesh configuration, and routes it to the backend service.
The magic happens because the frontend application is configured to talk to a specific App Mesh VirtualRouter’s hostname. The Envoy sidecar, managed by the App Mesh controller, intercepts traffic destined for backend-router.my-app-mesh.svc.cluster.local. It looks up the backend-router in App Mesh, finds that it points to backend-node, and then resolves the backend-node’s actual Kubernetes service endpoint (e.g., backend.my-namespace.svc.cluster.local) to send the request.
The most surprising thing about App Mesh is that your application code doesn’t need to know about App Mesh at all, beyond its ability to make HTTP requests to a specific target hostname. You can completely change the routing logic, introduce retries, or even switch to a different backend implementation without touching your application code, as long as the new implementation adheres to the same port and protocol.
When you deploy your frontend service, the App Mesh controller automatically injects the Envoy sidecar container. This sidecar is configured to listen on the same port as your application (or a different one if you configure it) and to proxy traffic. For outbound requests from your application, you configure your application to send traffic to the App Mesh Virtual Router’s hostname (e.g., http://backend-router.my-app-mesh.svc.cluster.local:9090). The Envoy sidecar intercepts this traffic and uses the App Mesh configuration to find the actual VirtualNode (e.g., backend-node) and its corresponding Kubernetes service.
This setup allows for advanced traffic management features like canary deployments, fault injection, and mTLS encryption to be implemented entirely within App Mesh, without requiring changes to your application code. You can use aws appmesh list-virtual-nodes --mesh-name my-app-mesh and aws appmesh list-routes --mesh-name my-app-mesh to inspect your configuration.
The next step you’ll likely encounter is configuring observability, such as setting up distributed tracing with AWS X-Ray or collecting metrics with Prometheus.