IPv6 gebruiken met Microk8s
Het configureren van dual-stack Microk8s is veel eenvoudiger dan verwacht.
Voor een deel van mijn applicatie dat bestaat uit verschillende Docker-Compose projecten, had ik toegang nodig tot externe IPv6-only services. In eerdere posts schreef ik dat ik al een deel van mijn applicatie had verplaatst van Docker naar Microk8s (Kubernetes). Dit is het deel dat toegang vereist tot de externe IPv6-diensten. De Docker applicatie communiceert met de Microk8s applicatie via een NodePort of Ingress Controller.
Mijn ontwikkelmachine bevindt zich op een lokaal IPv4-netwerk en mijn internetverbinding is ook IPv4. Ik wil mijn internetverbinding zeker niet veranderen van IPv4 naar IPv6.
In deze post maken we een IPv6, in feite een dual-stack, testomgeving waar we een applicatie kunnen draaien in Microk8s die toegang heeft tot een IPv6 dummy service die draait op een virtuele machine gemaakt met VirtualBox.
Zoals altijd doe ik dit op Ubuntu 22.04 Desktop.
Over IPv6-adressen
Hoewel het niet erg complex is, is goede uitleg over IPv6 te vinden in 'IPv6 Explained for Beginners', zie onderstaande links, erg nuttig.
In het kort bestaat een IPv6-adres uit 128 bits. Deze zijn opgesplitst in een netwerkdeel en een knooppuntdeel, die elk 64-bits hebben. Van het netwerk worden de bovenste 48-bits gebruikt voor routering over het internet.
Hier gebruiken we de IPv6-documentatie prefix, 2001:db8::/32. Uit het document "Understanding the IPv6 Documentation Prefix: 2001:db8::/32", zie onderstaande links: Dit is een gereserveerde reeks IPv6-adressen die gereserveerd is voor gebruik in documentatie, voorbeelden en educatief materiaal. Dit prefix werd gekozen om ervoor te zorgen dat adressen die dit gebruiken niet per ongeluk op het internet worden gerouteerd, waardoor conflicten met echte IPv6-adressen worden voorkomen.
Dit betekent dat het netwerkgedeelte 32-bits is. Voor ons netwerk voegen we 'abcd:0012' toe.
Voorbeeldadres van een knooppunt op ons netwerk:
2001:db8:abcd:12::1
Wat een afkorting is voor:
2001:0db8:abcd:0012:0000:0000:0000:0001
Het 'Prefix' is als het masker in IPv4.
IPv6 in- en uitschakelen op Ubuntu
In Ubuntu kunnen we IPv6-instellingen in- en uitschakelen met het commando sysctl. Om de instellingen te bekijken:
sysctl -a 2>/dev/null | grep disable_ipv6
Lang geleden heb ik IPv6 uitgeschakeld op mijn ontwikkelmachine. Ik heb het volgende toegevoegd:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
net.ipv6.conf.tun0.disable_ipv6 = 1
Aan het bestand:
/etc/sysctl.conf
Nu moet ik deze regels opnieuw becommentariëren.
We kunnen deze waarden ook tijdelijk instellen, bijvoorbeeld:
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
Om alle instellingen opnieuw te laden, geven we het commando:
sudo sysctl --system
Alle 'disable_ipv6' waarden moeten op '0' staan.
Zorg er ook voor dat het bestand:
/etc/hosts
de volgende regels bevat, waarbij ::1 het loopback-adres is:
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Configuratie van de ontwikkelmachine en VirtualBox
De ontwikkelmachine, Ubuntu Desktop, gebruikte al IPv4, ik hoefde alleen IPv6 toe te voegen. We hebben geen gateway of DNS-server, dus we zetten er gewoon wat willekeurige adressen op.
Met behulp van VirtualBox maken we een Ubuntu 22.04 server. We wijzen de volgende adressen toe aan de ontwikkelmachine en de nieuwe virtuele machine:
Ubuntu 220.04 Desktop
Address: 2001:db8:abcd:12::1
Prefix: 64
Gateway: 2001:db8:abcd:12::2
DNS: Automatic
Routes: Automatic
Ubuntu 220.04 Server (Virtualbox)
Address: 2001:db8:abcd:12::1:1/64
Prefix: 64
Gateway: 2001:db8:abcd:12::2
DNS: Automatic
Routes: Automatic
Op onze VirtualBox Ubuntu 22.04 server gebruiken we de 'Bridged Adapter' voor netwerken. In Ubuntu 22.04 Server bewerken we de netwerkconfiguratie in:
/etc/netplan/00-installer-config.yaml
Inhoud:
network:
ethernets:
enp0s3:
dhcp4: no
dhcp6: no
addresses:
- 192.168.1.26/24
- 2001:db8:abcd:12::1:1/64
nameservers:
addresses:
- 192.168.1.2
- 2606:4700:4700::1111
routes:
- to: default
via: 192.168.1.1
- to: default
via: "2001:db8:abcd:12::2"
version: 2
Merk op dat ik hier IPv4-instellingen heb opgenomen. Ik weet niet of de standaard SSH-serverinstellingen IPv6 bevatten. Nu kunnen we in ieder geval inloggen via IPv4. Als we klaar zijn, activeren we het opnieuw:
sudo netplan apply
Op beide machines kunnen we de IPv6-adressen controleren:.
Op de ontwikkelmachine:
ip a | grep inet6
Resultaat:
inet6 ::1/128 scope host
inet6 2001:db8:abcd:12::1/64 scope global noprefixroute
inet6 fe80::fe11:314e:9bb4:73c1/64 scope link noprefixroute
...
Op de virtuele machine:
ip a | grep inet6
Resultaat:
inet6 ::1/128 scope host
inet6 2001:db8:abcd:12::1:1/64 scope global
inet6 fe80::a00:27ff:feda:7026/64 scope link
...
Controleer IPv6 op beide machines en of ze kunnen communiceren
Op beide machines kunnen we draaien:
ping6 ::1
Resultaat:
64 bytes from ip6-localhost: icmp_seq=0 ttl=64 time=0,078 ms
64 bytes from ip6-localhost: icmp_seq=1 ttl=64 time=0,048 ms
64 bytes from ip6-localhost: icmp_seq=2 ttl=64 time=0,048 ms
Op de ontwikkelmachine pingen we de virtuele machine:
ping6 2001:db8:abcd:12::1:1
Op de virtuele machine pingen we de ontwikkelmachine:
ping6 2001:db8:abcd:12::1
Tot slot controleren we of we een service kunnen draaien op de virtuele machine en of we toegang hebben tot deze service.
Op de virtuele machine starten we 'netcat' en binden deze aan het IPv6-adres:
nc -l 2001:db8:abcd:12::1:1 3492
Op de ontwikkelmachine starten we 'telnet', typen 'hello' en kijken of het echo-ed:
telnet -6 2001:db8:abcd:12::1:1 3492
Resultaat:
Trying 2001:db8:abcd:12::1:1...
Connected to 2001:db8:abcd:12::1:1.
Escape character is '^]'.
hello
^]
telnet> quit
Connection closed.
Werkt, mooi.
Microk8s installeren met een dual-stack
Dit bleek veel eenvoudiger dan verwacht. Ik volgde de instructies uit de post 'How to configure network Dual-stack', zie onderstaande links.
Op de ontwikkelmachine maken we eerst een bestand aan:
/var/snap/microk8s/common/.microk8s.yaml
met de volgende inhoud:
---
version: 0.1.0
extraCNIEnv:
IPv4_SUPPORT: true
IPv4_CLUSTER_CIDR: 10.3.0.0/16
IPv4_SERVICE_CIDR: 10.153.183.0/24
IPv6_SUPPORT: true
IPv6_CLUSTER_CIDR: fd02::/64
IPv6_SERVICE_CIDR: fd99::/108
extraSANs:
- 10.153.183.1
addons:
- name: dns
Opmerking(en):
- Hier schakelen we 'dns' in. Als u dit hier niet doet, dan moet u dit doen na de installatie van Microk8s!
- We wijzen hier unieke Local Address's (ULA) toe, deze kunnen niet over het openbare internet gerouteerd worden.
Vervolgens installeren we Microk8s:
snap install microk8s --classic
Controleer of de pods een IPv4- en een IPv6-adres toegewezen krijgen, bijvoorbeeld door te draaien:
microk8s kubectl -n kube-system describe pod
Het zou zoiets als dit moeten tonen voor elke pod daar:
...
IPs:
IP: 10.3.105.121
IP: fd02::332e:7684:ac2:6979
...
Nu draaien we BusyBox in Microk8s:
kubectl run -i -t busybox --image=busybox --restart=Never
Eenmaal uitgevoerd kunnen we controleren of er een IPv6-adres is toegewezen:
cat /etc/hosts
Resultaat:
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.3.105.122 busybox
fd02::332e:7684:ac2:697a busybox
IPv6 testen met Microk8s
Start op de ontwikkelmachine een 'netcat' listener:
nc -l 2001:db8:abcd:12::1 3491
Vervolgens proberen we in de BusyBox-terminal verbinding te maken en typen we een bericht:
telnet -6 2001:db8:abcd:12::1 3491
Resultaat:
Connected to 2001:db8:abcd:12::1
hello
^]
Console escape. Commands are:
l go to line mode
c go to character mode
z suspend telnet
e exit telnet
e
Start nu de 'netcat' listener op de virtuele machine:
nc -l 2001:db8:abcd:12::1:1 3492
Opnieuw proberen we in BusyBox op de ontwikkelmachine verbinding te maken:
telnet 2001:db8:abcd:12::1:1 3492
Er wordt geen verbinding gemaakt! Dit was te verwachten. Uitgaand IPv6-verkeer is geblokkeerd.
Uit de post 'Enabling IPv6 for SC4SNMP', zie onderstaande links: De standaard CNI die wordt gebruikt voor microk8s is Calico. Om pods internet te laten bereiken via IPv6, moet je de parameter natOutgoing inschakelen in ipv6 ip pool configuration van calico. Om dit in te stellen maak je een yaml bestand met de volgende inhoud:
# calico-ippool.yaml
---
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
name: default-ipv6-ippool
spec:
natOutgoing: true
Om te activeren:
microk8s kubectl apply -f calico-ippool.yaml
Stop en start Microk8s:
microk8s stop
microk8s start
Verwijder nu de BusyBox pod en start deze opnieuw op:
kubectl delete pod busybox
kubectl run -i -t busybox --image=busybox --restart=Never
Opnieuw proberen we in BusyBox op de ontwikkelmachine verbinding te maken met de lister in de virtuele machine en typen een bericht:
telnet 2001:db8:abcd:12::1:1 3492
Resultaat:
Connected to 2001:db8:abcd:12::1:1
hello
^]
Console escape. Commands are:
l go to line mode
c go to character mode
z suspend telnet
e exit telnet
e
Geweldig, nu werkt het!
Meer over Calico en IP pools
Calico (Project Calico Documentation) is een open source netwerk- en netwerkbeveiligingsoplossing voor containers, virtuele machines en native host-gebaseerde werklasten.
Van 'Microk8s - Calico configureren', zie onderstaande koppelingen: Voor de meeste gevallen [] is de manier om de Calico-configuratie te wijzigen het patchen van de geïmplementeerde cni.yaml en deze vervolgens opnieuw toe te passen op het cluster.
Om de calico api-resources te controleren:
kubectl api-resources | grep 'projectcalico.org'
Resultaat:
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bgpconfigurations crd.projectcalico.org/v1 false BGPConfiguration
bgppeers crd.projectcalico.org/v1 false BGPPeer
blockaffinities crd.projectcalico.org/v1 false BlockAffinity
caliconodestatuses crd.projectcalico.org/v1 false CalicoNodeStatus
clusterinformations crd.projectcalico.org/v1 false ClusterInformation
felixconfigurations crd.projectcalico.org/v1 false FelixConfiguration
globalnetworkpolicies crd.projectcalico.org/v1 false GlobalNetworkPolicy
globalnetworksets crd.projectcalico.org/v1 false GlobalNetworkSet
hostendpoints crd.projectcalico.org/v1 false HostEndpoint
ipamblocks crd.projectcalico.org/v1 false IPAMBlock
ipamconfigs crd.projectcalico.org/v1 false IPAMConfig
ipamhandles crd.projectcalico.org/v1 false IPAMHandle
ippools crd.projectcalico.org/v1 false IPPool
ipreservations crd.projectcalico.org/v1 false IPReservation
kubecontrollersconfigurations crd.projectcalico.org/v1 false KubeControllersConfiguration
networkpolicies crd.projectcalico.org/v1 true NetworkPolicy
networksets crd.projectcalico.org/v1 true NetworkSet
Om de IP pools te krijgen:
kubectl get ippools
Resultaat:
NAME AGE
default-ipv4-ippool 11d
default-ipv6-ippool 11d
Om de IP pools te beschrijven:
kubectl describe IPPool
Resultaat:
Name: default-ipv4-ippool
Namespace:
Labels:
Annotations: projectcalico.org/metadata: {"uid":"421fa69c-6657-4bd3-8bba-a06681c33c82","creationTimestamp":"2024-11-21T14:11:25Z"}
API Version: crd.projectcalico.org/v1
Kind: IPPool
Metadata:
Creation Timestamp: 2024-11-21T14:11:25Z
Generation: 1
Resource Version: 108882
UID: 50e3ccfc-627d-42f8-aaa3-a61e6553f8ed
Spec:
Allowed Uses:
Workload
Tunnel
Block Size: 26
Cidr: 10.3.0.0/16
Ipip Mode: Never
Nat Outgoing: true
Node Selector: all()
Vxlan Mode: Always
Events:
Name: default-ipv6-ippool
Namespace:
Labels:
Annotations: projectcalico.org/metadata: {"uid":"8377dd46-681d-4dbd-88a4-86e04a1d52c3","creationTimestamp":"2024-11-21T14:11:25Z"}
API Version: crd.projectcalico.org/v1
Kind: IPPool
Metadata:
Creation Timestamp: 2024-11-21T14:11:25Z
Generation: 2
Resource Version: 1506748
UID: 49501699-831f-4317-9c9f-2d2b15168547
Spec:
Allowed Uses:
Workload
Tunnel
Block Size: 122
Cidr: fd02::/64
Ipip Mode: Never
Nat Outgoing: true
Node Selector: all()
Vxlan Mode: Always
Events:
Merk op dat 'Nat uitgaand' 'true' is voor zowel de 'default-ipv4-ippool' als de 'default-ipv6-ippool'.
We kunnen ook calicoctl gebruiken. Maar eerst moeten we het installeren.
De huidige versie van Calico is geïnstalleerd in Microk8s:
kubectl -n kube-system describe pod calico-kube-controllers-759cd8b574-wscp9 | grep Image
Resultaat:
Image: docker.io/calico/kube-controllers:v3.25.1
Image ID: docker.io/calico/kube-controllers@sha256:02c1232ee4b8c5a145c401ac1adb34a63ee7fc46b70b6ad0a4e068a774f25f8a
Dit betekent dat de huidige versie van Calico is:
v3.25.1
Om het calicoctl manifest te krijgen:
wget https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml
Om te activeren:
kubectl apply -f calicoctl.yaml
Om te controleren of het draait:
kubectl get pods -A
Resultaat:
NAMESPACE NAME READY STATUS RESTARTS AGE
...
kube-system calicoctl 1/1 Running 0 2m17s
...
De calico-profielen ophalen:
kubectl exec -ti -n kube-system calicoctl -- /calicoctl get profiles -o wide
Resultaat:
NAME LABELS
projectcalico-default-allow
kns.default pcns.kubernetes.io/metadata.name=default,pcns.projectcalico.org/name=default
kns.ingress pcns.kubernetes.io/metadata.name=ingress,pcns.projectcalico.org/name=ingress
kns.kube-node-lease pcns.kubernetes.io/metadata.name=kube-node-lease,pcns.projectcalico.org/name=kube-node-lease
...
Om een calicoctl alias aan te maken:
alias calicoctl="kubectl exec -i -n kube-system calicoctl -- /calicoctl"
Nu kunnen we het bovenstaande commando als volgt uitvoeren:
calicoctl get profiles -o wide
We kunnen calicoctl ook gebruiken om de IP pools op te halen:
calicoctl get ippools
Resultaat:
NAME CIDR SELECTOR
default-ipv4-ippool 10.3.0.0/16 all()
default-ipv6-ippool fd02::/64 all()
Om meer te laten zien:
calicoctl get IPPool default-ipv6-ippool -o wide
Resultaat:
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv6-ippool fd02::/64 true Never Always false false all()
We kunnen een IP pool verwijderen en aanmaken:
calicoctl delete ippool <ippool-to-delete>
cat <<EOF | calicoctl create -f -
- apiVersion: v1
kind: ipPool
metadata:
cidr: fd0e:c226:9228:fd1a::/64
spec: {}
EOF
Of een bestaande IP pool vervangen. Voorbeeld:
calicoctl replace -f - << EOF
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: default-ipv6-ippool
spec:
blockSize: 122
cidr: fd01::/64
ipipMode: Never
nodeSelector: all()
vxlanMode: Never
natOutgoing: true
EOF
Samenvatting
We hebben een IPv6-testomgeving gemaakt voor Microk8s applicaties die toegang moeten hebben tot externe IPv6-services. Met VirtualBox hebben we een virtuele Ubuntu servermachine gemaakt en IPv6 ingeschakeld op zowel de ontwikkelmachine als de virtuele machine. Vervolgens hebben we dual-stack Microk8s geïnstalleerd op de ontwikkelmachine en uitgaand IPv6-verkeer ingeschakeld. Nu kunnen we 'telnet' binnen Microk8s op de ontwikkelmachine naar een IPv6-service die op de virtuele machine draait.
Links / credits
Building a multi-node IPv6-enabled bare-metal kubernetes cluster with microk8s, metallb, longhorn and VyOS
https://blog.mowoe.com/building-a-multi-node-ipv6-enabled-bare-metal-kubernetes-cluster-with-microk8s-metallb-longhorn-and-vyos.html
calicoctl user reference
https://docs.tigera.io/calico/latest/reference/calicoctl/overview
How to configure network Dual-stack
https://discuss.kubernetes.io/t/how-to-configure-network-dual-stack/24784
IPv6 Explained for Beginners
http://www.steves-internet-guide.com/ipv6-guide
IPv6 masquerading for egress on microk8s on EC2
https://www.checklyhq.com/blog/ipv6-masquerading-for-egress-on-microk8s-on-ec2
Kubernetes - IPv4/IPv6 dual-stack
https://kubernetes.io/docs/concepts/services-networking/dual-stack
Microk8s - Configure Calico
https://microk8s.io/docs/change-cidr
Understanding the IPv6 Documentation Prefix: 2001:db8::/32
https://ipv6.net/blog/understanding-the-ipv6-documentation-prefix-2001db8-32