Recientemente me vi en la necesidad de utilizar una sola IP pública para varias VMs. La idea era ofrecer un servicio (OpenVPN en este caso) con fail over: tendría dos instancias de un mismo servicio, solamente una de ellas tendría asignada un IP público, pero si esa VM que tiene el IP público presenta algun problema (se apaga, pierde la red, etc) la otra asumiría el IP público y continuaría brindando el servicio.
En el escenario que mostraré tendré 3 VMs. Los detalles se muestran a continuación:
VM1 | VM1 | VM1 | |
---|---|---|---|
Hostname | KA1 | KA2 | KA3 |
OS | Ubuntu 20.04 | Ubuntu 20.04 | Ubuntu 20.04 |
CPU/MEM | 2vCPU/2GB | 2vCPU/2GB | 2vCPU/2GB |
enp0s3 (Clientes) | 192.168.43.101/24 | 192.168.43.102/24 | 192.168.43.103/24 |
enp0s8 (FloatingIP) | 192.168.1.11/24 | 192.168.1.11/24 | 192.168.1.11/24 |
enp0s9 (Managment) | 10.7.5.1/24 | 10.7.5.2/24 | 10.7.5.3/24 |
La interfaz
enp0s8
de cada una de las VMs sera la que recibirá el «IP público». En este caso, al ser un labarotorio utilizaré el IP 192.168.1.11/24 como «IP público»
El servicio que se utilizará para la configuración del FailOver será el KeepAlive utilizando el protocolo VRRP.
Luego del archiconocido apt update
y apt upgrade
de las VMs en donde vamos a trabajar lo primero será configurar las interfaces de red. Las interfaces enp0s3
y enp0s9
se utilizan para la conexión con los clientes y como red de managment respectivamente por lo que tendran un IP estático; mientras que la interfaz enp0s8
(como se mencionó anteriormente) será la que recibirá el FloatingIP de la «red pública», por lo que no se le asignará un IP, solamente se asegurará de que la interfaz está up.
A continuación se muestra el netplan de la primera VM (el resto es solo cambiar los IPs):
cat /etc/netplan/00-installer-config.yaml network: version: 2 renderer: networkd ethernets: enp0s3: addresses: - 192.168.43.101/24 nameservers: addresses: [192.168.43.1, 8.8.8.8] enp0s9: addresses: [10.7.5.1/24]
Si mostramos las interfaces con ip a
veremos que la interfaz enp0s8
esta DOWN:
ip a #[...] 3: enp0s8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 08:00:27:45:34:18 brd ff:ff:ff:ff:ff:ff #[...]
La «encederemos» (en cada VM) y comprobamos el estado de las mismas:
ip link set dev enp0s8 up && ip a show enp0s8 #[...] 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:e7:cd:c2 brd ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fee7:cdc2/64 scope link valid_lft forever preferred_lft forever
En todas las VMs:
apt install keepalived -y
Una vez instalado tendremos que crear el archivo: /etc/keepalived/keepalived.conf
en cada una de las VMs, y luego modificarlos a conveniencia. Intentaré explicar cada una de las opciones que he utilizado:
LB1:
cat > /etc/keepalived/keepalived.conf << EOF vrrp_instance KA1 { state MASTER interface enp0s9 virtual_router_id 182 priority 207 advert_int 1 #notify "/etc/keepalived/keepalived_failover.sh" authentication { auth_type PASS auth_pass YouWillLoveMyPinkGun } virtual_ipaddress { 192.168.43.100/24 dev enp0s3 192.168.1.11/24 dev enp0s8 } virtual_routes { default via 192.168.1.1/24 } } EOF
El servicio de keepalived es muy flexible a la hora de las configuraciones que nos permite hacer, pero voy a limitarme a lo que nos interesa de momento:
Una vez tengamos configurado el keepalived
a nuestro gusto podemos proceder a inicializar el servicio en la primera VM y checkear su estado:
systemctl start keepalived && systemctl status keepalived #[...] ● keepalived.service - Keepalive Daemon (LVS and VRRP) Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2022-07-13 16:54:06 UTC; 16s ago Main PID: 3844 (keepalived) Tasks: 2 (limit: 1066) Memory: 1.5M CGroup: /system.slice/keepalived.service ├─3844 /usr/sbin/keepalived --dont-fork └─3870 /usr/sbin/keepalived --dont-fork Jul 13 16:54:06 KA1 Keepalived_vrrp[3870]: Registering Kernel netlink reflector Jul 13 16:54:06 KA1 Keepalived_vrrp[3870]: Registering Kernel netlink command channel Jul 13 16:54:06 KA1 Keepalived_vrrp[3870]: Opening file '/etc/keepalived/keepalived.conf'. Jul 13 16:54:06 KA1 Keepalived_vrrp[3870]: (Line 11) Truncating auth_pass to 8 characters Jul 13 16:54:06 KA1 Keepalived_vrrp[3870]: Registering gratuitous ARP shared channel Jul 13 16:54:06 KA1 Keepalived_vrrp[3870]: (KA1) Entering BACKUP STATE (init) Jul 13 16:54:10 KA1 Keepalived_vrrp[3870]: (KA1) Entering MASTER STATE
Las interfaces que sean utilizadas por el servicio de
keepalived
tienen q estar en estado UP, sino el servicio dará error.Nótese que la contraseña es muy larga y será truncada a solamente 8 caracteres!
Ahora podremos comprobar los IPs de esta VM (actualmente en el estado Master del servicio):
ip a #[...] 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:3f:cf:a8 brd ff:ff:ff:ff:ff:ff inet 192.168.43.101/24 brd 192.168.43.255 scope global enp0s3 valid_lft forever preferred_lft forever inet 192.168.43.100/24 scope global secondary enp0s3 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe3f:cfa8/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:45:34:18 brd ff:ff:ff:ff:ff:ff inet 192.168.1.11/24 scope global enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe45:3418/64 scope link valid_lft forever preferred_lft forever 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:a9:7a:5d brd ff:ff:ff:ff:ff:ff inet 10.7.5.1/24 brd 10.7.5.255 scope global enp0s9 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fea9:7a5d/64 scope link valid_lft forever preferred_lft forever
Como se puede comprobar la interfaz enp0s3
tiene dos IPs asignados, mientras que la interfaz enp0s8
(la que fungiría como IP público) tiene su único IP asignado (FloatingIP).
Bien, procedamos entonces a configurar la VM2 (KA2):
cat > /etc/keepalived/keepalived.conf << EOF vrrp_instance KA1 { state MASTER interface enp0s9 virtual_router_id 182 priority 150 advert_int 1 #notify "/etc/keepalived/keepalived_failover.sh" authentication { auth_type PASS auth_pass YouWillLoveMyPinkGun } virtual_ipaddress { 192.168.43.100/24 dev enp0s3 192.168.1.11/24 dev enp0s8 } virtual_routes { default via 192.168.43.1/24 } } EOF
Nótese que la prioridad en este es más baja que en el caso de la VM1 (KA1)
Solo resta inicializar y comprobar el estado del servicio.
systemctl start keepalived && systemctl status keepalived #[...] ● keepalived.service - Keepalive Daemon (LVS and VRRP) Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2022-07-13 16:56:10 UTC; 2min 39s ago Main PID: 3113 (keepalived) Tasks: 2 (limit: 1066) Memory: 1.6M CGroup: /system.slice/keepalived.service ├─3113 /usr/sbin/keepalived --dont-fork └─3139 /usr/sbin/keepalived --dont-fork Jul 13 16:56:10 KA2 Keepalived[3113]: WARNING - keepalived was build for newer Linux 5.4.166, running on Linux 5.4.0-96-generic #109-Ubuntu SMP Wed Jan 12 16> Jul 13 16:56:10 KA2 Keepalived[3113]: Command line: '/usr/sbin/keepalived' '--dont-fork' Jul 13 16:56:10 KA2 Keepalived[3113]: Opening file '/etc/keepalived/keepalived.conf'. Jul 13 16:56:10 KA2 Keepalived[3113]: Starting VRRP child process, pid=3139 Jul 13 16:56:10 KA2 Keepalived_vrrp[3139]: Registering Kernel netlink reflector Jul 13 16:56:10 KA2 Keepalived_vrrp[3139]: Registering Kernel netlink command channel Jul 13 16:56:10 KA2 Keepalived_vrrp[3139]: Opening file '/etc/keepalived/keepalived.conf'. Jul 13 16:56:10 KA2 Keepalived_vrrp[3139]: (Line 11) Truncating auth_pass to 8 characters Jul 13 16:56:10 KA2 Keepalived_vrrp[3139]: Registering gratuitous ARP shared channel Jul 13 16:56:10 KA2 Keepalived_vrrp[3139]: (KA1) Entering BACKUP STATE (init)
Comprobemos el estado de los IPs:
ip a #[...] 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:b5:e3:b7 brd ff:ff:ff:ff:ff:ff inet 192.168.43.102/24 brd 192.168.43.255 scope global enp0s3 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:feb5:e3b7/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:e7:cd:c2 brd ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fee7:cdc2/64 scope link valid_lft forever preferred_lft forever 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:63:ea:59 brd ff:ff:ff:ff:ff:ff inet 10.7.5.2/24 brd 10.7.5.255 scope global enp0s9 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe63:ea59/64 scope link valid_lft forever preferred_lft forever
Como se puede apreciar la interfaz enp0s3
continúa con su único IP mientras que la interfaz enp0s3
no tiene ningun IP asignado.
Solamente queda configurar la ultima VM (KA3):
cat > /etc/keepalived/keepalived.conf << EOF vrrp_instance KA1 { state MASTER interface enp0s9 virtual_router_id 182 priority 100 advert_int 1 #notify /etc/keepalived/keepalived_failover.sh authentication { auth_type PASS auth_pass YouWillLoveMyPinkGun } virtual_ipaddress { 192.168.43.100/24 dev enp0s3 192.168.1.11/24 dev enp0s8 } virtual_routes { default via 192.168.43.1/24 } } EOF
Ahora, como en los anteriores casos, procedemos a inicializar el servicio y a checkearlo:
systemctl start keepalived && systemctl status keepalived #[...] ● keepalived.service - Keepalive Daemon (LVS and VRRP) Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2022-07-13 17:05:00 UTC; 21s ago Main PID: 2214 (keepalived) Tasks: 2 (limit: 1066) Memory: 1.5M CGroup: /system.slice/keepalived.service ├─2214 /usr/sbin/keepalived --dont-fork └─2226 /usr/sbin/keepalived --dont-fork Jul 13 17:05:00 KA3 Keepalived[2214]: Command line: '/usr/sbin/keepalived' '--dont-fork' Jul 13 17:05:00 KA3 Keepalived[2214]: Opening file '/etc/keepalived/keepalived.conf'. Jul 13 17:05:00 KA3 Keepalived[2214]: Starting VRRP child process, pid=2226 Jul 13 17:05:00 KA3 Keepalived_vrrp[2226]: Registering Kernel netlink reflector Jul 13 17:05:00 KA3 Keepalived_vrrp[2226]: Registering Kernel netlink command channel Jul 13 17:05:00 KA3 Keepalived_vrrp[2226]: Opening file '/etc/keepalived/keepalived.conf'. Jul 13 17:05:00 KA3 Keepalived_vrrp[2226]: (Line 11) Truncating auth_pass to 8 characters Jul 13 17:05:00 KA3 Keepalived_vrrp[2226]: Registering gratuitous ARP shared channel Jul 13 17:05:00 KA3 Keepalived_vrrp[2226]: (KA1) Entering BACKUP STATE (init)
Si checkeamos el estado de la interfaces y sus IPs asignados, podremos comprobar que ocurre lo mismo que con el caso de KA2.
Para comprobar que el servicio funciona simplemente apagaremos la interfaz de managmente enp0s9
de KA1. Recuerden q es esta la interfaz configurada para checkear.
ip link set dev enp0s9 down
Si ahora checkeamos el estado del servicio en KA1, y luego sus interfaces veremos los FloatingIP dejan de estar configurados:
systemctl status keepalived #[...] Jul 13 17:08:33 KA1 Keepalived_vrrp[3870]: Netlink reports enp0s9 down Jul 13 17:08:33 KA1 Keepalived_vrrp[3870]: (KA1) Entering FAULT STATE Jul 13 17:08:33 KA1 Keepalived_vrrp[3870]: (KA1) sent 0 priority
ip a #[...] 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:3f:cf:a8 brd ff:ff:ff:ff:ff:ff inet 192.168.43.101/24 brd 192.168.43.255 scope global enp0s3 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe3f:cfa8/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:45:34:18 brd ff:ff:ff:ff:ff:ff inet6 fe80::a00:27ff:fe45:3418/64 scope link valid_lft forever preferred_lft forever 4: enp0s9: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000 link/ether 08:00:27:a9:7a:5d brd ff:ff:ff:ff:ff:ff
Ahora, si checkeamos el estado de KA2 veremos como la interfaz enp0s3
asume el FloatingIP configurado, mientras que con la interfaz enp0s8
ocurre igual:
ip a #[...] 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:b5:e3:b7 brd ff:ff:ff:ff:ff:ff inet 192.168.43.102/24 brd 192.168.43.255 scope global enp0s3 valid_lft forever preferred_lft forever inet 192.168.43.100/24 scope global secondary enp0s3 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:feb5:e3b7/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:e7:cd:c2 brd ff:ff:ff:ff:ff:ff inet 192.168.1.11/24 scope global enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fee7:cdc2/64 scope link valid_lft forever preferred_lft forever 4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:63:ea:59 brd ff:ff:ff:ff:ff:ff inet 10.7.5.2/24 brd 10.7.5.255 scope global enp0s9 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe63:ea59/64 scope link valid_lft forever preferred_lft forever
Si checkeamos el estado del servicio en KA2:
systemctl status keepalived #[...] Jul 13 16:56:10 KA2 Keepalived_vrrp[3139]: (KA1) Entering BACKUP STATE (init) Jul 13 17:08:35 KA2 Keepalived_vrrp[3139]: (KA1) Entering MASTER STATE
Lo mismo ocurrirá en el caso si apagamos la interfaz de managment de KA2, KA3 asumirá el role de Master.
Si encendemos la interfaz de managment de KA1, veremos como enseguida asume el role de Master, pues tiene una prioridad mayor que KA2:
ip link set dev enp0s9 up && systemctl status keepalived #[...] ● keepalived.service - Keepalive Daemon (LVS and VRRP) Loaded: loaded (/lib/systemd/system/keepalived.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2022-07-13 16:54:06 UTC; 19min ago Main PID: 3844 (keepalived) Tasks: 2 (limit: 1066) Memory: 1.5M CGroup: /system.slice/keepalived.service ├─3844 /usr/sbin/keepalived --dont-fork └─3870 /usr/sbin/keepalived --dont-fork Jul 13 16:54:10 KA1 Keepalived_vrrp[3870]: (KA1) Entering MASTER STATE Jul 13 17:08:33 KA1 Keepalived_vrrp[3870]: Netlink reports enp0s9 down Jul 13 17:08:33 KA1 Keepalived_vrrp[3870]: (KA1) Entering FAULT STATE Jul 13 17:08:33 KA1 Keepalived_vrrp[3870]: (KA1) sent 0 priority Jul 13 17:13:29 KA1 Keepalived_vrrp[3870]: Netlink reports enp0s9 up Jul 13 17:13:29 KA1 Keepalived_vrrp[3870]: (KA1) Entering BACKUP STATE Jul 13 17:13:30 KA1 Keepalived_vrrp[3870]: (KA1) received lower priority (150) advert from 10.7.5.2 - discarding Jul 13 17:13:31 KA1 Keepalived_vrrp[3870]: (KA1) received lower priority (150) advert from 10.7.5.2 - discarding Jul 13 17:13:32 KA1 Keepalived_vrrp[3870]: (KA1) received lower priority (150) advert from 10.7.5.2 - discarding Jul 13 17:13:33 KA1 Keepalived_vrrp[3870]: (KA1) Entering MASTER STATE
En el archivo de configuración hay una opción llamada notify. Esta configuración nos permite correr un script cada vez que keepalive detecte un cambio en sus estados (por ejemplo: de Backup a Master).
cat /etc/keepalived/keepalived.conf #[...] advert_int 1 notify "/etc/keepalived/keepalived_failover.sh" authentication { auth_type PASS #[...]
Como mencioné al principio en mis VMs corre un servicio de OpenVPN al cual se conectaran clientes desde alguna red pública, pero no es necesario que el servicio esté habilitado en todo momento en todas las VMs, por lo tanto, crearemos un script que, en dependencia del estado del servicio de keepalived
iniciará o detendrá el servicio de OpenVPN:
cat > /etc/keepalived/keepalived.conf << EOF #!/bin/bash TYPE=$1 NAME=$2 STATE=$3 case $STATE in "MASTER") /bin/systemctl start openvpn@server /bin/ip r del default via 172.17.52.1 ;; "BACKUP") /bin/systemctl stop openvpn@server /bin/ip r add default via 172.17.52.1 ;; "STOP") /bin/systemctl stop openvpn@server /bin/ip r add default via 172.17.52.1 ;; "FAULT") /bin/systemctl stop openvpn@server /bin/ip r add default via 172.17.52.1 exit 0 ;; *) /usr/bin/logger "keepalived unknown state" exit 1 ;; esac echo "$1 $2 has transitioned to the $3 state with a priority of $4" >> /opt/k_logs/keepalived_status EOF
El notify
pasa 4 parámetros al script:
Si hace cualquier cambio en los archivos de configuración (descomentar la opcion del notify en este caso) del servicio
keepalived
recuerde reinicializar el servicio.
En el script, como parte del logueo, indiqué que en /opt/k_logs/keepalived_status
me muestre los cambios, si configuramos el script en KA1, apagamos e iniciamos la interfaz de managment y luego leemos el archivo de log veremos algo como:
cat /var/run/keepalived_status #[...] INSTANCE KA1 has transitioned to the FAULT state with a priority of 207 INSTANCE KA1 has transitioned to the BACKUP state with a priority of 207 INSTANCE KA1 has transitioned to the MASTER state with a priority of 207
Y de esta forma sencilla podemos controlar el servicio de OpenVPN en depedencia del estado del servicio de keepalived
+++++++++++++++++++++++++++++++++++++++++++++++++++
Autores:
Frank Morales
Franco Díaz
Me complace anunciar la creación de esta útil herramienta (SquidStats), para el análisis y monitoreo…
La inteligencia artificial está revolucionando las industrias al automatizar tareas, predecir patrones y permitiendo tomar…
Uno de los grandes retos al que nos podemos enfrentar cuando una aplicación crece, es…
Percona Monitoring and Management (PMM) es una herramienta de código abierto para la supervisión y…
Qué es lo que deseo hacer en este capítulo? Básicamente un sonoff, quiero encender/apagar las…
Hace algunos meses estoy escuchando hablar del proyecto Home Assistant (HA). En palabras literales del…