--- layout: docs page_title: Cluster Peering on Kubernetes description: >- If you use Consul on Kubernetes, learn how to enable cluster peering, create peering CRDs, and then manage peering connections in consul-k8s. --- # Cluster Peering on Kubernetes ~> **Cluster peering is currently in beta:** Functionality associated with cluster peering is subject to change. You should never use the beta release in secure environments or production scenarios. Features in beta may have performance issues, scaling issues, and limited support.

Cluster peering is not currently available in the HCP Consul offering. To establish a cluster peering connection on Kubernetes, you need to enable the feature in the Helm chart and create custom resource definitions (CRDs) for each side of the peering. The following CRDs are used to create and manage a peering connection: - `PeeringAcceptor`: Generates a peering token and accepts an incoming peering connection. - `PeeringDialer`: Uses a peering token to make an outbound peering connection with the cluster that generated the token. As of Consul v1.14, you can also [implement service failovers and redirects to control traffic](/consul/docs/connect/l7-traffic) between peers. > To learn how to peer clusters and connect services across peers in AWS Elastic Kubernetes Service (EKS) environments, complete the [Consul Cluster Peering on Kubernetes tutorial](https://learn.hashicorp.com/tutorials/consul/cluster-peering-aws?utm_source=docs). ## Prerequisites You must implement the following requirements to create and use cluster peering connections with Kubernetes: - Consul v1.13.1 or later - At least two Kubernetes clusters - The installation must be running on Consul on Kubernetes version 0.47.1 or later ### Prepare for installation 1. After you provision a Kubernetes cluster and set up your kubeconfig file to manage access to multiple Kubernetes clusters, use the `kubectl` command to export the Kubernetes context names and then set them to variables for future use. For more information on how to use kubeconfig and contexts, refer to the [Kubernetes docs on configuring access to multiple clusters](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/). You can use the following methods to get the context names for your clusters: - Use the `kubectl config current-context` command to get the context for the cluster you are currently in. - Use the `kubectl config get-contexts` command to get all configured contexts in your kubeconfig file. ```shell-session $ export CLUSTER1_CONTEXT= $ export CLUSTER2_CONTEXT= ``` 1. To establish cluster peering through Kubernetes, create a `values.yaml` file with the following Helm values. ```yaml global: name: consul image: "hashicorp/consul:1.13.1" peering: enabled: true connectInject: enabled: true dns: enabled: true enableRedirection: true server: exposeService: enabled: true controller: enabled: true meshGateway: enabled: true replicas: 1 ``` These Helm values configure the servers in each cluster so that they expose ports over a Kubernetes load balancer service. For additional configuration options, refer to [`server.exposeService`](/docs/k8s/helm#v-server-exposeservice). When generating a peering token from one of the clusters, Consul includes a load balancer address in the token so that the peering stream goes through the load balancer in front of the servers. For additional configuration options, refer to [`global.peering.tokenGeneration`](/docs/k8s/helm#v-global-peering-tokengeneration). ### Install Consul on Kubernetes Install Consul on Kubernetes by using the CLI to apply `values.yaml` to each cluster. 1. In `cluster-01`, run the following commands: ```shell-session $ export HELM_RELEASE_NAME=cluster-01 ``` ```shell-session $ helm install ${HELM_RELEASE_NAME} hashicorp/consul --create-namespace --namespace consul --version "0.47.1" --values values.yaml --kube-context $CLUSTER1_CONTEXT ``` 1. In `cluster-02`, run the following commands: ```shell-session $ export HELM_RELEASE_NAME=cluster-02 ``` ```shell-session $ helm install ${HELM_RELEASE_NAME} hashicorp/consul --create-namespace --namespace consul --version "0.47.1" --values values.yaml --kube-context $CLUSTER2_CONTEXT ``` ## Create a peering connection for Consul on Kubernetes ### Create a peering token To peer Kubernetes clusters running Consul, you need to create a peering token and share it with the other cluster. Peers identify each other using the `metadata.name` values you establish when creating the `PeeringAcceptor` and `PeeringDialer` CRDs. 1. In `cluster-01`, create the `PeeringAcceptor` custom resource. ```yaml apiVersion: consul.hashicorp.com/v1alpha1 kind: PeeringAcceptor metadata: name: cluster-02 ## The name of the peer you want to connect to spec: peer: secret: name: "peering-token" key: "data" backend: "kubernetes" ``` 1. Apply the `PeeringAcceptor` resource to the first cluster. ```shell-session $ kubectl --context $CLUSTER1_CONTEXT apply --filename acceptor.yaml ```` 1. Save your peering token so that you can export it to the other cluster. ```shell-session $ kubectl --context $CLUSTER1_CONTEXT get secret peering-token --output yaml > peering-token.yaml ``` ### Establish a peering connection between clusters 1. Apply the peering token to the second cluster. ```shell-session $ kubectl --context $CLUSTER2_CONTEXT apply --filename peering-token.yaml ``` 1. In `cluster-02`, create the `PeeringDialer` custom resource. ```yaml apiVersion: consul.hashicorp.com/v1alpha1 kind: PeeringDialer metadata: name: cluster-01 ## The name of the peer you want to connect to spec: peer: secret: name: "peering-token" key: "data" backend: "kubernetes" ``` 1. Apply the `PeeringDialer` resource to the second cluster. ```shell-session $ kubectl --context $CLUSTER2_CONTEXT apply --filename dialer.yaml ``` ### Export services between clusters ~> **Tip**: The examples in this section demonstrate how to export a service named `backend`. You should change instances of `backend` in the example code to the name of the service you want to export. 1. For the service in `cluster-02` that you want to export, add the following [annotations](/docs/k8s/annotations-and-labels) to your service's pods. ```yaml # Service to expose backend apiVersion: v1 kind: Service metadata: name: backend spec: selector: app: backend ports: - name: http protocol: TCP port: 80 targetPort: 9090 --- apiVersion: v1 kind: ServiceAccount metadata: name: backend --- # Deployment for backend apiVersion: apps/v1 kind: Deployment metadata: name: backend labels: app: backend spec: replicas: 1 selector: matchLabels: app: backend template: metadata: labels: app: backend annotations: "consul.hashicorp.com/connect-inject": "true" spec: serviceAccountName: backend containers: - name: backend image: nicholasjackson/fake-service:v0.22.4 ports: - containerPort: 9090 env: - name: "LISTEN_ADDR" value: "0.0.0.0:9090" - name: "NAME" value: "backend" - name: "MESSAGE" value: "Response from backend" ``` 1. In `cluster-02`, create an `ExportedServices` custom resource. ```yaml apiVersion: consul.hashicorp.com/v1alpha1 kind: ExportedServices metadata: name: default ## The name of the partition containing the service spec: services: - name: backend ## The name of the service you want to export consumers: - peer: cluster-01 ## The name of the peer that receives the service ``` 1. Apply the service file and the `ExportedServices` resource to the second cluster. ```shell-session $ kubectl apply --context $CLUSTER2_CONTEXT --filename backend.yaml --filename exportedsvc.yaml ``` ### Authorize services for peers 1. Create service intentions for the second cluster. ```yaml apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceIntentions metadata: name: backend-deny spec: destination: name: backend sources: - name: "*" action: deny - name: frontend action: allow ``` 1. Apply the intentions to the second cluster. ```shell-session $ kubectl --context $CLUSTER2_CONTEXT apply --filename intention.yml ``` 1. For the services in `cluster-01` that you want to access `backend`, add the following annotations to the service file. To dial the upstream service from an application, ensure that the requests are sent to the correct DNS name as specified in [Service Virtual IP Lookups](/docs/discovery/dns#service-virtual-ip-lookups). ```yaml # Service to expose frontend apiVersion: v1 kind: Service metadata: name: frontend spec: selector: app: frontend ports: - name: http protocol: TCP port: 9090 targetPort: 9090 --- apiVersion: v1 kind: ServiceAccount metadata: name: frontend --- apiVersion: apps/v1 kind: Deployment metadata: name: frontend labels: app: frontend spec: replicas: 1 selector: matchLabels: app: frontend template: metadata: labels: app: frontend annotations: "consul.hashicorp.com/connect-inject": "true" spec: serviceAccountName: frontend containers: - name: frontend image: nicholasjackson/fake-service:v0.22.4 securityContext: capabilities: add: ["NET_ADMIN"] ports: - containerPort: 9090 env: - name: "LISTEN_ADDR" value: "0.0.0.0:9090" - name: "UPSTREAM_URIS" value: "http://backend.virtual.cluster-02.consul" - name: "NAME" value: "frontend" - name: "MESSAGE" value: "Hello World" - name: "HTTP_CLIENT_KEEP_ALIVES" value: "false" ``` 1. Apply the service file to the first cluster. ```shell-session $ kubectl --context $CLUSTER1_CONTEXT apply --filename frontend.yaml ``` 1. Run the following command in `frontend` and then check the output to confirm that you peered your clusters successfully. ```shell-session $ kubectl --context $CLUSTER1_CONTEXT exec -it $(kubectl --context $CLUSTER1_CONTEXT get pod -l app=frontend -o name) -- curl localhost:9090 { "name": "frontend", "uri": "/", "type": "HTTP", "ip_addresses": [ "10.16.2.11" ], "start_time": "2022-08-26T23:40:01.167199", "end_time": "2022-08-26T23:40:01.226951", "duration": "59.752279ms", "body": "Hello World", "upstream_calls": { "http://backend.virtual.cluster-02.consul": { "name": "backend", "uri": "http://backend.virtual.cluster-02.consul", "type": "HTTP", "ip_addresses": [ "10.32.2.10" ], "start_time": "2022-08-26T23:40:01.223503", "end_time": "2022-08-26T23:40:01.224653", "duration": "1.149666ms", "headers": { "Content-Length": "266", "Content-Type": "text/plain; charset=utf-8", "Date": "Fri, 26 Aug 2022 23:40:01 GMT" }, "body": "Response from backend", "code": 200 } }, "code": 200 } ``` ## End a peering connection To end a peering connection, delete both the `PeeringAcceptor` and `PeeringDialer` resources. To confirm that you deleted your peering connection, in `cluster-01`, query the `/health` HTTP endpoint. The peered services should no longer appear. ```shell-session $ curl "localhost:8500/v1/health/connect/backend?peer=cluster-02" ``` ## Recreate or reset a peering connection To recreate or reset the peering connection, you need to generate a new peering token from the cluster where you created the `PeeringAcceptor`. 1. In the `PeeringAcceptor` CRD, add the annotation `consul.hashicorp.com/peering-version`. If the annotation already exists, update its value to a higher version. ```yaml apiVersion: consul.hashicorp.com/v1alpha1 kind: PeeringAcceptor metadata: name: cluster-02 annotations: consul.hashicorp.com/peering-version: 1 ## The peering version you want to set. spec: peer: secret: name: "peering-token" key: "data" backend: "kubernetes" ``` 2. After you update `PeeringAcceptor`, repeat the steps to create a peering connection, including saving a new peering token and exporting it to the other cluster. Your peering connection is re-established with the updated token. ~> **Note:** The only way to create or set a new peering token is to manually adjust the value of the annotation `consul.hashicorp.com/peering-version`. Creating a new token causes the previous token to expire. ## Traffic management between peers As of Consul v1.14, you can use [dynamic traffic management](/consul/docs/connect/l7-traffic) to configure your service mesh so that services automatically failover and redirect between peers. To configure automatic service failovers and redirect, edit the `ServiceResolver` CRD so that traffic resolves to a backup service instance on a peer. The following example updates the `ServiceResolver` CRD in `cluster-01` so that Consul redirects traffic intended for the `frontend` service to a backup instance in `cluster-02` when it detects multiple connection failures to the primary instance. ```yaml apiVersion: consul.hashicorp.com/v1alpha1 kind: ServiceResolver metadata: name: frontend spec: connectTimeout: 15s failover: '*': targets: - peer: 'cluster-02' service: 'backup' namespace: 'default' ```