Gateway and Service Mesh — API Gateways with Istio and Linkerd
In this tutorial, you'll learn about Gateway Service Mesh. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
An API gateway and service mesh complement each other. The gateway handles north-south traffic while the mesh handles east-west traffic within the cluster.
What You'll Learn
By the end of this lesson, you will understand the difference between gateway and service mesh, configure sidecar injection for gateway pods, implement mTLS between gateway and services, and use traffic policies for canary routing.
Why It Matters
Understanding when to use a gateway versus a service mesh prevents overcomplicating your architecture and ensures each component handles the right responsibilities.
Real-World Use
Durga Antivirus Pro uses an API gateway for external traffic and Istio service mesh for internal service-to-service communication with automatic mTLS and traffic splitting.
Gateway vs Service Mesh
flowchart TD
Internet-->Gateway[API Gateway]
Gateway-->Mesh[Service Mesh]
subgraph Mesh[Service Mesh (Istio)]
SidecarA[Sidecar Proxy]-->ServiceA[Service A]
SidecarB[Sidecar Proxy]-->ServiceB[Service B]
SidecarC[Sidecar Proxy]-->ServiceC[Service C]
ServiceA-->SidecarB
ServiceB-->SidecarC
end
Gateway and Mesh Responsibility Split
Define clear responsibilities between the gateway and service mesh.
from typing import Dict, List, Optional
class ResponsibilityMatrix:
def __init__(self):
self.gateway: List[str] = []
self.mesh: List[str] = []
self.both: List[str] = []
def assign_gateway(self, feature: str):
self.gateway.append(feature)
def assign_mesh(self, feature: str):
self.mesh.append(feature)
def assign_both(self, feature: str):
self.both.append(feature)
def get_summary(self) -> Dict:
return {
"gateway_only": self.gateway,
"mesh_only": self.mesh,
"both": self.both,
}
matrix = ResponsibilityMatrix()
matrix.assign_gateway("TLS termination")
matrix.assign_gateway("Authentication")
matrix.assign_gateway("Rate limiting")
matrix.assign_gateway("API key validation")
matrix.assign_mesh("Service-to-service mTLS")
matrix.assign_mesh("Traffic splitting within mesh")
matrix.assign_mesh("Retry and timeout between services")
matrix.assign_both("Observability and metrics")
matrix.assign_both("Access logging")
print(f"Gateway: {matrix.gateway}")
print(f"Mesh: {matrix.mesh}")
print(f"Both: {matrix.both}")
Istio Sidecar Injection for Gateway
Configure Istio sidecar injection for gateway pods.
from typing import Dict, Optional
class IstioGatewayConfig:
def __init__(self, gateway_name: str,
namespace: str = "default"):
self.gateway_name = gateway_name
self.namespace = namespace
self.sidecar_injection = True
self.mtls_mode = "STRICT"
self.traffic_policies: Dict = {}
def enable_sidecar(self, enabled: bool = True):
self.sidecar_injection = enabled
def set_mtls_mode(self, mode: str = "STRICT"):
self.mtls_mode = mode
def add_retry_policy(self, attempts: int = 3,
per_try_timeout: str = "2s"):
self.traffic_policies["retries"] = {
"attempts": attempts,
"perTryTimeout": per_try_timeout
}
def add_timeout(self, timeout: str = "10s"):
self.traffic_policies["timeout"] = timeout
def add_circuit_breaker(self, max_connections: int = 100,
max_pending: int = 30,
max_retries: int = 3):
self.traffic_policies["circuitBreaker"] = {
"maxConnections": max_connections,
"maxPendingRequests": max_pending,
"maxRetries": max_retries,
}
def generate_vs(self) -> str:
vs = {
"apiVersion": "networking.istio.io/v1beta1",
"kind": "VirtualService",
"metadata": {
"name": self.gateway_name,
"namespace": self.namespace
},
"spec": {
"hosts": [self.gateway_name],
"gateways": [self.gateway_name],
"http": [{"route": [{
"destination": {
"host": self.gateway_name,
"port": {"number": 8080}
}
}]}]
}
}
if self.traffic_policies:
vs["spec"]["http"][0].update(
self.traffic_policies
)
import yaml
return yaml.dump(vs, default_flow_style=False)
def generate_peer_auth(self) -> str:
pa = {
"apiVersion": "security.istio.io/v1beta1",
"kind": "PeerAuthentication",
"metadata": {
"name": f"{self.gateway_name}-mtls",
"namespace": self.namespace
},
"spec": {
"mtls": {
"mode": self.mtls_mode
}
}
}
import yaml
return yaml.dump(pa, default_flow_style=False)
istio = IstioGatewayConfig("api-gateway")
istio.add_retry_policy(attempts=3, per_try_timeout="2s")
istio.add_timeout("10s")
print(istio.generate_vs())
print(istio.generate_peer_auth())
mTLS Between Gateway and Services
Configure mutual TLS between the gateway and backend services.
from typing import Dict, Optional
class MeshMTLSConfig:
def __init__(self):
self.services: Dict[str, str] = {}
def add_service(self, name: str,
mtls_mode: str = "STRICT"):
self.services[name] = mtls_mode
def get_service_config(self, name: str
) -> Optional[str]:
return self.services.get(name)
def validate_gateway_cert(self,
cert_pem: str) -> bool:
return True
def generate_destination_rule(self,
service: str,
namespace: str = "default"
) -> str:
dr = {
"apiVersion": "networking.istio.io/v1beta1",
"kind": "DestinationRule",
"metadata": {
"name": f"{service}-mtls",
"namespace": namespace
},
"spec": {
"host": f"{service}.{namespace}.svc.cluster.local",
"trafficPolicy": {
"tls": {
"mode": self.services.get(
service, "ISTIO_MUTUAL"
)
}
}
}
}
import yaml
return yaml.dump(dr, default_flow_style=False)
mtls = MeshMTLSConfig()
mtls.add_service("scan-service", "ISTIO_MUTUAL")
mtls.add_service("report-service", "ISTIO_MUTUAL")
print(mtls.generate_destination_rule("scan-service"))
Traffic Policies for Canary Routing
Use service mesh traffic policies for canary routing within the cluster.
from typing import Dict, List, Optional
class MeshTrafficSplit:
def __init__(self, service_name: str,
namespace: str = "default"):
self.service = service_name
self.namespace = namespace
self.subsets: List[Dict] = []
def add_subset(self, version: str,
labels: Dict,
weight: int):
self.subsets.append({
"version": version,
"labels": labels,
"weight": weight,
})
def generate_vs(self) -> str:
routes = []
for subset in self.subsets:
routes.append({
"weight": subset["weight"],
"destination": {
"host": self.service,
"subset": subset["version"],
"port": {"number": 8080}
}
})
vs = {
"apiVersion": "networking.istio.io/v1beta1",
"kind": "VirtualService",
"metadata": {
"name": self.service,
"namespace": self.namespace
},
"spec": {
"hosts": [self.service],
"http": [{
"route": routes
}]
}
}
import yaml
return yaml.dump(vs, default_flow_style=False)
def generate_dr(self) -> str:
subsets = []
for subset in self.subsets:
subsets.append({
"name": subset["version"],
"labels": subset["labels"]
})
dr = {
"apiVersion": "networking.istio.io/v1beta1",
"kind": "DestinationRule",
"metadata": {
"name": self.service,
"namespace": self.namespace
},
"spec": {
"host": self.service,
"subsets": subsets
}
}
import yaml
return yaml.dump(dr, default_flow_style=False)
split = MeshTrafficSplit("scan-service")
split.add_subset("v1", {"version": "v1"}, 90)
split.add_subset("v2", {"version": "v2"}, 10)
print(split.generate_vs())
Common Mistakes
Mistake 1: Duplicating Gateway and Mesh Features
Both can do retries, timeouts, and auth. Choose one to avoid conflicts and confusion.
Mistake 2: Forgetting Sidecar Injection
Gateway pods without sidecar cannot participate in the mesh. Enable injection for mTLS and Observability.
Mistake 3: mTLS Misconfiguration
If the gateway and mesh have different mTLS settings, requests fail. Ensure consistent TLS configuration.
Mistake 4: Overlapping Rules
Gateway and mesh both rewriting headers or enforcing timeouts causes unpredictable behavior.
Mistake 5: Not Using the Mesh for Internal Traffic
Without the mesh, internal services lose mTLS, retries, and observability benefits.
Practice Questions
- What is the difference between north-south and east-west traffic?
- How does the API gateway complement the service mesh?
- What is sidecar injection and why is it needed?
- How does mTLS work between the gateway and mesh services?
- What traffic policies should be in the gateway versus the mesh?
Challenge
Build an architecture where an API gateway handles external authentication and Rate Limiting, while an Istio service mesh handles mTLS, retries, and canary traffic splitting between internal services, with clear responsibility boundaries.
FAQ
Mini Project
Build a combined gateway and service mesh architecture where the gateway handles TLS termination and rate limiting, Istio handles mTLS and retries between services, and the gateway has sidecar injection enabled for mesh participation.
What's Next
Learn about Gateway Kubernetes for container Orchestration, or explore Gateway Clustering for high availability.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro