Este artículo describe y demuestra NMState, un administrador de red que utiliza un enfoque declarativo para configurar hosts. Esto significa que define el estado de configuración deseado a través de una API y la herramienta aplica la configuración a través de un proveedor.
Enfoques de configuración: imperativo frente a declarativo
La gestión de redes puede ser una tarea muy compleja según el tamaño y la diversidad del entorno. En los primeros días de la TI, la administración de redes se basaba en procedimientos manuales realizados por administradores de redes a través de dispositivos de red. Hoy en día, la Infraestructura como Código (IaC) permite automatizar esas tareas de una manera diferente. Hay, esencialmente, dos enfoques: imperativo o declarativo.
En un enfoque imperativo, define “cómo” llegará al estado de configuración deseado. El paradigma declarativo define “cuál” es el estado de configuración deseado, por lo que no determina qué pasos se requieren ni en qué orden se deben realizar. Actualmente, este enfoque está reuniendo a más expertos y puede encontrarlo en la mayoría de las herramientas de administración y orquestación que se utilizan actualmente.
NMState: una herramienta declarativa
NMState es un administrador de red que le permite configurar hosts siguiendo un enfoque declarativo. Significa que define el estado de configuración deseado a través de una API declarativa hacia el norte y esta herramienta aplica la configuración a través de un proveedor hacia el sur.
Actualmente, el único proveedor admitido por NMState es NetworkManager, que es el servicio principal para abordar las capacidades de red en Fedora linux Sin embargo, el ciclo de vida de desarrollo de NMState agregará otros proveedores gradualmente.
Para obtener más información sobre NMState, visite su proyecto sitio o github repositorio .
Instalación
NMState está disponible en Fedora Linux 29+ y requiere NetworkManager 1.26 o posterior instalado y ejecutándose en el sistema. A continuación se muestra la instalación en Fedora linux34:
$ sudo dnf -y install nmstate … output omitted … Installed: NetworkManager-config-server-1:1.30.4-1.fc34.noarch gobject-introspection-1.68.0-3.fc34.x86_64 nispor-1.0.1-2.fc34.x86_64 nmstate-1.0.3-2.fc34.noarch python3-gobject-base-3.40.1-1.fc34.x86_64 python3-libnmstate-1.0.3-2.fc34.noarch python3-nispor-1.0.1-2.fc34.noarch python3-varlink-30.3.1-2.fc34.noarch Complete!
En este punto, puede usar nmstatectl como una herramienta de línea de comandos para NMState. Consulte nmstatectl –help o man nmstatectl para obtener más información sobre esta herramienta.
Uso de NMstate
Comience por verificar la versión de NMState instalada en el sistema:
$ nmstatectl version 1.0.3
Compruebe la configuración actual de una interfaz de red, por ejemplo, la configuración eth0:
$ nmstatectl show eth0 2021-06-29 10:28:21,530 root DEBUG NetworkManager version 1.30.4 2021-06-29 10:28:21,531 root DEBUG Async action: Retrieve applied config: ethernet eth0 started 2021-06-29 10:28:21,531 root DEBUG Async action: Retrieve applied config: ethernet eth1 started 2021-06-29 10:28:21,532 root DEBUG Async action: Retrieve applied config: ethernet eth0 finished 2021-06-29 10:28:21,533 root DEBUG Async action: Retrieve applied config: ethernet eth1 finished --- dns-resolver: config: {} running: search: [] server: - 192.168.122.1 route-rules: config: [] routes: config: [] running: - destination: fe80::/64 metric: 100 next-hop-address: '' next-hop-interface: eth0 table-id: 254 - destination: 0.0.0.0/0 metric: 100 next-hop-address: 192.168.122.1 next-hop-interface: eth0 table-id: 254 - destination: 192.168.122.0/24 metric: 100 next-hop-address: '' next-hop-interface: eth0 table-id: 254 interfaces: - name: eth0 type: ethernet state: up ipv4: enabled: true address: - ip: 192.168.122.238 prefix-length: 24 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true dhcp: true ipv6: enabled: true address: - ip: fe80::c3c9:c4f9:75b1:a570 prefix-length: 64 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true autoconf: true dhcp: true lldp: enabled: false mac-address: 52:54:00:91:E4:4E mtu: 1500
Como puede ver arriba, la configuración de red muestra cuatro secciones principales:
- dns-resolver : esta sección tiene la configuración del servidor de nombres para esta interfaz.
- reglas de ruta : establece las reglas de enrutamiento.
- rutas : incluye rutas tanto dinámicas como estáticas.
- Interfaces : esta sección describe la configuración de ipv4 e ipv6.
Modificar la configuración
Puede modificar el estado de configuración deseado en dos modos:
- Interactivo : editar la configuración de la interfaz a través de nmstatectl edit. Este comando invoca el editor de texto definido por la variable de entorno EDITOR para que el estado de la red se pueda editar en formato yaml. Después de terminar la edición, NMState aplicará la nueva configuración de red a menos que haya errores de sintaxis.
- basado en archivos : aplicar la configuración de la interfaz mediante nmstatectl apply, que importa un estado de configuración deseado desde un archivo yaml o json creado anteriormente.
Las siguientes secciones le muestran cómo cambiar la configuración de red usando NMState. Estos cambios pueden ser perjudiciales para el sistema, por lo que se recomienda realizar estas tareas en un sistema de prueba o en una máquina virtual invitada hasta que comprenda mejor NMState.
El sistema de prueba en uso aquí tiene dos interfaces Ethernet: eth0 y eth1:
$ ip -br -4 a lo UNKNOWN 127.0.0.1/8 eth0 UP 192.168.122.238/24 eth1 UP 192.168.122.108/24
Ejemplo de modo de configuración interactiva:
Change the MTU of eth0 interface to 9000 bytes using the nmstatectl edit command as follows (all changes are in bold):
$ sudo nmstatectl edit eth0 --- dns-resolver: config: {} running: search: [] server: - 192.168.122.1 route-rules: config: [] routes: config: [] running: - destination: fe80::/64 metric: 100 next-hop-address: '' next-hop-interface: eth0 table-id: 254 - destination: 0.0.0.0/0 metric: 100 next-hop-address: 192.168.122.1 next-hop-interface: eth0 table-id: 254 - destination: 192.168.122.0/24 metric: 100 next-hop-address: '' next-hop-interface: eth0 table-id: 254 interfaces: - name: eth0 type: ethernet state: up ipv4: enabled: true address: - ip: 192.168.122.123 prefix-length: 24 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true dhcp: true ipv6: enabled: true address: - ip: fe80::c3c9:c4f9:75b1:a570 prefix-length: 64 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true autoconf: true dhcp: true lldp: enabled: false mac-address: 52:54:00:91:E4:4E mtu: 9000
Después de guardar y salir de la edición, NMState aplica el nuevo estado deseado de la red:
2021-06-29 11:29:05,726 root DEBUG Nmstate version: 1.0.3 2021-06-29 11:29:05,726 root DEBUG Applying desire state: {'dns-resolver': {'config': {}, 'running': {'search': [], 'server': ['192.168.122.1']}}, 'route-rules': {'config': []}, 'routes': {'config': [], 'running': [{'destination': 'fe80::/64', 'metric': 102, 'next-hop-address': '', 'next-hop-interface': 'eth0', 'table-id': 254}, {'destination': '0.0.0.0/0', 'metric': 102, 'next-hop-address': '192.168.122.1', 'next-hop-interface': 'eth0', 'table-id': 254}, {'destination': '192.168.122.0/24', 'metric': 102, 'next-hop-address': '', 'next-hop-interface': 'eth0', 'table-id': 254}]}, 'interfaces': [{'name': 'eth0', 'type': 'ethernet', 'state': 'up', 'ipv4': {'enabled': True, 'address': [{'ip': '192.168.122.238', 'prefix-length': 24}], 'auto-dns': True, 'auto-gateway': True, 'auto-route-table-id': 0, 'auto-routes': True, 'dhcp': True}, 'ipv6': {'enabled': True, 'address': [{'ip': 'fe80::5054:ff:fe91:e44e', 'prefix-length': 64}], 'auto-dns': True, 'auto-gateway': True, 'auto-route-table-id': 0, 'auto-routes': True, 'autoconf': True, 'dhcp': True}, 'lldp': {'enabled': False}, 'mac-address': '52:54:00:91:E4:4E', 'mtu': 9000}]} --- output omitted --- 2021-06-29 11:29:05,760 root DEBUG Async action: Update profile uuid:2bdee700-f62b-365a-bd1d-69d9c31a9f0c iface:eth0 type:ethernet started 2021-06-29 11:29:05,792 root DEBUG Async action: Update profile uuid:2bdee700-f62b-365a-bd1d-69d9c31a9f0c iface:eth0 type:ethernet finished
Ahora, use el comando ip y también el archivo de configuración eth0 para verificar que la MTU de eth0 sea de 9000 bytes.
$ ip link show eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 52:54:00:91:e4:4e brd ff:ff:ff:ff:ff:ff altname enp1s0 $ sudo cat /etc/NetworkManager/system-connections/eth0.nmconnection [sudo] password for admin: [connection] id=eth0 uuid=2bdee700-f62b-365a-bd1d-69d9c31a9f0c type=ethernet interface-name=eth0 lldp=0 permissions= [ethernet] cloned-mac-address=52:54:00:91:E4:4E mac-address-blacklist= mtu=9000 [ipv4] dhcp-client-id=mac dhcp-timeout=2147483647 dns-search= method=auto [ipv6] addr-gen-mode=eui64 dhcp-duid=ll dhcp-iaid=mac dhcp-timeout=2147483647 dns-search= method=auto ra-timeout=2147483647 [proxy]
Ejemplo de modo de configuración basado en archivos:
Usemos el enfoque basado en archivos para establecer un nuevo estado de configuración. En este caso, deshabilite la configuración de IPv6 en la interfaz eth1.
Primero, cree un archivo yaml para definir el estado deseado de la interfaz eth1. Use nmstatectl show para guardar la configuración actual y luego nmstatectl edit para deshabilitar IPv6. Nuevamente, todos los cambios están en negrita y las eliminaciones se muestran tachadas:
$ nmstatectl show eth1 > eth1.yaml $ vi eth1.yaml --- dns-resolver: config: {} running: search: [] server: - 192.168.122.1 route-rules: config: [] routes: config: [] running: - destination: fe80::/64 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 - destination: 0.0.0.0/0 metric: 101 next-hop-address: 192.168.122.1 next-hop-interface: eth1 table-id: 254 - destination: 192.168.122.0/24 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 interfaces: - name: eth1 type: ethernet state: up ipv4: enabled: true address: - ip: 192.168.122.108 prefix-length: 24 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true dhcp: true ipv6: enabled: false address: - ip: fe80::5054:ff:fe3c:9b04 prefix-length: 64 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true autoconf: true dhcp: true lldp: enabled: false mac-address: 52:54:00:3C:9B:04 mtu: 1500
Después de guardar la nueva configuración, utilícela para aplicar el nuevo estado:
$ sudo nmstatectl apply eth1.yaml 2021-06-29 12:17:21,531 root DEBUG Nmstate version: 1.0.3 2021-06-29 12:17:21,531 root DEBUG Applying desire state: {'dns-resolver': {'config': {}, 'running': {'search': [], 'server': ['192.168.122.1']}}, 'route-rules': {'config': []}, 'routes': {'config': [], 'running': [{'destination': 'fe80::/64', 'metric': 101, 'next-hop-address': '', 'next-hop-interface': 'eth1', 'table-id': 254}, {'destination': '0.0.0.0/0', 'metric': 101, 'next-hop-address': '192.168.122.1', 'next-hop-interface': 'eth1', 'table-id': 254}, {'destination': '192.168.122.0/24', 'metric': 101, 'next-hop-address': '', 'next-hop-interface': 'eth1', 'table-id': 254}]}, 'interfaces': [{'name': 'eth1', 'type': 'ethernet', 'state': 'up', 'ipv4': {'enabled': True, 'address': [{'ip': '192.168.122.108', 'prefix-length': 24}], 'auto-dns': True, 'auto-gateway': True, 'auto-route-table-id': 0, 'auto-routes': True, 'dhcp': True}, 'ipv6': {'enabled': False}, 'lldp': {'enabled': False}, 'mac-address': '52:54:00:3C:9B:04', 'mtu': 1500}]} --- output omitted --- 2021-06-29 12:17:21,582 root DEBUG Async action: Update profile uuid:5d7244cb-673d-3b88-a675-32e31fad4347 iface:eth1 type:ethernet started 2021-06-29 12:17:21,587 root DEBUG Async action: Update profile uuid:5d7244cb-673d-3b88-a675-32e31fad4347 iface:eth1 type:ethernet finished --- output omitted --- Desired state applied: --- dns-resolver: config: {} running: search: [] server: - 192.168.122.1 route-rules: config: [] routes: config: [] running: - destination: fe80::/64 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 - destination: 0.0.0.0/0 metric: 101 next-hop-address: 192.168.122.1 next-hop-interface: eth1 table-id: 254 - destination: 192.168.122.0/24 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 interfaces: - name: eth1 type: ethernet state: up ipv4: enabled: true address: - ip: 192.168.122.108 prefix-length: 24 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true dhcp: true ipv6: enabled: false lldp: enabled: false mac-address: 52:54:00:3C:9B:04 mtu: 1500
Puedes comprobar que la interfaz eth1 no tiene configurado ningún IPv6:
$ ip -br a lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 192.168.122.238/24 fe80::5054:ff:fe91:e44e/64 eth1 UP 192.168.122.108/24 $ sudo cat /etc/NetworkManager/system-connections/eth1.nmconnection [connection] id=eth1 uuid=5d7244cb-673d-3b88-a675-32e31fad4347 type=ethernet interface-name=eth1 lldp=0 permissions= [ethernet] cloned-mac-address=52:54:00:3C:9B:04 mac-address-blacklist= mtu=1500 [ipv4] dhcp-client-id=mac dhcp-timeout=2147483647 dns-search= method=auto [ipv6] addr-gen-mode=eui64 dhcp-duid=ll dhcp-iaid=mac dns-search= method=disabled [proxy]
Aplicando cambios temporalmente
Una característica interesante de NMState le permite configurar temporalmente un estado de red deseado. En caso de que esté satisfecho con la configuración, puede enviarla después. De lo contrario, se revertirá cuando expire el tiempo de espera (el valor predeterminado es 60 segundos).
Modificar la configuración eth1 de la anterior example por lo que tiene una dirección estática IPv4 en lugar de obtenerla dinámicamente por DHCP.
$ vi eth1.yaml --- dns-resolver: config: {} running: search: [] server: - 192.168.122.1 route-rules: config: [] routes: config: [] running: - destination: fe80::/64 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 - destination: 0.0.0.0/0 metric: 101 next-hop-address: 192.168.122.1 next-hop-interface: eth1 table-id: 254 - destination: 192.168.122.0/24 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 interfaces: - name: eth1 type: ethernet state: up ipv4: enabled: true address: - ip: 192.168.122.110 prefix-length: 24 auto-dns: true auto-gateway: true auto-route-table-id: 0 auto-routes: true dhcp: false ipv6: enabled: false lldp: enabled: false mac-address: 52:54:00:3C:9B:04 mtu: 1500
Ahora, aplique esta configuración temporalmente usando la opción sin compromiso para que sea válida solo por 30 segundos. Esto se puede hacer agregando la opción –timeout. Mientras tanto, ejecutaremos el comando ip -br a tres veces para ver cómo cambia la dirección IPv4 configurada en la interfaz eth1 y luego se revierte la configuración.
$ ip -br a && sudo nmstatectl apply --no-commit --timeout 30 eth1.yaml && sleep 10 && ip -br a && sleep 25 && ip -br a lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 192.168.122.238/24 fe80::5054:ff:fe91:e44e/64 eth1 UP 192.168.122.108/24 2021-06-29 17:29:18,266 root DEBUG Nmstate version: 1.0.3 2021-06-29 17:29:18,267 root DEBUG Applying desire state: {'dns-resolver': {'config': {}, 'running': {'search': [], 'server': ['192.168.122.1']}}, 'route-rules': {'config': []}, 'routes': {'config': [], 'running': [{'destination': 'fe80::/64', 'metric': 101, 'next-hop-address': '', 'next-hop-interface': 'eth1', 'table-id': 254}, {'destination': '0.0.0.0/0', 'metric': 101, 'next-hop-address': '192.168.122.1', 'next-hop-interface': 'eth1', 'table-id': 254}, {'destination': '192.168.122.0/24', 'metric': 101, 'next-hop-address': '', 'next-hop-interface': 'eth1', 'table-id': 254}]}, 'interfaces': [{'name': 'eth1', 'type': 'ethernet', 'state': 'up', 'ipv4': {'enabled': True, 'address': [{'ip': '192.168.122.110', 'prefix-length': 24}], 'dhcp': False}, 'ipv6': {'enabled': False}, 'lldp': {'enabled': False}, 'mac-address': '52:54:00:3C:9B:04', 'mtu': 1500}]} --- output omitted --- Desired state applied: --- dns-resolver: config: {} running: search: [] server: - 192.168.122.1 route-rules: config: [] routes: config: [] running: - destination: fe80::/64 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 - destination: 0.0.0.0/0 metric: 101 next-hop-address: 192.168.122.1 next-hop-interface: eth1 table-id: 254 - destination: 192.168.122.0/24 metric: 101 next-hop-address: '' next-hop-interface: eth1 table-id: 254 interfaces: - name: eth1 type: ethernet state: up ipv4: enabled: true address: - ip: 192.168.122.110 prefix-length: 24 dhcp: false ipv6: enabled: false lldp: enabled: false mac-address: 52:54:00:3C:9B:04 mtu: 1500 Checkpoint: NetworkManager|/org/freedesktop/NetworkManager/Checkpoint/7 lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 192.168.122.238/24 fe80::5054:ff:fe91:e44e/64 eth1 UP 192.168.122.110/24 lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 192.168.122.238/24 fe80::5054:ff:fe91:e44e/64 eth1 UP 192.168.122.108/24
Como puede ver arriba, la dirección IP de eth1 cambió temporalmente de 192.168.122.108 a 192.168.122.110 y luego volvió a 192.168.122.108 después de que expiró el tiempo de espera.
Conclusión
NMState es una herramienta de configuración de red declarativa que actualmente aplica el estado de configuración de red deseado en un host a través de la API NetworkManager. Este estado se puede definir de forma interactiva con un editor de texto o con un enfoque basado en archivos creando un archivo yaml o json.
Este tipo de herramienta proporciona Infraestructura como código, permite la automatización de tareas de red y también reduce posibles errores de configuración o escenarios de red inestables que podrían surgir al usar métodos de configuración heredados.