Use cases
This guide uses the HashiCups as an example service applications registered on a Kubernetes deployment or pod and node with client agent to demonstrate the following use cases.
Service discovery and health monitoring
Register client node and health check
You can register nodes by deploying client agent configuration in the config directory with TF modules or with CLI and and start the client agents.
data_dir = "/etc/consul.d/consul-`hostname`"
node_name = "consul-`hostname`"
log_level = "${consul_log_level}"
datacenter = "${consul_datacenter}"
primary_datacenter = "${consul_primary_datacenter}"
encrypt = "${gossip_encryption_key}"
server = false
license_path = "${consul_license_path}"
enable_debug = true
ui_config {
enabled = true
}
partition = "partition-1"
ports {
serf_lan = 8302
}
client_addr = "0.0.0.0"
retry_join = ["provider=aws region=us-west-2 tag_key=consul tag_value=consul"]
connect {
enabled = true
}
rpc {
enable_streaming = false
}
advertise_addr = "$INTERNAL_IP_ADDRESS"
# TLS config
tls {
defaults {
verify_incoming = true
verify_outgoing = true
ca_file = "/etc/consul.d/tls/consul-ca.pem"
ca_path = "/etc/consul.d/tls"
cert_file = "/etc/consul.d/tls/consul-cert.pem"
key_file = "/etc/consul.d/tls/consul-key.pem"
}
# overrides tls.defaults path, if specified.
https {
verify_incoming = true
verify_outgoing = true
}
grpc {
verify_incoming = true
}
#Telemetry
telemetry {
dogstatsd_addr = "127.0.0.1:8125"
dogstatsd_tags = ["host-agent:consul-client"]
prefix_filter = ["+consul.serf.member.flap", "+consul.serf.member.failed"]
}
consul agent -config-dir=${CONSUL_CONFIG_DIR} > /tmp/consul-client.log 2>&1 &
Consul also allows you to define node-level health-checks that are not tied to a specific service. These checks monitor the overall health of the node itself. Node-level health checks can be registered separately:
{
"node": "consul-`hostname`",
"check": {
"script": "/usr/local/bin/check-node-health.sh",
"interval": "30s"
}
}
Here, a script-based health check runs every 30 seconds to check the health of the "consul-hostname
".
Register service and health checks
To register a service in Consul, you typically use the consul services register
command or by making an HTTP PUT request to the Consul agent's HTTP API. Service definition structure allows service health checks registered with service. Below are examples of both methods:
- Using
consul services register
command, we register counting service and its tcp health-check:
Product_db.json [VM]
{
"service": {
"ID": "product_db",
"name": "product_db",
"tags": ["backend", "product_db"],
"port": 5432,
"check": {
"id": "product_db_check",
"name": "Check DB health 5432",
"tcp": "localhost:5432",
"interval": "10s",
"timeout": "1s"
}
}
}
consul services register prodct_db.json
- We can also register a service by making an HTTP PUT request to the Consul agent's API endpoint. Once the definition is saved you can register the dashboard service and HTTP health-check by running:
curl --request PUT --data @product_db.json http://127.0.0.1:8500/v1/agent/service/register
- Using Iaac approach using client agents, service definition files can be placed on disk that Consul can reload during agent start or with
consul reload
command.
Register external service with service discovery
Consul enables the registration and discovery of services internal to your infrastructure as well as external services: third-party SaaS services, and services running in other environments where it is not possible to run the Consul agent directly.
External services run on nodes where you cannot run a local Consul agent. These nodes might be inside your infrastructure (e.g. a mainframe, virtual appliance, or unsupported platform) or outside of it (e.g. a SaaS platform).
Because external services by definition don't have a local Consul agent, you can't register them with that agent or use it for health checking. Instead, you must register them directly with the catalog using the /catalog/register
endpoint. We can use the /catalog/register endpoint for registering external services or nodes but with skip_node_update
to the API will not modify the node registration and assign specific service and checks to the existing node.
Typically external services are registered via nodes dedicated for that purpose so we'll continue our example using the Consul dev agent (localhost) as if it were running on a different node (e.g. "External Services") from the one where our internal web service is registered.
Use a PUT request to register the external service.
{
"Node": "hashicorp",
"Address": "learn.hashicorp.com",
"NodeMeta": {
"external-node": "true",
"external-probe": "true"
},
"Service": {
"ID": "learn1",
"Service": "learn",
"Port": 80
},
"Checks": [
{
"Name": "http-check",
"status": "passing",
"Definition": {
"http": "https://learn.hashicorp.com/consul/",
"interval": "30s"
}
}
]
}
curl --request PUT --data @external.json localhost:8500/v1/catalog/register
External service can be monitored with Consul ESM (External Services Monitor) that runs as a daemon alongside Consul in order to health check external nodes and update their status in the catalog.
Diagram shows how Consul ESM works with Consul to monitor the health of external services:
Service mesh and gateways
Secure service communication with Consul service mesh and Envoy
Consul service mesh secures service-to-service communication with authorization and encryption. Applications can use sidecar proxies in a service mesh configuration to automatically establish TLS connections for inbound and outbound connections without being aware of the network configuration and topology. In addition to securing your services, Consul service mesh can also intercept data about service-to-service communications and surface it to monitoring tools.
We will register two services and their sidecar proxies in the Consul catalog and then start the services and sidecar proxies. Finally, we will demonstrate that the service-to-service communication is going through the proxies by stopping traffic with an "intention".
Connect services outside the service mesh
The simplest use case for terminating gateways is routing to external services in the same logical network as the Consul service mesh.
A managed service, such as Amazon RDS or a third-party service, that needs to be integrated into the service mesh. In this scenario, you will not be able to install Consul on the machine and you will only be able to access the service via the endpoint(s) it exposes.
In these situations, given the heterogeneous nature or location of these services, the gateways and the external services would be registered in the same Consul datacenter catalog. Traffic from services in the mesh would flow through their sidecar to the terminating gateway. The gateway will then forward the traffic, potentially unencrypted, to the destination service.
To terminate TLS connections, the terminating gateway will present leaf certificates for the services it represents. Internal mesh traffic to the gateway will be encrypted with mTLS and controlled by intentions as expected with Consul service mesh. Intentions reference the source and destination services and do not require knowledge of the gateway itself.
The routing between gateways and external services is determined by the terminating-gateway
configuration entry. The configuration is associated with the name of a gateway service and will apply to all instances of gateways with that name across all federated Consul datacenters.
Update helm chart with minimum required configuration to install terminating gateways.
global:
name: consul
terminatingGateways:
enabled: true
Registering the external services with Consul is a multi-step process:
- Register external services with Consul using
ServiceDefaults
, ifTransparentProxy
is enabled. Otherwise, you register the service as a node in the Consul catalog. Example below configureServiceDefaults
to register AWS RDS postgres instance with Consul Service Mesh.
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceDefaults
metadata:
name: example-rds
spec:
protocol: tcp
destination:
addresses:
- "consul53.test.us-west-2.rds.amazonaws.com"
port: 5431
- Update the terminating gateway ACL token if ACLs are enabled. Update the terminating gateway ACL role to have service:write permissions on all of the services being represented by the gateway.
Create a new policy that includes the write permission for the service you created.
service "example-rds" {
policy = "write"
}
Apply terminating gateway write-policy.hcl
and create ALC role.
$ consul acl policy create -name "example-rds-write-policy" -rules @write-policy.hcl
# Obtain the ID of the terminating gateway role.
$ consul acl role list -format=json | jq --raw-output '[.[] | select(.Name | endswith("-terminating-gateway-acl-role"))] | if (. | length) == 1 then (. | first | .ID) else "Unable to determine the role ID because there are multiple roles matching this name.\n" | halt_error end'
<role_id>
# Update the terminating gateway ACL role with the new policy.
$ consul acl role update -id <role id> -policy-name example-rds-write-policy
- Create a
TerminatingGateway
resource to configure the terminating gateway after acl role update.
#terminating-gateway.yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: TerminatingGateway
metadata:
name: terminating-gateway
spec:
services:
- name: example-rds
- Create a
ServiceIntentions
resource to allow access from services in the mesh to external service.
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
name: example-rds
spec:
destination:
name: example-rds
sources:
- name: api
action: allow
API gateway - control access into service mesh
Consul API Gateway is a dedicated ingress solution for intelligently routing traffic to applications on your Consul service mesh. This provides a consistent method for handling inbound requests to the service mesh from external clients.
Consul API Gateway takes all API calls from clients, then routes them to the appropriate service with request routing, composition, and protocol translation. Once Consul API Gateway becomes available for your services, you can use it for ingress, load balancing, modifying HTTP headers, and splitting traffic between multiple services based on weighted ratios.
Consul API Gateway can be enabled by defining the API gateway in the ConnectInject
stanza as specified in consul server helm file.
Consul server helm
global:
name: consul
image: "hashicorp/consul-enterprise:1.16.X-ent"
datacenter: default
adminPartitions:
enabled: true
name: "default"
acls:
manageSystemACLs: true
enableConsulNamespaces: true
enterpriseLicense:
secretName: consul-enterprise-license
secretKey: license
enableLicenseAutoload: true
peering:
enabled: true
tls:
enabled: true
server:
replicas: 3
bootstrapExpect: 3
exposeService:
enabled: true
type: LoadBalancer
extraConfig: |
{
"log_level": "TRACE"
}
syncCatalog:
enabled: true
k8sAllowNamespaces: ["*"]
consulNamespaces:
mirroringK8S: true
connectInject:
enabled: true
transparentProxy:
defaultEnabled: false
consulNamespaces:
mirroringK8S: true
k8sAllowNamespaces: ['*']
k8sDenyNamespaces: []
apiGateway:
managedGatewayClass:
serviceType: LoadBalancer
meshGateway:
enabled: true
replicas: 3
service:
enabled: true
type: LoadBalancer
controller:
enabled: true
ui:
enabled: true
service:
enabled: true
type: LoadBalancer
Deploy API gateway
A complete API Gateway deployment consists of an API Gateway configuration and a routing configuration. It consists of multiple components that enable external traffic into your Consul service mesh. The configuration file specifies how Consul API Gateway will handle API calls from clients and how it will route them to the respective services with request routing, composition, and protocol translation.
consul-api-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: api-gateway
namespace: consul
spec:
gatewayClassName: consul
listeners:
# options: HTTP or HTTPS
- protocol: HTTP
# options: 80 or 443 or custom
port: 80
name: http
allowedRoutes:
namespaces:
# options: All or Same or Specific
from: All
This configuration file also defines other objects needed for the deployment of the Consul API Gateway, such as ReferenceGrant
, ClusterRoleBinding
and ClusterRole
. The reference grant lets API Gateway route traffic to services in different namespaces, and the RBAC ClusterRole objects let the API gateway interact with Consul datacenter resources.
#Apply consul-api-gateway.yaml to deploy the gateway
$ kubectl apply --filename api-gw/consul-api-gateway.yaml
# Verify the deployed gateway
$ kubectl get services --namespace=consul api-gateway
# Export API gateway external loadbalancer DNS
$ export APIGW_URL=$(kubectl get services --namespace=consul api-gateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') && echo $APIGW_URL
Create API gateway ingress route for the Frontend service
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: route-hashicups
namespace: default
spec:
parentRefs:
- name: api-gateway
namespace: consul
rules:
- matches:
- path:
type: Exact
value: /hashicups
backendRefs:
- kind: Service
name: frontend
namespace: default
port: 3000
filters:
- type: URLRewrite
urlRewrite:
path:
replacePrefixMatch: /
type: ReplacePrefixMatch