Open Service Mesh (OSM) is a way to manage the network of microservices in your Kubernetes cluster without changing your application code. It’s built on Envoy proxy and aims to be simple and extensible.
Let’s see OSM in action. Imagine you have two services, httpbin and curl, where curl calls httpbin.
First, set up a Kubernetes cluster. For this example, we’ll use Azure Kubernetes Service (AKS).
az group create --name osm-rg --location eastus
az aks create --resource-group osm-rg --name osm-cluster --node-count 1 --enable-addons monitoring --generate-ssh-keys
Now, install OSM. The easiest way is using the osm CLI.
# Download the OSM CLI
curl -sL "https://get.openservicemesh.io" | bash -
# Install OSM into the 'osm-namespace'
osm namespace add --namespace default
osm install --set injector.logLevel=debug --set controller.logLevel=debug
This command installs OSM’s core components (controller and injector) and configures the default namespace to be part of the mesh. The injector will automatically inject Envoy sidecar proxies into pods in the default namespace.
Next, deploy your sample applications.
# httpbin.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
labels:
app: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: httpbin
image: kennethreitz/httpbin
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: httpbin
---
# curl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: curl
labels:
app: curl
spec:
replicas: 1
selector:
matchLabels:
app: curl
template:
metadata:
labels:
app: curl
spec:
containers:
- name: curl
image: appropriate/curl:latest
command: ["sleep", "3600"] # Keep the pod running
---
apiVersion: v1
kind: Service
metadata:
name: curl
labels:
app: curl
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: curl
Apply these manifests:
kubectl apply -f httpbin.yaml
kubectl apply -f curl.yaml
After applying, you’ll notice that the pods in the default namespace (e.g., httpbin-xxxx-yyyy and curl-xxxx-yyyy) now have two containers: one for your application and one for the Envoy proxy.
Now, let’s test communication. From within the curl pod, try to access httpbin.
kubectl exec -it $(kubectl get pods -l app=curl -o jsonpath='{.items[0].metadata.name}') -- curl httpbin:80
This command will likely fail with a connection refused error. This is because, by default, OSM enforces traffic policies. No traffic is allowed unless explicitly permitted.
To allow traffic from the curl service to the httpbin service, you need to create an HTTPRouteGroup and a TCPRoute (or HTTPRoute if you’re using HTTP).
# httproutegroup.yaml
apiVersion: osm.openservicemesh.io/v1alpha1
kind: HTTPRouteGroup
metadata:
name: httpbin-route-group
namespace: default
spec:
matches:
- name: httpbin-match
methods:
- GET
methods:
- POST
path:
type: prefix
value: /
hostnames:
- httpbin
---
# tcproute.yaml (for basic TCP connectivity)
apiVersion: osm.openservicemesh.io/v1alpha1
kind: TCPRoute
metadata:
name: httpbin-tcp-route
namespace: default
spec:
remote_service: httpbin
tcp_matches:
- port: 80
---
# trafficpolicy.yaml
apiVersion: osm.openservicemesh.io/v1alpha1
kind: TrafficPolicy
metadata:
name: httpbin-policy
namespace: default
spec:
protocol: tcp # Or http if using HTTPRoute
destination_ports:
- 80
traffic_ports:
- port: 80
protocol: tcp
route_groups:
- httpbin-route-group
Apply these:
kubectl apply -f httproutegroup.yaml
kubectl apply -f tcproute.yaml
kubectl apply -f trafficpolicy.yaml
Now, try the curl command again:
kubectl exec -it $(kubectl get pods -l app=curl -o jsonpath='{.items[0].metadata.name}') -- curl httpbin:80
This time, it should succeed, returning the JSON output from httpbin.
OSM works by deploying a control plane (the OSM controller) and injecting Envoy proxies as sidecars into your application pods. When you define traffic policies, the OSM controller translates these into Envoy configurations and pushes them to the proxies. The Envoy proxies then intercept all inbound and outbound traffic for the pod, enforcing the defined policies.
The HTTPRouteGroup defines what kinds of HTTP requests are allowed (methods, paths, hostnames). The TCPRoute (or HTTPRoute) defines the actual routing rules, mapping incoming requests to specific backend services. The TrafficPolicy ties these together and specifies which ports and protocols are managed by OSM for a given service.
A key concept is that OSM operates on a per-namespace basis. You opt namespaces into the mesh using osm namespace add. Once a namespace is in the mesh, the injector webhook automatically attaches Envoy sidecars to new pods.
One of the most powerful, yet often overlooked, aspects of OSM is its ability to inject TLS automatically between services. By defining a TrafficPolicy with protocol: tls (or http with tls.mutual: true in the TrafficPolicy), OSM configures the Envoy proxies to encrypt traffic between services using SPIFFE identities. This provides strong, zero-trust security for your microservices without any application code changes. You don’t need to manage certificates or PKI; OSM handles it all.
The next step is often exploring advanced traffic management features like traffic splitting for canary deployments or fault injection for testing resilience.