Consul on Kubernetes with Helm is fundamentally about treating your service discovery and configuration management system as just another distributed application, managed with the same declarative tooling you use for everything else.

Here’s Consul running in a Kubernetes cluster. Notice how the StatefulSet defines the desired number of Consul servers, and the Service exposes them internally.

# Example Consul Server Deployment (simplified)
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: consul-server
spec:
  serviceName: consul-server
  replicas: 3
  selector:
    matchLabels:
      app: consul
      component: server
  template:
    metadata:
      labels:
        app: consul
        component: server
    spec:
      containers:
      - name: consul
        image: consul:latest
        ports:
        - containerPort: 8500 # HTTP API
        - containerPort: 8600 # DNS
        args:
          - "agent"
          - "-server"
          - "-ui"
          - "-client=0.0.0.0"
          - "-bootstrap-expect=3"
          - "-data-dir=/consul/data"
          - "-node-id=$(hostname)"
        volumeMounts:
        - name: data
          mountPath: /consul/data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi

---
# Example Consul Server Service
apiVersion: v1
kind: Service
metadata:
  name: consul-server
spec:
  selector:
    app: consul
    component: server
  ports:
  - port: 8500
    name: http
  - port: 8600
    name: dns
  clusterIPs: # Required for headless service
  - None

This setup tackles a few core problems. First, it provides robust service discovery: applications running in Kubernetes can ask Consul for the network locations of other services without needing hardcoded IP addresses or complex DNS configurations. Second, it enables dynamic configuration: Consul can serve configuration data to applications, allowing you to update settings without redeploying them. Finally, it offers health checking: Consul actively monitors the health of registered services, removing unhealthy instances from discovery results.

When you install Consul using Helm, you’re essentially deploying a curated set of Kubernetes resources (Deployments/StatefulSets, Services, ConfigMaps, etc.) that are pre-configured to run Consul. The Helm chart abstracts away the complexity of manually creating and linking these resources. It allows you to easily customize the Consul deployment, such as setting the number of server nodes, enabling the UI, configuring storage, or integrating with external Consul datacenters.

The helm install command is your primary tool. You’ll typically use it with a specific chart from a repository, like HashiCorp’s official chart:

helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
helm install my-consul hashicorp/consul --version 1.0.0 --namespace consul --create-namespace --set server.bootstrapExpect=3 --set ui.enabled=true

Here, my-consul is the release name for your Consul deployment. --namespace consul places it in a dedicated Kubernetes namespace. --set server.bootstrapExpect=3 tells Consul to start with 3 server nodes, crucial for quorum in a clustered setup. --set ui.enabled=true makes the Consul UI accessible.

The most surprising true thing about Consul on Kubernetes is that its DNS-based service discovery mechanism works by leveraging Kubernetes’ own DNS service. Consul agents running within pods register their services with the Consul cluster. When another pod queries for a service (e.g., my-service.service.consul), the Consul DNS server intercepts this query. If the service is registered in Consul, the Consul DNS server responds with the IP addresses of healthy Consul-registered service instances. If the service is not registered in Consul but is a Kubernetes Service, Consul can be configured to forward the query to Kubernetes’ native DNS (usually CoreDNS), allowing for a unified discovery experience.

The bootstrapExpect value is critical during the initial bootstrapping of a Consul server cluster. It tells the Consul agent how many server nodes it expects to be part of the cluster. When the agent starts, it waits until bootstrapExpect number of servers are available before it becomes fully operational. If you set this too high and don’t have enough nodes, the cluster will never form. If you set it too low and then try to scale up later without proper procedure, you might run into issues where new servers can’t join because the cluster already believes it’s at its bootstrapped size. For a production cluster, always start with an odd number of servers (3, 5, or 7) to ensure quorum.

The next concept you’ll likely encounter is integrating applications into Consul for service discovery and health checking.

Want structured learning?

Take the full Consul course →