Pular para o conteúdo

HashiCorp Consul Connect Cheat Sheet

Overview

HashiCorp Consul is a multi-networking tool that provides service discovery, service mesh, and network automation capabilities. Consul Connect is its service mesh feature that provides service-to-service connection authorization and encryption using mutual TLS, enabling secure communication between services without modifying application code.

Consul Connect works across multiple platforms including Kubernetes, VMs, and bare metal. It uses sidecar proxies (Envoy by default) to handle mTLS, traffic routing, and observability. Consul also provides a built-in key-value store, health checking, multi-datacenter support, and a web UI for service visualization.

Installation

Linux Binary

# Download and install
wget https://releases.hashicorp.com/consul/1.18.0/consul_1.18.0_linux_amd64.zip
unzip consul_1.18.0_linux_amd64.zip
sudo mv consul /usr/local/bin/

# Verify
consul version

# Start dev agent (development only)
consul agent -dev -client 0.0.0.0

# Web UI: http://localhost:8500

Docker

docker run -d --name consul \
  -p 8500:8500 \
  -p 8600:8600/udp \
  -p 8301:8301 \
  -p 8302:8302 \
  hashicorp/consul:1.18 agent -server -bootstrap-expect=1 \
  -ui -client=0.0.0.0

Kubernetes (Helm)

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

helm install consul hashicorp/consul \
  --namespace consul --create-namespace \
  --values consul-values.yaml
# consul-values.yaml
global:
  name: consul
  datacenter: dc1
  tls:
    enabled: true
  acls:
    manageSystemACLs: true
server:
  replicas: 3
  storageClass: standard
connectInject:
  enabled: true
  default: false
meshGateway:
  enabled: true
ui:
  enabled: true
  service:
    type: LoadBalancer

Service Registration

Service Definition File

{
  "service": {
    "name": "web",
    "port": 8080,
    "tags": ["v1", "production"],
    "meta": {
      "version": "1.0.0"
    },
    "check": {
      "http": "http://localhost:8080/health",
      "interval": "10s",
      "timeout": "5s"
    },
    "connect": {
      "sidecar_service": {
        "proxy": {
          "upstreams": [
            {
              "destination_name": "api",
              "local_bind_port": 9191
            },
            {
              "destination_name": "database",
              "local_bind_port": 9192
            }
          ]
        }
      }
    }
  }
}
# Register service
consul services register web-service.json

# Deregister
consul services deregister -id=web

# List services
consul catalog services

# Query service health
consul catalog nodes -service=web

Kubernetes Service Registration

apiVersion: v1
kind: Pod
metadata:
  name: web
  annotations:
    consul.hashicorp.com/connect-inject: "true"
    consul.hashicorp.com/connect-service-upstreams: "api:9191,database:9192"
spec:
  containers:
    - name: web
      image: myapp/web:v1
      ports:
        - containerPort: 8080
      env:
        - name: API_URL
          value: "http://localhost:9191"
        - name: DB_URL
          value: "localhost:9192"

CLI Commands

CommandDescription
consul membersList cluster members
consul catalog servicesList registered services
consul catalog nodesList nodes
consul services register <file>Register a service
consul services deregister -id <id>Deregister a service
consul connect proxy -sidecar-for <svc>Start sidecar proxy
consul intention listList all intentions
consul intention create web apiAllow web to access api
consul config write <file>Write config entry
consul config list -kind <type>List config entries
consul kv put <key> <value>Write KV pair
consul kv get <key>Read KV pair

Intentions (Service Access Control)

# Allow web to access api
consul intention create -allow web api

# Deny web to access database
consul intention create -deny web database

# List intentions
consul intention list

# Delete an intention
consul intention delete web api

# Check if connection is allowed
consul intention check web api

Intention Config Entry (L7)

{
  "Kind": "service-intentions",
  "Name": "api",
  "Sources": [
    {
      "Name": "web",
      "Action": "allow",
      "Permissions": [
        {
          "Action": "allow",
          "HTTP": {
            "PathPrefix": "/api/v1",
            "Methods": ["GET", "POST"]
          }
        },
        {
          "Action": "deny",
          "HTTP": {
            "PathPrefix": "/admin"
          }
        }
      ]
    },
    {
      "Name": "*",
      "Action": "deny"
    }
  ]
}
consul config write intentions.json

