Managing a service mesh with GitOps: Istio, Linkerd, and Consul Connect for traffic management, mTLS, and observability. Covering Istio resources like VirtualService, DestinationRule, and Gateway that are managed directly by ArgoCD.

In episode 19 we discussed progressive delivery with Argo Rollouts, and mentioned service mesh several times as a traffic splitting mechanism — especially for header-based canary and A/B testing. In this episode we dissect that layer: what a service mesh is, how Istio works, and — most importantly for you — how to manage the whole mesh configuration with GitOps through ArgoCD.
Why does this topic matter? Once your architecture grows from a dozen to hundreds of services, two problems appear at once: traffic between services is invisible (where's the error? which hop is slow?) and communication between services is untrusted (who may talk to whom?). A service mesh answers both through sidecar proxies that slip in between services — and because all mesh configuration is just regular Kubernetes manifests, it's a perfect candidate for GitOps management.
A service mesh places a proxy (usually a sidecar) next to every pod. All traffic in and out goes through the proxy, so the mesh has full control without changing application code. The three main options in the ecosystem:
| Aspect | Istio | Linkerd | Consul Connect |
|---|---|---|---|
| Data plane | Envoy (powerful, feature-rich) | Dedicated proxy (lightweight) | Envoy / built-in proxy |
| Traffic features | Routing, retry, mirroring, fault injection | Basic split and failover | Intentions, split |
| mTLS | Automatic with PeerAuthentication | Fully automatic | Automatic with intentions |
| Observability | Tracing, metrics, service graph | Metrics and graph | Metrics and L7 |
| Complexity | High | Low | Medium |
The choice between them is often driven by the learning curve: Istio is the most powerful but also the heaviest; Linkerd is the best balance for small teams; Consul is interesting when you also need service discovery outside Kubernetes. The GitOps principles we'll discuss stay the same for all of them.
Note
Don't get stuck in the "which mesh is best" argument. This whole episode focuses on the management pattern — mesh resources are manifests, so ArgoCD is their home. The concepts learned here apply across meshes.
Istio introduces several custom resources that become the control points for traffic and security. Since they're all just YAML, ArgoCD can manage istio-system (the control plane) and per-application resources separately.
The three main resources you'll manage most often:
Gateway — the mesh's front door: the ports, hosts, and TLS opened at the edge.VirtualService — routing: where traffic with a certain host and path is directed, including weights and headers.DestinationRule — destination policy: subsets, load balancing, connection pools, and mTLS.All of them are stored in Git and applied as a regular Application:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: api-gateway
namespace: istio-system
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: api-tls
hosts:
- api.org.dev
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: api
spec:
hosts:
- api.org.dev
gateways:
- istio-system/api-gateway
http:
- route:
- destination:
host: api
subset: stable
weight: 100
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: api
spec:
host: api
subsets:
- name: stable
labels:
version: v1
- name: canary
labels:
version: v2Notice how the VirtualService refers to subset: stable and subset: canary, defined by the DestinationRule. This is where Argo Rollouts (episode 19) injects the canary weight: it rewrites weight on the VirtualService according to the promotion steps, while ArgoCD keeps all resources synced with Git.
When version v2 is launched, the VirtualService changes into a 90-10 split. Argo Rollouts can do this automatically by adding istio to the trafficRouting section of the Rollout:
spec:
strategy:
canary:
trafficRouting:
managedRoutes:
- name: canary
istio:
virtualService:
name: api
routes:
- primary
steps:
- setWeight: 10
- pause: {duration: 5m}The Rollout manages the weight on the primary route of the VirtualService directly — no human, no script. ArgoCD makes sure the resources exist in the cluster; the Rollout moves the traffic inside them.
The biggest operational benefit of a service mesh is "free" observability. Because every hop goes through Envoy, the mesh knows exactly the path every request takes.
Envoy injects tracing headers into every request; Jaeger or Tempo assembles them into a single end-to-end trace:
for i in $(seq 1 100); do
curl -s http://api.org.dev/hello -o /dev/null
doneFrom the trace, you see the time spent at each hop: gateway, api, auth, all the way to the database. This turns debugging from "trial and error" into checking a single map. In GitOps, tracing sampling configuration is also part of the manifests — for example Istio's MeshConfig stored in the istio-system repo.
Kiali (Istio's companion) shows a service graph: nodes are services, edges are communications, colors indicate errors and latency. The same metrics can flow into Prometheus for Rollout analysis (episode 19) and Grafana dashboards (episode 22). All of this reads Envoy metrics — enabled with nothing more than a MeshConfig in Git.
A service mesh is also a security tool. Two core features:
With PeerAuthentication set to MESH_WIDE, all traffic between services is encrypted and mutually trusted via mTLS — without changing code:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICTSTRICT mode forces all communication in the namespace to use mTLS. This eliminates the class of "pod-to-pod eavesdropping" attacks that are usually impossible to detect.
An AuthorizationPolicy defines who may talk to whom — access control at the network level:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: api-allow-frontend
spec:
selector:
matchLabels:
app: api
action: ALLOW
rules:
- from:
- source:
principals:
- cluster.local/ns/frontend/sa/frontend
to:
- operation:
methods: ["GET", "POST"]Tip
GitOps for security configuration means network policies go through the same process as code: pull request, review, and audit trail in Git. Change a policy = change a manifest + commit. ArgoCD applies and reconciles — there's no SSH backdoor to "just do it quickly".
Because PeerAuthentication and AuthorizationPolicy are ordinary manifests, both can be put into the same ArgoCD Application as the protected application, or into a dedicated security project that only the platform team can change (the concept from episode 10).
This episode connected a service mesh with GitOps: the comparison of Istio, Linkerd, and Consul Connect; managing Gateway, VirtualService, and DestinationRule as manifests; canary traffic splitting with Istio trafficRouting in Argo Rollouts; observability through tracing, metrics, and the service graph; and mTLS and authorization security policies — all pushed from Git.
The points you should take with you:
VirtualService and DestinationRule are where Argo Rollouts injects the canary weight.The architecture is now robust and can roll out new versions safely. But there's one thing often forgotten until disaster strikes: what if the entire cluster is lost? In the next episode 21 we discuss disaster recovery & backup — ArgoCD backup strategies, cluster recovery procedures, multi-cluster DR, and RTO/RPO testing. See you in episode 21!