Utilización de IPv6 con Microk8s
Configurar Microk8s dual-stack es mucho más fácil de lo esperado.

Para una parte de mi aplicación que consiste en varios proyectos Docker-Compose, necesitaba acceso a servicios externos sólo IPv6. En entradas anteriores escribí que ya había movido parte de mi aplicación de Docker a Microk8s (Kubernetes). Esta es la parte que requiere acceso a los servicios IPv6 externos. La aplicación Docker se comunica con la aplicación Microk8s usando un NodePort o Ingress Controller.
Mi máquina de desarrollo está en una red local sólo IPv4, y mi conexión a Internet también es IPv4. Ciertamente no quiero cambiar mi conexión ISP de IPv4 a IPv6.
En este post crearemos un entorno de pruebas IPv6, de hecho dual-stack, donde podremos ejecutar una aplicación en Microk8s que puede acceder a un servicio ficticio IPv6 que se ejecuta en una máquina virtual creada con VirtualBox.
Como siempre estoy haciendo esto en Ubuntu 22.04 Desktop.
Sobre las direcciones IPv6
Aunque no es muy complejo, se pueden encontrar buenas explicaciones sobre IPv6 en 'IPv6 Explained for Beginners', ver enlaces más abajo, muy útil.
En resumen, una dirección IPv6 consta de 128 bits. Estos se dividen en una parte de red y otra de nodo, cada una con 64 bits. Los 48 bits superiores de la red se utilizan para el encaminamiento a través de Internet.
Aquí utilizamos la documentación IPv6 prefix, 2001:db8::/32. Del documento "Understanding the IPv6 Documentation Prefix: 2001:db8::/32", ver enlaces más abajo: Se trata de un rango reservado de direcciones IPv6 reservado para su uso en documentación, ejemplos y material educativo. Se eligió este prefix para garantizar que ninguna dirección que lo utilice se enrute accidentalmente en Internet, evitando así conflictos con direcciones IPv6 del mundo real.
Esto significa que la parte de red es de 32 bits. Para nuestra red, añadimos 'abcd:0012'.
Dirección de ejemplo de un nodo de nuestra red:
2001:db8:abcd:12::1
Que es la abreviatura de:
2001:0db8:abcd:0012:0000:0000:0000:0001
El 'Prefijo' es como la máscara en IPv4.
Activar y desactivar IPv6 en Ubuntu
En Ubuntu podemos habilitar y deshabilitar la configuración de IPv6 usando el comando sysctl. Para ver la configuración:
sysctl -a 2>/dev/null | grep disable_ipv6
Hace tiempo deshabilité IPv6 en mi máquina de desarrollo. Añadí lo siguiente:
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
Al archivo:
/etc/sysctl.conf
Ahora debo volver a comentar estas líneas.
También podemos establecer estos valores temporalmente, ejemplo:
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
Para recargar todos los valores de nuevo, ejecutamos el comando:
sudo sysctl --system
Todos los valores de 'disable_ipv6' deben ser '0'.
También asegúrate de que el archivo
/etc/hosts
contiene las siguientes líneas, donde ::1 es la dirección loopback:
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Configuración de la máquina de desarrollo y VirtualBox
La máquina de desarrollo, Ubuntu Desktop, ya estaba usando IPv4, sólo necesitaba añadir IPv6. No tenemos puerta de enlace ni servidor DNS, así que simplemente ponemos algunas direcciones aleatorias.
Usando VirtualBox, creamos un servidor Ubuntu 22.04. Asignamos las siguientes direcciones a la máquina de desarrollo y a la nueva máquina virtual:
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
En nuestro servidor VirtualBox Ubuntu 22.04 utilizamos el 'Bridged Adapter' para la conexión en red. En Ubuntu 22.04 Server, editamos la configuración de red en:
/etc/netplan/00-installer-config.yaml
Contenido:
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
Nótese que aquí he incluido la configuración IPv4. Desconozco si la configuración por defecto del servidor SSH incluye IPv6. Ahora podemos iniciar sesión al menos a través de IPv4. Cuando esté hecho, lo reactivamos:
sudo netplan apply
En ambas máquinas podemos comprobar las direcciones IPv6:.
En la máquina de desarrollo:
ip a | grep inet6
Resultado:
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
...
En la máquina virtual:
ip a | grep inet6
Resultado:
inet6 ::1/128 scope host
inet6 2001:db8:abcd:12::1:1/64 scope global
inet6 fe80::a00:27ff:feda:7026/64 scope link
...
Comprobamos IPv6 en ambas máquinas y si se pueden comunicar
En ambas máquinas podemos ejecutar:
ping6 ::1
Resultado:
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
En la máquina de desarrollo, hacemos ping a la máquina virtual:
ping6 2001:db8:abcd:12::1:1
En la máquina virtual, hacemos ping a la máquina de desarrollo:
ping6 2001:db8:abcd:12::1
Por último, comprobamos si podemos ejecutar un servicio en la máquina virtual y vemos si podemos acceder a este servicio.
En la máquina virtual, iniciamos 'netcat', y lo vinculamos a la dirección IPv6:
nc -l 2001:db8:abcd:12::1:1 3492
En la máquina de desarrollo, arrancamos 'telnet', escribimos 'hello' y comprobamos si se hace eco:
telnet -6 2001:db8:abcd:12::1:1 3492
Resultado:
Trying 2001:db8:abcd:12::1:1...
Connected to 2001:db8:abcd:12::1:1.
Escape character is '^]'.
hello
^]
telnet> quit
Connection closed.
Funcionando, bien.
Instalando Microk8s con un dual-stack
Esto resultó ser mucho más fácil de lo esperado. Seguí las instrucciones del post 'Cómo configurar Dual-stack de red', ver enlaces más abajo.
En la máquina de desarrollo, primero creamos un fichero
/var/snap/microk8s/common/.microk8s.yaml
con el siguiente contenido:
---
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
Nota(s):
- Aquí habilitamos 'dns'. ¡Si usted no hace esto aquí, entonces usted debe hacer esto después de instalar Microk8s!
- Asignamos Unique Local Addresses (ULA) aquí, no pueden ser enrutados en la Internet pública.
A continuación, instalamos Microk8s:
snap install microk8s --classic
Compruebe si los pods tienen asignada una dirección IPv4 y otra IPv6, por ejemplo ejecutando:
microk8s kubectl -n kube-system describe pod
Debería mostrar algo como esto para cada pod allí:
...
IPs:
IP: 10.3.105.121
IP: fd02::332e:7684:ac2:6979
...
Ahora ejecutamos BusyBox en Microk8s:
kubectl run -i -t busybox --image=busybox --restart=Never
Una vez ejecutado podemos comprobar si se ha asignado una dirección IPv6:
cat /etc/hosts
Resultado:
# 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
Pruebas IPv6 con Microk8s
En la máquina de desarrollo, iniciamos un listener 'netcat' :
nc -l 2001:db8:abcd:12::1 3491
A continuación, en el terminal BusyBox, intentamos conectarnos, y escribimos un mensaje:
telnet -6 2001:db8:abcd:12::1 3491
Resultado:
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
Ahora iniciamos el listener 'netcat' en la máquina virtual:
nc -l 2001:db8:abcd:12::1:1 3492
De nuevo, en BusyBox en la máquina de desarrollo intentamos conectar:
telnet 2001:db8:abcd:12::1:1 3492
¡No se conecta! Esto era de esperar. El tráfico IPv6 saliente está bloqueado.
Del post 'Enabling IPv6 for SC4SNMP', ver enlaces más abajo: El CNI por defecto utilizado para microk8s es Calico. Para que los pods puedan llegar a internet a través de IPv6, necesita habilitar el parámetro natOutgoing en la configuración ipv6 ip pool de calico. Para activarlo cree el fichero yaml con el siguiente contenido:
# calico-ippool.yaml
---
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
name: default-ipv6-ippool
spec:
natOutgoing: true
Activar:
microk8s kubectl apply -f calico-ippool.yaml
Parar y arrancar Microk8s:
microk8s stop
microk8s start
Ahora quita y reinicia el pod de BusyBox:
kubectl delete pod busybox
kubectl run -i -t busybox --image=busybox --restart=Never
De nuevo, en BusyBox en la máquina de desarrollo intentamos conectar con el lister en la máquina virtual y escribimos un mensaje:
telnet 2001:db8:abcd:12::1:1 3492
Resultado:
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
Genial, ¡ahora funciona!
Más sobre Calico y IP pools
Calico (Project Calico Documentation) es una solución open source de redes y seguridad de redes para contenedores, máquinas virtuales y cargas de trabajo nativas basadas en host.
Desde 'Microk8s - Configurar Calico', ver enlaces más abajo: Para la mayoría de los casos [], la forma de cambiar la configuración de Calico es parchear el cni.yaml desplegado y luego volver a aplicarlo al cluster.
Para comprobar los recursos api de calico:
kubectl api-resources | grep 'projectcalico.org'
Resultado:
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
Para obtener las IP pools:
kubectl get ippools
Resultado:
NAME AGE
default-ipv4-ippool 11d
default-ipv6-ippool 11d
Para describir los IP pools:
kubectl describe IPPool
Resultado:
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:
Observa que 'Nat Outgoing' es 'true' tanto para 'default-ipv4-ippool' como para 'default-ipv6-ippool'.
También podemos usar calicoctl. Pero primero debemos instalarlo.
Para obtener la versión actual de Calico instalado en Microk8s:
kubectl -n kube-system describe pod calico-kube-controllers-759cd8b574-wscp9 | grep Image
Resultado:
Image: docker.io/calico/kube-controllers:v3.25.1
Image ID: docker.io/calico/kube-controllers@sha256:02c1232ee4b8c5a145c401ac1adb34a63ee7fc46b70b6ad0a4e068a774f25f8a
Esto significa que la versión actual de Calico es:
v3.25.1
Para obtener el manifiesto calicoctl:
wget https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml
Para activarlo:
kubectl apply -f calicoctl.yaml
Para comprobar que se está ejecutando:
kubectl get pods -A
Resultado:
NAMESPACE NAME READY STATUS RESTARTS AGE
...
kube-system calicoctl 1/1 Running 0 2m17s
...
Para obtener los perfiles de calico:
kubectl exec -ti -n kube-system calicoctl -- /calicoctl get profiles -o wide
Resultado:
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
...
Para crear un alias calicoctl:
alias calicoctl="kubectl exec -i -n kube-system calicoctl -- /calicoctl"
Ahora podemos ejecutar el comando anterior de la siguiente manera:
calicoctl get profiles -o wide
También podemos usar calicoctl para obtener las IP pools:
calicoctl get ippools
Resultado:
NAME CIDR SELECTOR
default-ipv4-ippool 10.3.0.0/16 all()
default-ipv6-ippool fd02::/64 all()
Para mostrar más:
calicoctl get IPPool default-ipv6-ippool -o wide
Resultado:
NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR
default-ipv6-ippool fd02::/64 true Never Always false false all()
Podemos borrar y crear un pool de IPs:
calicoctl delete ippool <ippool-to-delete>
cat <<EOF | calicoctl create -f -
- apiVersion: v1
kind: ipPool
metadata:
cidr: fd0e:c226:9228:fd1a::/64
spec: {}
EOF
O, reemplazar un pool IP existente. Ejemplo:
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
Resumen
Creamos un entorno de pruebas IPv6 para aplicaciones Microk8s que deben acceder a servicios externos IPv6. Usando VirtualBox creamos una máquina virtual de servidor Ubuntu y habilitamos IPv6 tanto en la máquina de desarrollo como en la máquina virtual. Luego instalamos dual-stack Microk8s en la máquina de desarrollo y habilitamos el tráfico IPv6 saliente. Ahora podemos 'telnet' dentro de Microk8s en la máquina de desarrollo a un servicio IPv6 que se ejecuta en la máquina virtual.
Enlaces / créditos
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
Leer más
Kubernetes Microk8s Networking
Recientes
- Gráfico de series temporales con Flask, Bootstrap y Chart.js
- Utilización de IPv6 con Microk8s
- Uso de Ingress para acceder a RabbitMQ en un clúster Microk8s
- Galería de vídeo simple con Flask, Jinja, Bootstrap y JQuery
- Programación básica de trabajos con APScheduler
- Un conmutador de base de datos con HAProxy y el HAProxy Runtime API
Más vistos
- Usando PyInstaller y Cython para crear un ejecutable de Python
- Reducir los tiempos de respuesta de las páginas de un sitio Flask SQLAlchemy web
- Usando Python's pyOpenSSL para verificar los certificados SSL descargados de un host
- Conectarse a un servicio en un host Docker desde un contenedor Docker
- Usando UUIDs en lugar de Integer Autoincrement Primary Keys con SQLAlchemy y MariaDb
- SQLAlchemy: Uso de Cascade Deletes para eliminar objetos relacionados