Configuration Entries

Service Router

{
  "Kind": "service-router",
  "Name": "api",
  "Routes": [
    {
      "Match": {
        "HTTP": {
          "PathPrefix": "/api/v2"
        }
      },
      "Destination": {
        "Service": "api-v2"
      }
    },
    {
      "Match": {
        "HTTP": {
          "Header": [
            { "Name": "x-canary", "Exact": "true" }
          ]
        }
      },
      "Destination": {
        "Service": "api",
        "ServiceSubset": "canary"
      }
    }
  ]
}

Service Splitter (Traffic Splitting)

{
  "Kind": "service-splitter",
  "Name": "api",
  "Splits": [
    {
      "Weight": 90,
      "ServiceSubset": "stable"
    },
    {
      "Weight": 10,
      "ServiceSubset": "canary"
    }
  ]
}

Service Resolver

{
  "Kind": "service-resolver",
  "Name": "api",
  "DefaultSubset": "stable",
  "Subsets": {
    "stable": {
      "Filter": "Service.Meta.version == v1"
    },
    "canary": {
      "Filter": "Service.Meta.version == v2"
    }
  },
  "ConnectTimeout": "15s",
  "RequestTimeout": "30s"
}

Configuration

Server Configuration (consul.hcl)

datacenter = "dc1"
data_dir = "/opt/consul/data"
log_level = "INFO"

server = true
bootstrap_expect = 3

bind_addr = "0.0.0.0"
client_addr = "0.0.0.0"

ui_config {
  enabled = true
}

connect {
  enabled = true
}

ports {
  grpc = 8502
  grpc_tls = 8503
}

tls {
  defaults {
    ca_file = "/etc/consul.d/consul-agent-ca.pem"
    cert_file = "/etc/consul.d/dc1-server-consul-0.pem"
    key_file = "/etc/consul.d/dc1-server-consul-0-key.pem"
    verify_incoming = true
    verify_outgoing = true
  }
}

acl {
  enabled = true
  default_policy = "deny"
  enable_token_persistence = true
}

Advanced Usage

Mesh Gateway (Multi-Datacenter)

# Register mesh gateway
consul connect envoy -mesh-gateway -register \
  -address '{{ GetInterfaceIP "eth0" }}:8443' \
  -wan-address '{{ GetInterfaceIP "eth0" }}:8443'

# Config entry for mesh
consul config write - <<EOF
{
  "Kind": "mesh",
  "Peering": {
    "PeerThroughMeshGateways": true
  }
}
EOF

Service Defaults

{
  "Kind": "service-defaults",
  "Name": "api",
  "Protocol": "http",
  "MeshGateway": {
    "Mode": "local"
  },
  "UpstreamConfig": {
    "Defaults": {
      "ConnectTimeoutMs": 5000,
      "Limits": {
        "MaxConnections": 512,
        "MaxPendingRequests": 512,
        "MaxConcurrentRequests": 512
      }
    }
  }
}

Monitoring

# Health check of all services
curl http://localhost:8500/v1/health/state/critical

# Service health
curl http://localhost:8500/v1/health/service/api?passing

# Envoy proxy admin (per sidecar)
# http://localhost:19000/stats
# http://localhost:19000/clusters
# http://localhost:19000/config_dump

Troubleshooting

IssueSolution
Service not discoverableCheck service registration; verify health checks pass
Connect proxy not startingEnsure connect.enabled = true; check Envoy binary availability
Intention deniedReview intentions with consul intention list; check ordering
mTLS failingVerify CA certificates; check TLS configuration on all agents
Upstream connection refusedVerify upstream service is healthy; check local bind port
Config entry not appliedVerify Kind and Name; check protocol matches (HTTP vs TCP)
ACL permission deniedBootstrap ACLs; create proper tokens for services
Split not taking effectEnsure service-resolver defines subsets; check service metadata