Why Run Consul on Kubernetes?

Kubernetes has its own basic service discovery (via DNS and Services), but it lacks several capabilities that Consul provides out of the box: cross-cluster service discovery, mTLS service mesh, health-check driven routing, and integration with non-Kubernetes services. Running Consul on Kubernetes lets you bridge K8s workloads with VMs, bare metal, or other clusters in a unified control plane.

Prerequisites

  • A running Kubernetes cluster (v1.25+)
  • kubectl configured and pointing at your cluster
  • Helm v3 installed
  • At least 3 nodes for server pods (to maintain quorum)

Installing Consul via Helm

Add the HashiCorp Helm Repository

helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update

Create a values.yaml File

Start with a minimal but production-oriented configuration:

global:
  name: consul
  datacenter: dc1
  tls:
    enabled: true
  acls:
    manageSystemACLs: true

server:
  replicas: 3
  storage: 10Gi

client:
  enabled: true

connectInject:
  enabled: true

ui:
  enabled: true
  service:
    type: LoadBalancer

Install the Chart

helm install consul hashicorp/consul \
  --namespace consul \
  --create-namespace \
  -f values.yaml

Wait for all pods to reach Running status:

kubectl get pods -n consul -w

How the Helm Chart Works

The chart deploys:

  • Server StatefulSet — 3 (or more) Consul server pods with persistent volumes
  • Client DaemonSet — one Consul client pod per K8s node, handling health checks and local service registration
  • Connect Inject Controller — a mutating admission webhook that automatically injects Envoy sidecar containers into annotated pods
  • Controller — syncs Consul CRDs (custom resource definitions) to Consul config entries

Automatically Injecting Sidecars

To enable the Consul service mesh for a Kubernetes deployment, add a single annotation:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  template:
    metadata:
      annotations:
        consul.hashicorp.com/connect-inject: "true"
    spec:
      containers:
        - name: web
          image: myapp/web:latest
          ports:
            - containerPort: 8080

The webhook injects an Envoy sidecar and an init container that configures the proxy — your application container doesn't need any modification.

Service Sync: Bridging K8s and Non-K8s Services

Enable syncCatalog in your Helm values to bidirectionally sync services between Kubernetes and Consul:

syncCatalog:
  enabled: true
  toConsul: true
  toK8S: true

With this enabled:

  • Kubernetes Services appear in Consul's catalog automatically
  • Services registered in Consul appear as Kubernetes Services, making them accessible via kube-dns

This is the key to connecting Kubernetes workloads with legacy VMs or external databases registered in Consul.

Using CRDs for Config Entries

The Consul Helm chart installs CRDs that let you manage Consul config entries as native Kubernetes resources:

apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: web-to-api
spec:
  destination:
    name: api
  sources:
    - name: web
      action: allow

Apply this with kubectl apply -f intentions.yaml and Consul will enforce it across your mesh.

Integrating Consul with Vault on Kubernetes

For secrets management, pair Consul with HashiCorp Vault using the Vault Agent Injector or the Vault Secrets Operator. Vault can act as Consul's certificate authority, rotating mTLS certificates automatically and storing ACL bootstrap tokens securely.

Troubleshooting Tips

  • Sidecar not injecting? Check that the namespace has the consul.hashicorp.com/connect-inject label and that the pod annotation is correct.
  • Services not syncing? Verify the sync catalog RBAC permissions and check the controller logs: kubectl logs -n consul -l component=sync-catalog.
  • TLS errors? Ensure your Consul clients and servers all use certificates from the same CA. Re-run consul tls cert create if needed.

Summary

The Consul Helm chart makes it straightforward to deploy a production-grade Consul cluster on Kubernetes with TLS, ACLs, and Connect injection enabled from day one. The real power comes from the bidirectional service sync and CRD-based management, which let you treat Consul configuration as code alongside your Kubernetes manifests.