angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Utilización de IPv6 con Microk8s

Configurar Microk8s dual-stack es mucho más fácil de lo esperado.

3 diciembre 2024
post main image
https://www.pexels.com/@sedanur-kunuk-78972032

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

Deje un comentario

Comente de forma anónima o inicie sesión para comentar.

Comentarios

Deje una respuesta.

Responda de forma anónima o inicie sesión para responder.