Calico enable support for eBPF (#7618)

* Calico: align manifests with upstream

* allow enabling typha prometheus metrics

* Calico: enable eBPF support

* manage the kubernetes-services-endpoint configmap

* Calico: document the use of eBPF dataplane

* Calico: improve checks before deployment

* enforce disabling kube-proxy when using eBPF dataplane
* ensure calico_version is supported
This commit is contained in:
Cristian Calin 2021-06-07 14:58:39 +03:00 committed by GitHub
parent 1739b27231
commit ec0c0d4a28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 231 additions and 12 deletions

View file

@ -260,3 +260,73 @@ calico_ipam_host_local: true
``` ```
Refer to Project Calico section [Using host-local IPAM](https://docs.projectcalico.org/reference/cni-plugin/configuration#using-host-local-ipam) for further information. Refer to Project Calico section [Using host-local IPAM](https://docs.projectcalico.org/reference/cni-plugin/configuration#using-host-local-ipam) for further information.
## eBPF Support
Calico supports eBPF for its data plane see [an introduction to the Calico eBPF Dataplane](https://www.projectcalico.org/introducing-the-calico-ebpf-dataplane/) for further information.
Note that it is advisable to always use the latest version of Calico when using the eBPF dataplane.
### Enabling eBPF support
To enable the eBPF dataplane support ensure you add the following to your inventory. Note that the `kube-proxy` is incompatible with running Calico in eBPF mode and the kube-proxy should be removed from the system.
```yaml
calico_bpf_enabled: true
kube_proxy_remove: true
```
### Cleaning up after kube-proxy
Calico node cannot clean up after kube-proxy has run in ipvs mode. If you are converting an existing cluster to eBPF you will need to ensure the `kube-proxy` DaemonSet is deleted and that ipvs rules are cleaned.
To check that kube-proxy was running in ipvs mode:
```ShellSession
# ipvsadm -l
```
To clean up any ipvs leftovers:
```ShellSession
# ipvsadm -C
```
### Calico access to the kube-api
Calico node, typha and kube-controllers need to be able to talk to the kubernetes API. Please reference the [Enabling eBPF Calico Docs](https://docs.projectcalico.org/maintenance/ebpf/enabling-bpf) for guidelines on how to do this.
Kubespray sets up the `kubernetes-services-endpoint` configmap based on the contents of the `loadbalancer_apiserver` inventory variable documented in [HA Mode](./ha-mode.md).
If no external loadbalancer is used, Calico eBPF can also use the localhost loadbalancer option. In this case Calico Automatic Host Endpoints need to be enabled to allow services like `coredns` and `metrics-server` to communicate with the kubernetes host endpoint. See [this blog post](https://www.projectcalico.org/securing-kubernetes-nodes-with-calico-automatic-host-endpoints/) on enabling automatic host endpoints.
```yaml
loadbalancer_apiserver_localhost: true
use_localhost_as_kubeapi_loadbalancer: true
```
### Tunneled versus Direct Server Return
By default Calico usese Tunneled service mode but it can use direct server return (DSR) in order to optimize the return path for a service.
To configure DSR:
```yaml
calico_bpf_service_mode: "DSR"
```
### eBPF Logging and Troubleshooting
In order to enable Calico eBPF mode logging:
```yaml
calico_bpf_log_level: "Debug"
```
To view the logs you need to use the `tc` command to read the kernel trace buffer:
```ShellSession
tc exec bpf debug
```
Please see [Calico eBPF troubleshooting guide](https://docs.projectcalico.org/maintenance/troubleshoot/troubleshoot-ebpf#ebpf-program-debug-logs).

View file

@ -69,6 +69,7 @@ quay_image_repo: "quay.io"
calico_version: "v3.18.4" calico_version: "v3.18.4"
calico_ctl_version: "{{ calico_version }}" calico_ctl_version: "{{ calico_version }}"
calico_cni_version: "{{ calico_version }}" calico_cni_version: "{{ calico_version }}"
calico_flexvol_version: "{{ calico_version }}"
calico_policy_version: "{{ calico_version }}" calico_policy_version: "{{ calico_version }}"
calico_typha_version: "{{ calico_version }}" calico_typha_version: "{{ calico_version }}"
typha_enabled: false typha_enabled: false
@ -439,6 +440,8 @@ calico_node_image_repo: "{{ quay_image_repo }}/calico/node"
calico_node_image_tag: "{{ calico_version }}{%- if image_arch != 'amd64' -%}-{{ image_arch }}{%- endif -%}" calico_node_image_tag: "{{ calico_version }}{%- if image_arch != 'amd64' -%}-{{ image_arch }}{%- endif -%}"
calico_cni_image_repo: "{{ quay_image_repo }}/calico/cni" calico_cni_image_repo: "{{ quay_image_repo }}/calico/cni"
calico_cni_image_tag: "{{ calico_cni_version }}{%- if image_arch != 'amd64' -%}-{{ image_arch }}{%- endif -%}" calico_cni_image_tag: "{{ calico_cni_version }}{%- if image_arch != 'amd64' -%}-{{ image_arch }}{%- endif -%}"
calico_flexvol_image_repo: "{{ quay_image_repo }}/calico/pod2daemon-flexvol"
calico_flexvol_image_tag: "{{ calico_flexvol_version }}{%- if image_arch != 'amd64' -%}-{{ image_arch }}{%- endif -%}"
calico_policy_image_repo: "{{ quay_image_repo }}/calico/kube-controllers" calico_policy_image_repo: "{{ quay_image_repo }}/calico/kube-controllers"
calico_policy_image_tag: "{{ calico_policy_version }}{%- if image_arch != 'amd64' -%}-{{ image_arch }}{%- endif -%}" calico_policy_image_tag: "{{ calico_policy_version }}{%- if image_arch != 'amd64' -%}-{{ image_arch }}{%- endif -%}"
calico_typha_image_repo: "{{ quay_image_repo }}/calico/typha" calico_typha_image_repo: "{{ quay_image_repo }}/calico/typha"

View file

@ -47,6 +47,25 @@
- kube_network_plugin == 'calico' - kube_network_plugin == 'calico'
- not ignore_assert_errors - not ignore_assert_errors
- name: Stop if supported Calico versions
assert:
that:
- "calico_version in calico_crds_archive_checksums.keys()"
msg: "Calico version not supported {{ calico_version }} not in {{ calico_crds_archive_checksums.keys() }}"
when:
- kube_network_plugin == 'calico'
- not ignore_assert_errors
- name: Stop if kube-proxy is enabled when using eBPF dataplane
assert:
that:
- kube_proxy_remove
msg: "kube-proxy needs to be disabled when using Calico with eBPF dataplane"
when:
- calico_bpf_enabled | default(false)
- kube_network_plugin == 'calico'
- not ignore_assert_errors
- name: Stop if unsupported version of Kubernetes - name: Stop if unsupported version of Kubernetes
assert: assert:
that: kube_version is version(kube_version_min_required, '>=') that: kube_version is version(kube_version_min_required, '>=')

View file

@ -32,6 +32,12 @@ calico_advertise_service_external_ips: []
# Adveritse Service LoadBalancer IPs # Adveritse Service LoadBalancer IPs
calico_advertise_service_loadbalancer_ips: [] calico_advertise_service_loadbalancer_ips: []
# Calico eBPF support
calico_bpf_enabled: false
calico_bpf_log_level: ""
# Valid option for service mode: Tunnel (default), DSR=Direct Server Return
calico_bpf_service_mode: Tunnel
# Limits for apps # Limits for apps
calico_node_memory_limit: 500M calico_node_memory_limit: 500M
calico_node_cpu_limit: 300m calico_node_cpu_limit: 300m
@ -91,6 +97,8 @@ kube_etcd_key_file: node-{{ inventory_hostname }}-key.pem
# Use typha (only with kdd) # Use typha (only with kdd)
typha_enabled: false typha_enabled: false
typha_prometheusmetricsenabled: false
typha_prometheusmetricsport: 9093
# Scaling typha: 1 replica per 100 nodes is adequate # Scaling typha: 1 replica per 100 nodes is adequate
# Number of typha replicas # Number of typha replicas
@ -106,3 +114,7 @@ calico_feature_control: {}
# Calico default BGP port # Calico default BGP port
calico_bgp_listen_port: 179 calico_bgp_listen_port: 179
# Calico FelixConfiguration options
calico_felix_reporting_interval: 0s
calico_felix_log_severity_screen: Info

View file

@ -131,6 +131,27 @@
- inventory_hostname in groups['kube_control_plane'] - inventory_hostname in groups['kube_control_plane']
- calico_datastore == "kdd" - calico_datastore == "kdd"
- name: Calico | Configure calico FelixConfiguration
command:
cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
vars:
stdin: >
{ "kind": "FelixConfiguration",
"apiVersion": "projectcalico.org/v3",
"metadata": {
"name": "default",
},
"spec": {
"ipipEnabled": {{ calico_ipip_mode != 'Never' | bool }},
"reportingInterval": "{{ calico_felix_reporting_interval }}",
"bpfLogLevel": "{{ calico_bpf_log_level }}",
"bpfEnabled": {{ calico_bpf_enabled | bool }},
"bpfExternalServiceMode": "{{ calico_bpf_service_mode }}",
"logSeverityScreen": "{{ calico_felix_log_severity_screen }}" }}
when:
- inventory_hostname == groups['kube_control_plane'][0]
- name: Calico | Configure calico network pool - name: Calico | Configure calico network pool
command: command:
cmd: "{{ bin_dir }}/calicoctl.sh apply -f -" cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
@ -302,6 +323,7 @@
- {name: calico, file: calico-node-sa.yml, type: sa} - {name: calico, file: calico-node-sa.yml, type: sa}
- {name: calico, file: calico-cr.yml, type: clusterrole} - {name: calico, file: calico-cr.yml, type: clusterrole}
- {name: calico, file: calico-crb.yml, type: clusterrolebinding} - {name: calico, file: calico-crb.yml, type: clusterrolebinding}
- {name: kubernetes-services-endpoint, file: kubernetes-services-endpoint.yml, type: cm }
register: calico_node_manifests register: calico_node_manifests
when: when:
- inventory_hostname in groups['kube_control_plane'] - inventory_hostname in groups['kube_control_plane']

View file

@ -28,6 +28,7 @@ rules:
resources: resources:
- nodes/status - nodes/status
verbs: verbs:
# Needed for clearing NodeNetworkUnavailable flag.
- patch - patch
{% if calico_datastore == "etcd" %} {% if calico_datastore == "etcd" %}
- apiGroups: - apiGroups:

View file

@ -44,6 +44,11 @@ spec:
- name: upgrade-ipam - name: upgrade-ipam
image: {{ calico_cni_image_repo }}:{{ calico_cni_image_tag }} image: {{ calico_cni_image_repo }}:{{ calico_cni_image_tag }}
command: ["/opt/cni/bin/calico-ipam", "-upgrade"] command: ["/opt/cni/bin/calico-ipam", "-upgrade"]
envFrom:
- configMapRef:
# Allow KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT to be overridden for eBPF mode.
name: kubernetes-services-endpoint
optional: true
env: env:
- name: KUBERNETES_NODE_NAME - name: KUBERNETES_NODE_NAME
valueFrom: valueFrom:
@ -94,12 +99,26 @@ spec:
name: cni-bin-dir name: cni-bin-dir
securityContext: securityContext:
privileged: true privileged: true
# Adds a Flex Volume Driver that creates a per-pod Unix Domain Socket to allow Dikastes
# to communicate with Felix over the Policy Sync API.
- name: flexvol-driver
image: {{ calico_flexvol_image_repo }}:{{ calico_flexvol_image_tag }}
volumeMounts:
- name: flexvol-driver-host
mountPath: /host/driver
securityContext:
privileged: true
containers: containers:
# Runs calico/node container on each Kubernetes node. This # Runs calico/node container on each Kubernetes node. This
# container programs network policy and routes on each # container programs network policy and routes on each
# host. # host.
- name: calico-node - name: calico-node
image: {{ calico_node_image_repo }}:{{ calico_node_image_tag }} image: {{ calico_node_image_repo }}:{{ calico_node_image_tag }}
envFrom:
- configMapRef:
# Allow KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT to be overridden for eBPF mode.
name: kubernetes-services-endpoint
optional: true
env: env:
# The location of the Calico etcd cluster. # The location of the Calico etcd cluster.
{% if calico_datastore == "etcd" %} {% if calico_datastore == "etcd" %}
@ -231,8 +250,6 @@ spec:
{% if calico_ip_auto_method is defined %} {% if calico_ip_auto_method is defined %}
- name: IP_AUTODETECTION_METHOD - name: IP_AUTODETECTION_METHOD
value: "{{ calico_ip_auto_method }}" value: "{{ calico_ip_auto_method }}"
- name: IP
value: "autodetect"
{% else %} {% else %}
- name: NODEIP - name: NODEIP
valueFrom: valueFrom:
@ -240,9 +257,9 @@ spec:
fieldPath: status.hostIP fieldPath: status.hostIP
- name: IP_AUTODETECTION_METHOD - name: IP_AUTODETECTION_METHOD
value: "can-reach=$(NODEIP)" value: "can-reach=$(NODEIP)"
{% endif %}
- name: IP - name: IP
value: "autodetect" value: "autodetect"
{% endif %}
{% if enable_dual_stack_networks %} {% if enable_dual_stack_networks %}
- name: IP6 - name: IP6
value: autodetect value: autodetect
@ -286,10 +303,10 @@ spec:
{% if calico_network_backend|default("bird") == "bird" %} {% if calico_network_backend|default("bird") == "bird" %}
- -bird-live - -bird-live
{% endif %} {% endif %}
initialDelaySeconds: 5 periodSeconds: 10
initialDelaySeconds: 10
failureThreshold: 6 failureThreshold: 6
readinessProbe: readinessProbe:
failureThreshold: 6
exec: exec:
command: command:
- /bin/calico-node - /bin/calico-node
@ -297,18 +314,22 @@ spec:
- -bird-ready - -bird-ready
{% endif %} {% endif %}
- -felix-ready - -felix-ready
periodSeconds: 10
failureThreshold: 6
volumeMounts: volumeMounts:
- mountPath: /lib/modules - mountPath: /lib/modules
name: lib-modules name: lib-modules
readOnly: true readOnly: true
- mountPath: /var/run/calico - mountPath: /var/run/calico
name: var-run-calico name: var-run-calico
readOnly: false
- mountPath: /var/lib/calico - mountPath: /var/lib/calico
name: var-lib-calico name: var-lib-calico
readOnly: false readOnly: false
{% if calico_datastore == "etcd" %} {% if calico_datastore == "etcd" %}
- mountPath: /calico-secrets - mountPath: /calico-secrets
name: etcd-certs name: etcd-certs
readOnly: true
{% endif %} {% endif %}
- name: xtables-lock - name: xtables-lock
mountPath: /run/xtables.lock mountPath: /run/xtables.lock
@ -324,7 +345,20 @@ spec:
mountPath: /etc/typha-ca/ca.crt mountPath: /etc/typha-ca/ca.crt
readOnly: true readOnly: true
{% endif %} {% endif %}
- name: policysync
mountPath: /var/run/nodeagent
{% if calico_bpf_enabled %}
# For eBPF mode, we need to be able to mount the BPF filesystem at /sys/fs/bpf so we mount in the
# parent directory.
- name: sysfs
mountPath: /sys/fs/
# Bidirectional means that, if we mount the BPF filesystem at /sys/fs/bpf it will propagate to the host.
# If the host is known to mount that filesystem already then Bidirectional can be omitted.
mountPropagation: Bidirectional
{% endif %}
- name: cni-log-dir
mountPath: /var/log/calico/cni
readOnly: true
volumes: volumes:
# Used by calico/node. # Used by calico/node.
- name: lib-modules - name: lib-modules
@ -375,6 +409,26 @@ spec:
hostPath: hostPath:
path: "/etc/kubernetes/ssl/" path: "/etc/kubernetes/ssl/"
{% endif %} {% endif %}
{% if calico_bpf_enabled %}
- name: sysfs
hostPath:
path: /sys/fs/
type: DirectoryOrCreate
{% endif %}
# Used to access CNI logs.
- name: cni-log-dir
hostPath:
path: /var/log/calico/cni
# Used to create per-pod Unix Domain Sockets
- name: policysync
hostPath:
type: DirectoryOrCreate
path: /var/run/nodeagent
# Used to install Flex Volume Driver
- name: flexvol-driver-host
hostPath:
type: DirectoryOrCreate
path: "{{ kubelet_flexvolumes_plugins_dir | default('/usr/libexec/kubernetes/kubelet-plugins/volume/exec') }}/nodeagent~uds"
updateStrategy: updateStrategy:
rollingUpdate: rollingUpdate:
maxUnavailable: {{ serial | default('20%') }} maxUnavailable: {{ serial | default('20%') }}

View file

@ -46,6 +46,10 @@ spec:
k8s-app: calico-typha k8s-app: calico-typha
annotations: annotations:
cluster-autoscaler.kubernetes.io/safe-to-evict: 'true' cluster-autoscaler.kubernetes.io/safe-to-evict: 'true'
{% if typha_prometheusmetricsenabled %}
prometheus.io/scrape: 'true'
prometheus.io/port: "{{ typha_prometheusmetricsport }}"
{% endif %}
spec: spec:
nodeSelector: nodeSelector:
kubernetes.io/os: linux kubernetes.io/os: linux
@ -61,6 +65,9 @@ spec:
# as a host-networked pod. # as a host-networked pod.
serviceAccountName: calico-node serviceAccountName: calico-node
priorityClassName: system-cluster-critical priorityClassName: system-cluster-critical
# fsGroup allows using projected serviceaccount tokens as described here kubernetes/kubernetes#82573
securityContext:
fsGroup: 65534
containers: containers:
- image: {{ calico_typha_image_repo }}:{{ calico_typha_image_tag }} - image: {{ calico_typha_image_repo }}:{{ calico_typha_image_tag }}
name: calico-typha name: calico-typha
@ -68,6 +75,11 @@ spec:
- containerPort: 5473 - containerPort: 5473
name: calico-typha name: calico-typha
protocol: TCP protocol: TCP
envFrom:
- configMapRef:
# Allow KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT to be overridden for eBPF mode.
name: kubernetes-services-endpoint
optional: true
env: env:
# Enable "info" logging by default. Can be set to "debug" to increase verbosity. # Enable "info" logging by default. Can be set to "debug" to increase verbosity.
- name: TYPHA_LOGSEVERITYSCREEN - name: TYPHA_LOGSEVERITYSCREEN
@ -105,13 +117,14 @@ spec:
name: cacert name: cacert
readOnly: true readOnly: true
{% endif %} {% endif %}
# Uncomment these lines to enable prometheus metrics. Since Typha is host-networked, {% if typha_prometheusmetricsenabled %}
# Since Typha is host-networked,
# this opens a port on the host, which may need to be secured. # this opens a port on the host, which may need to be secured.
#- name: TYPHA_PROMETHEUSMETRICSENABLED - name: TYPHA_PROMETHEUSMETRICSENABLED
# value: "true" value: "true"
#- name: TYPHA_PROMETHEUSMETRICSPORT - name: TYPHA_PROMETHEUSMETRICSPORT
# value: "9093" value: "{{ typha_prometheusmetricsport }}"
{% endif %}
# Needed for version >=3.7 when the 'host-local' ipam is used # Needed for version >=3.7 when the 'host-local' ipam is used
# Should never happen given templates/cni-calico.conflist.j2 # Should never happen given templates/cni-calico.conflist.j2
# Configure route aggregation based on pod CIDR. # Configure route aggregation based on pod CIDR.

View file

@ -64,6 +64,12 @@
"capabilities": { "capabilities": {
"portMappings": true "portMappings": true
} }
},
{
"type":"bandwidth",
"capabilities": {
"bandwidth": true
}
} }
] ]
} }

View file

@ -0,0 +1,19 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
namespace: kube-system
name: kubernetes-services-endpoint
data:
{% if calico_bpf_enabled %}
{% if loadbalancer_apiserver is defined %}
KUBERNETES_SERVICE_HOST: "{{ apiserver_loadbalancer_domain_name }}"
KUBERNETES_SERVICE_PORT: "{{ loadbalancer_apiserver.port | default(kube_apiserver_port) }}"
{%- elif use_localhost_as_kubeapi_loadbalancer|default(False)|bool %}
KUBERNETES_SERVICE_HOST: "127.0.0.1"
KUBERNETES_SERVICE_PORT: "{{ kube_apiserver_port }}"
{%- else %}
KUBERNETES_SERVICE_HOST: "{{ first_kube_master }}"
KUBERNETES_SERVICE_PORT: "{{ kube_apiserver_port }}"
{%- endif %}
{% endif %}