Ce TP se déroule sur un cluster KinD.
- But du TP
- Etape 0 Préparation
- Etape 1 Lancement de KinD
- Etape 2 Déploiement de Containerlab
- Etape 3 Installation de Cilium
- Etape 4 Affichage des routes BGP
- Etape 5 Activation de BGP dans Cilium
- Etape 6 Vérification du routage
- Bonus L4LB
On utiliser cilium
en version 1.6.1 et l'implementation GoGBP
(via CRD
) et non MetalLB
(via ConfigMap
)
- Construire en lab une mini matrice de Clos (1 spine, 2 leaf), y connecter 4 Nodes.
- Activer BGP au niveau des Nodes pour diffuser les réseaux CIDRs des Pods.
Connectez-vous en SSH sur la VM auquel l'animateur vous donne accès.
Containerlab et KinD y sont déjà installés.
Nettoyons les eventuels clusters déjà présents :
cd /home/cilium_lab/bgp-cplane-demo
./clean-kind.sh
Lançons le cluster avec un script simple :
./01-build-kind-cluster.sh
Nous finissons pas obtenir :
[..]
---
Kubernetes control plane is running at https://127.0.0.1:36969
CoreDNS is running at https://127.0.0.1:36969/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
---
NAME STATUS ROLES AGE VERSION
clab-bgp-cplane-demo-control-plane NotReady control-plane 28s v1.24.0
clab-bgp-cplane-demo-worker NotReady <none> 5s v1.24.0
clab-bgp-cplane-demo-worker2 NotReady <none> 5s v1.24.0
clab-bgp-cplane-demo-worker3 NotReady <none> 5s v1.24.0
Les noeuds restent en NotReady
car le CNI n’est pas encore installé
Nous avons appliqué un label nommé rack
, qui permet de grouper les server
(dérouler tout à droite de la fenetre ci dessous) :
# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
clab-bgp-cplane-demo-control-plane NotReady control-plane 32m v1.24.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=clab-bgp-cplane-demo-control-plane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=,rack=rack0
clab-bgp-cplane-demo-worker NotReady <none> 32m v1.24.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=clab-bgp-cplane-demo-worker,kubernetes.io/os=linux,rack=rack0
clab-bgp-cplane-demo-worker2 NotReady <none> 32m v1.24.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=clab-bgp-cplane-demo-worker2,kubernetes.io/os=linux,rack=rack1
clab-bgp-cplane-demo-worker3 NotReady <none> 32m v1.24.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=clab-bgp-cplane-demo-worker3,kubernetes.io/os=linux,rack=rack1
Créeons un lab avec containerlab, consitué de 4 Node (server0
à server3
), chaque paire étant connectée sur un switch ToR (tor0
et tor1
), eux-même interconnectés sur un routeur central, router0
.
La topologie est décrite dans le fichier topo.yaml
.
./02-deploy-containerlab.sh
On obtient :
IMPORTANT : Tout d'abord vérifier que le fichier values.yaml
a le contenu suiviant :
routingMode: native
ipv4NativeRoutingCIDR: "10.0.0.0/8"
bgpControlPlane:
enabled: true
k8s:
requireIPv4PodCIR: true
ipam:
mode: kubernetes
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
Ensuite, installons le CNI Cilium :
./03-install-cilium.sh
Au final, cilium est prêt :
# cilium status
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Hubble: OK
\__/¯¯\__/ ClusterMesh: disabled
\__/
Deployment hubble-ui Desired: 1, Ready: 1/1, Available: 1/1
DaemonSet cilium Desired: 4, Ready: 4/4, Available: 4/4
Deployment hubble-relay Desired: 1, Ready: 1/1, Available: 1/1
Deployment cilium-operator Desired: 2, Ready: 2/2, Available: 2/2
Containers: cilium Running: 4
hubble-relay Running: 1
cilium-operator Running: 2
hubble-ui Running: 1
Nous avons crée un simple script qui se connecte dans un des switches (tor0
, tor1
ou router0
) et affiche la table BGP (show bgp ipv4 summary wide
, show bgp ipv4 wide
)
./showbgp.sh router0
On constate le peering vers tor0
et tor1
.
Regardons vu de tor0
:
./showbgp.sh tor0
Nous constatons qu'aucun préfixe n'est échange avec les server0
et server1
.
Creeons notre BGP advertisement avec le fichier cilium-bgp-advertisement.yaml
:
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
name: bgp-advertisements
labels:
advertise: bgp
spec:
advertisements:
- advertisementType: "Service"
service:
addresses:
- ClusterIP
- ExternalIP
- LoadBalancerIP
selector:
matchExpressions:
- { key: bgp, operator: In, values: [ blue ] }
Appliquons ces CRD :
kubectl apply -f cilium-bgp-advertisement.yaml
Activons BGP au niveau des Nodes grâce aux 2 politiques Cilium suivantes (1 par rack) :
## cilium-bgp-peering-policies.yaml
---
apiVersion: "cilium.io/v2alpha1"
kind: CiliumBGPPeeringPolicy
metadata:
name: rack0
namespace: kube-system
spec:
nodeSelector:
matchLabels:
rack: "rack0"
virtualRouters:
- localASN: 65010
exportPodCIDR: true
neighbors:
- peerAddress: "10.0.0.1/32"
peerASN: 65010
serviceSelector:
matchExpressions:
- {key: 'bgp', operator: In, values: ['blue']}
---
apiVersion: "cilium.io/v2alpha1"
kind: CiliumBGPPeeringPolicy
metadata:
name: "rack1"
namespace: kube-system
spec:
nodeSelector:
matchLabels:
rack: rack1
virtualRouters:
- localASN: 65011
exportPodCIDR: true
neighbors:
- peerAddress: "10.0.0.2/32"
peerASN: 65011
serviceSelector:
matchExpressions:
- {key: 'bgp', operator: In, values: ['blue']}
Appliquons cette politique :
# ./04-enable-bgp-cilium.sh
ciliumbgppeeringpolicy.cilium.io/rack0 created
ciliumbgppeeringpolicy.cilium.io/rack1 created
Regardons à nouveau les routeurs sur router0
:
Nous voyons les CIDRs des Pods apparaitre !
Nous laissons au lecteur le soin de déployer un DaemonSet (image=nginx par exemple), et de vérifier que les préfixes sont bien échangés en réalisant des connexions TCP/80 internodes.
Reconfigurons les paramètres Helm contenu dans le fichier values.yaml
:
ipv4NativeRoutingCIDR: "10.0.0.0/8"
kubeProxyReplacement: true
## add-on
externalIPs:
enabled: true
loadBalancer:
algorithm: maglev
bgp:
## desactive Metal LB
enabled: false
announce:
loadbalancerIP: true
podCIDR: true
##
bgpControlPlane:
## active GoBGP
enabled: true
k8s:
requireIPv4PodCIR: true
ipam:
mode: kubernetes
Appliquons ces modifications à Cilium :
C_VERSION="1.16.1"; helm upgrade --install --namespace kube-system --repo https://helm.cilium.io cilium cilium --values values.yaml --version $C_VERSION
Il faut également créer le fichier cilium-iploadbalancer-ippool.yaml
suivant :
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
name: "blue-pool"
spec:
blocks:
- cidr: "192.0.2.0/24"
serviceSelector:
matchExpressions:
- {key: bgp, operator: In, values: [blue, cyan]}
Appliquons la:
kubectl apply -f cilium-iploadbalancer-ippool.yaml
Redémarrons les DameonSet Cilium :
kubectl rollout restart ds/cilium -n kube-system
Pour activer la fonctionnalité LB, il nous faut un service à publier. Utilisons celui-là (notez le label qui activera la publication BGP):
## lbsvc.yaml
apiVersion: v1
kind: Service
metadata:
name: test-lb
labels:
bgp: blue
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
svc: test-lb
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
svc: test-lb
template:
metadata:
labels:
svc: test-lb
spec:
containers:
- name: web
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
Et appliquons-le :
kubectl apply -f lbsvc.yaml
On constate que le préfixe 192.0.2.0/32 est annoncé :
./showbgp.sh tor0
----- tor0 ----
IPv4 Unicast Summary (VRF default):
BGP router identifier 10.0.0.1, local AS number 65010 vrf-id 0
BGP table version 39
RIB entries 25, using 4600 bytes of memory
Peers 3, using 2149 KiB of memory
Peer groups 2, using 128 bytes of memory
Neighbor V AS LocalAS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
router0(net0) 4 65000 65010 812 815 0 0 0 00:38:54 8 14 N/A
clab-bgp-cplane-demo-control-plane(10.0.1.2) 4 65010 65010 558 579 0 0 0 00:00:31 2 11 N/A
clab-bgp-cplane-demo-worker(10.0.2.2) 4 65010 65010 563 586 0 0 0 00:00:34 2 11 N/A
Total number of neighbors 3
--
BGP table version is 39, local router ID is 10.0.0.1, vrf id 0
Default local pref 100, local AS 65010
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 0.0.0.0/0 net0 0 65000 i
*> 10.0.0.0/32 net0 0 0 65000 ?
*> 10.0.0.1/32 0.0.0.0(tor0) 0 32768 ?
*> 10.0.0.2/32 net0 0 65000 65011 ?
*> 10.0.1.0/24 0.0.0.0(tor0) 0 32768 ?
*> 10.0.2.0/24 0.0.0.0(tor0) 0 32768 ?
*> 10.0.3.0/24 net0 0 65000 65011 ?
*> 10.0.4.0/24 net0 0 65000 65011 ?
*>i10.244.0.0/24 10.0.1.2(clab-bgp-cplane-demo-control-plane)
0 0 ?
*>i10.244.1.0/24 10.0.2.2(clab-bgp-cplane-demo-worker) 0 0 ?
*> 10.244.2.0/24 net0 0 65000 65011 i
*> 10.244.3.0/24 net0 0 65000 65011 i
*> 172.20.20.0/24 net0 0 0 65000 ?
*>i192.0.2.0/32 10.0.1.2(clab-bgp-cplane-demo-control-plane)
0 0 ?
*=i 10.0.2.2(clab-bgp-cplane-demo-worker) 0 0 ?
Displayed 14 routes and 15 total paths
Et l'IP LB est bien attribuée :
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 51m
svc-echoserver LoadBalancer 10.245.137.44 192.0.2.0 80:30516/TCP 35m
On peut tester :
# kubectl run debug2 -it --rm --image=alpine -- sh
If you don't see a command prompt, try pressing enter.
/ # curl 192.0.2.0
sh: curl: not found
/ # wget 192.0.2.0
Connecting to 192.0.2.0 (192.0.2.0:80)
saving to 'index.html'
index.html 100% |***********************************************************************************| 1868 0:00:00 ETA
'index.html' saved
/ #
Pour note, l'annonce BGP de l'IP LoadBalancer n'a lieu que si au moins 1 Pod fait partie du svc.