Improve network performance with route reflectors
Estimated reading time: 6 minutesThis topic applies to Docker Enterprise.
The Docker Enterprise platform business, including products, customers, and employees, has been acquired by Mirantis, inc., effective 13-November-2019. For more information on the acquisition and how it may affect you and your business, refer to the Docker Enterprise Customer FAQ.
Docker Universal Control Plane (UCP) uses Calico as the default Kubernetes networking solution. Calico is configured to create a Border Gateway Protocol (BGP) mesh between all nodes in the cluster.
As you add more nodes to the cluster, networking performance starts decreasing. In fact, if your cluster has more than 100 nodes, you should reconfigure Calico to use route reflectors instead of a node-to-node mesh.
Route reflectors are useful in large scale deployments to reduce the number of BGP connections needed for correct and complete route propagation.
Note
UCP running on Microsoft Azure uses Azure Software Defined Networking (SDN) instead of Calico for multi-host networking. If your UCP deployment is running on Azure, you don’t need to configure it this way. See Install UCP on Azure for more information.
Before you begin
For production-grade systems, deploy at least two route reflectors, each running on its own node. These nodes should be dedicated solely to the purpose, too, because Swarm ingress and NodePorts may not function on any other workloads running on a route reflector node.
Choose dedicated nodes
-
Taint the nodes to ensure that they are unable to run other workloads. To do this, configure the CLI with a UCP client bundle.
-
For each dedicated node:
kubectl taint node <node-name> \ com.docker.ucp.kubernetes.calico/route-reflector=true:NoSchedule
-
Add labels to each of the dedicated nodes:
kubectl label nodes <node-name> \ com.docker.ucp.kubernetes.calico/route-reflector=true
Deploy the route reflectors
-
Create a
calico-rr.yaml
file with the following content:kind: DaemonSet apiVersion: extensions/v1beta1 metadata: name: calico-rr namespace: kube-system labels: app: calico-rr spec: updateStrategy: type: RollingUpdate selector: matchLabels: k8s-app: calico-rr template: metadata: labels: k8s-app: calico-rr annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: tolerations: - key: com.docker.ucp.kubernetes.calico/route-reflector value: "true" effect: NoSchedule hostNetwork: true containers: - name: calico-rr image: calico/routereflector:v0.6.1 env: - name: ETCD_ENDPOINTS valueFrom: configMapKeyRef: name: calico-config key: etcd_endpoints - name: ETCD_CA_CERT_FILE valueFrom: configMapKeyRef: name: calico-config key: etcd_ca # Location of the client key for etcd. - name: ETCD_KEY_FILE valueFrom: configMapKeyRef: name: calico-config key: etcd_key # Location of the client certificate for etcd. - name: ETCD_CERT_FILE valueFrom: configMapKeyRef: name: calico-config key: etcd_cert - name: IP valueFrom: fieldRef: fieldPath: status.podIP volumeMounts: - mountPath: /calico-secrets name: etcd-certs securityContext: privileged: true nodeSelector: com.docker.ucp.kubernetes.calico/route-reflector: "true" volumes: # Mount in the etcd TLS secrets. - name: etcd-certs secret: secretName: calico-etcd-secrets
-
Deploy the DaemonSet:
kubectl create -f calico-rr.yaml
Configure calicoctl
To reconfigure Calico to use route reflectors instead of a node-to-node mesh, calicoctl
needs to be able to locate the etcd key-value store managed by UCP. From a CLI configured with a UCP client bundle, create a shell alias to start calicoctl
using the docker/ucp-dsinfo
image:
UCP_VERSION=$(docker version --format '{{index (split .Server.Version "/") 1}}')
alias calicoctl="\
docker run -i --rm \
--pid host \
--net host \
-e constraint:ostype==linux \
-e ETCD_ENDPOINTS=127.0.0.1:12378 \
-e ETCD_KEY_FILE=/ucp-node-certs/key.pem \
-e ETCD_CA_CERT_FILE=/ucp-node-certs/ca.pem \
-e ETCD_CERT_FILE=/ucp-node-certs/cert.pem \
-v /var/run/calico:/var/run/calico \
-v ucp-node-certs:/ucp-node-certs:ro \
docker/ucp-dsinfo:${UCP_VERSION} \
calicoctl \
"
Disable node-to-node BGP mesh
After configuring calicoctl
, check the current Calico BGP configuration:
calicoctl get bgpconfig
If you don’t see any configuration listed, create one:
calicoctl create -f - <<EOF
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
logSeverityScreen: Info
nodeToNodeMeshEnabled: false
asNumber: 63400
EOF
This action creates a new configuration with node-to-node mesh BGP disabled.
If you have a configuration, and meshenabled
is set to true
:
-
Update your configuration:
calicoctl get bgpconfig --output yaml > bgp.yaml
- Edit the
bgp.yaml
file, changingnodeToNodeMeshEnabled
tofalse
. -
Update the Calico configuration:
calicoctl replace -f - < bgp.yaml
Configure Calico to use route reflectors
To configure Calico to use route reflectors, you first need to get the Autonomous System (AS) number for the network. To get the AS number for your network:
calicoctl get nodes --output=wide
Using the AS number, create the Calico configuration by customizing and running the following snipped for each route reflector:
calicoctl create -f - << EOF
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: bgppeer-global
spec:
peerIP: <IP_RR>
asNumber: <AS_NUMBER>
EOF
Where:
IP_RR
is the IP address of the node on which the route reflector pod is deployed.AS_NUMBER
is the sameAS number
for your nodes.
You can learn more about this configuration in the Calico documentation.
Stop calico-node pods
-
Manually delete any
calico-node
pods that are running on nodes dedicated to the running of route reflectors, as this will ensure that there are no instances in which pods and route reflectors are running on the same node. -
Using your UCP client bundle:
# Find the Pod name
kubectl -n kube-system \
get pods --selector k8s-app=calico-node -o wide | \
grep <node-name>
# Delete the Pod
kubectl -n kube-system delete pod <pod-name>
Validate peers
- Verify that the
calico-node
pods running on other nodes are peering with the route reflector. - From a CLI configured with a UCP client bundle, use a Swarm affinity filter to run
calicoctl node status
on any node runningcalico-node
:
UCP_VERSION=$(docker version --format '{{index (split .Server.Version "/") 1}}')
docker run -i --rm \
--pid host \
--net host \
-e affinity:container=='k8s_calico-node.*' \
-e ETCD_ENDPOINTS=127.0.0.1:12378 \
-e ETCD_KEY_FILE=/ucp-node-certs/key.pem \
-e ETCD_CA_CERT_FILE=/ucp-node-certs/ca.pem \
-e ETCD_CERT_FILE=/ucp-node-certs/cert.pem \
-v /var/run/calico:/var/run/calico \
-v ucp-node-certs:/ucp-node-certs:ro \
docker/ucp-dsinfo:${UCP_VERSION} \
calicoctl node status
The following is a sample output.
IPv4 BGP status
+--------------+-----------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+--------------+-----------+-------+----------+-------------+
| 172.31.24.86 | global | up | 23:10:04 | Established |
+--------------+-----------+-------+----------+-------------+
IPv6 BGP status
No IPv6 peers found.