Escenario 2B. LXC: perfís, redes e control de recursos

De MediaWiki
Ir a la navegación Ir a la búsqueda

Introdución

Montaremos a infraestrutura da figura con contedores e ó longo do proceso aprenderemos a:

  • Crear e asignar perfís (profiles) ós contedores para aplicar configuracións 'hardware' específicas ós nosos contedores.
  • Coñecer o funcionamento da interface incusbr0 creada na inicialización.
  • Crear e configurar redes para situar os contedores nelas. Coñeceremos outros modos de rede e como facer accesibles os servizos correndo nos contedores dende fóra do anfitrión.
  • Establecer límites de cpu, RAM e disco ós contedores para controlar o uso dos recursos do equipo anfitrión.

Esquema de rede do escenario 2B:


Preparación da máquina Incus: Para abordar este escenario usaremos a máquina Incus ó remate do Escenario 2A - Contedores LXC. No meu caso tiña uns contedores Ubuntu xa creados, pero non hai problema con que sexa diferente xa que crearemos todo o que precisamos para implantar esta infraestrutura.

Perfíl por defecto

Os profiles ou perfís permiten de xeito 'centralizado' definir a configuración e os dispositivos dun contedor para así poder aplicalo a todos os contedores que o precisen. Por exemplo, podemos crear un perfil onde está imposto un uso máximo de 256 MB de memoria e 1 cpu. Este perfil podemos aplicalo a todos aqueles contedores ós que queiramos aplicar esta restricción. Do mesmo xeito, podemos ter un perfil onde indicamos que haberá dúas interfaces de rede (p.e. unha con conexión á rede local e outra conectada a unha rede interna/ privada) e aplicalo a todos aqueles contedores que o precisen. Podemos crear varios perfís e aplicarllos a un contedor; deste xeito, cando se cree a configuración final do contedor os perfís aplicaranse na orde na que foron indicados (sobreescribindo a configuración anterior no caso de haber coincidencias).

Podemos ver os perfís dispoñibles executando o comando incus profile list e tamén modificar o comando incus list para ver directamente que perfís están a usar os contedores (executar incus list -h para ver todas as posibilidades):

~$ incus profile list 
+---------+-----------------------+---------+
|  NAME   |      DESCRIPCIÓN      | USED BY |
+---------+-----------------------+---------+
| default | Default Incus profile | 0       |
+---------+-----------------------+---------+

Para ver as características do perfil e os contedores que o utilizan executamos o comando lxc profile show <nome_perfil>:

~$ incus profile show default 
config: {}
description: Default Incus profile
devices:
  eth0:
    name: eth0
    network: incusbr0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: default
used_by: []
project: default

Ó instalar incus créase un perfil chamado default que correspóndese cun contedor cun disco duro e unha interface de rede conectada ó dispositivo incusbr0.

Ó longo deste escenario traballaremos cos perfís, creando, editando as súas características, asignando, etc.; pero de momento, se queremos ver todas as operacións posibles sobe os perfís podemos executar:

~$ incus profile 
Usage:
  incus profile [flags]
  incus profile [command]

Available Commands:
  add         Add profiles to instances
  assign      Assign sets of profiles to instances
  copy        Copy profiles
  create      Create profiles
  delete      Delete profiles
  device      Manage devices
  edit        Edit profile configurations as YAML
  get         Get values for profile configuration keys
  list        List profiles
  remove      Remove profiles from instances
  rename      Rename profiles
  set         Set profile configuration keys
  show        Show profile configurations
  unset       Unset profile configuration keys

Global Flags:
      --debug          Show all debug messages
      --force-local    Force using the local unix socket
  -h, --help           Print help
      --project        Override the source project
  -q, --quiet          Don't show progress information
      --sub-commands   Use with help or --help to view sub-commands
  -v, --verbose        Show all information messages
      --version        Print version number

Use "incus profile [command] --help" for more information about a command.

Interfaz incusbr0

Ó traballar con contedores LXC/Incus podemos crear configuracións de rede semellantes ás que ofrecen solucións de virtualización como Virtualbox. A xestión das redes pode facerse a través da configuración de rede do sistema operativo ou ben directamente a través de Incus. Ó longo do curso ensinarei a facelo das dúas formas, para que escollades a que mellor se adapta á vosa forma de traballar co alumnado.

No momento de facer o incus init creamos unha nova interface de rede incusbr0 que proporciona funcionalidades semellantes ás que ofrece o modo rede NAT en Virtualbox xa que:

Os contedores reciben por dhcp unha configuración válida para unha rede privada 10.103.214.0/24 (esta é a rede creada no meu equipo e seguramente sexa diferente no voso). Os contedores conectados a ela poden comunicarse entre si. É dicir, funciona como se fose un conmutador/switch para eles. Os contedores conectados a ela poden saír ó exterior. É dicir, funciona como se fose un router-nat, traducindo os enderezos IP privados pola IP real do equipo anfitrión. Automáticamente creáronse regras de filtrado e NAT no equipo anfitrión durante a inicialización de incus. O equipo anfitrión pode comunicarse cos contedores a través dos enderezos da rede interna (no meu exemplo, a rede 10.103.214.0/24) e viceversa. No meu caso o equipo anfitrión recibiu a IP 10.103.214.1 e a través desta IP pode falar directamente cos contedores conectados á rede incusbr0 10.103.214.1/24. Dende fóra do equipo anfitrión non se poden iniciar comunicacións directas hacia os servizos correndo nos contedores; polo tanto, habería que crear regras de filtrado e NAT para permitilo ou crear a través de incus un dispositivo tipo proxy asociado ó contedor. No meu equipo de probas hai dous contedores usando o perfil por defecto que emprega incusbr0 como tarxeta de rede:

asir@incus:~$ incus list -c n,4,s,P,S,l +-----------+----------------------+---------+----------+-----------+----------------------+ | NAME | IPV4 | STATE | PROFILES | SNAPSHOTS | LAST USED AT | +-----------+----------------------+---------+----------+-----------+----------------------+ | platega00 | 10.103.214.4 (eth0) | RUNNING | default | 0 | 2026/01/17 13:08 CET | +-----------+----------------------+---------+----------+-----------+----------------------+ | platega01 | 10.103.214.70 (eth0) | RUNNING | default | 0 | 2026/01/17 13:08 CET | +-----------+----------------------+---------+----------+-----------+----------------------+ asir@incus:~$ incus profile show default config: {} description: Default Incus profile devices:

 eth0:
   name: eth0
   network: incusbr0
   type: nic
 root:
   path: /
   pool: default
   type: disk

name: default used_by: - /1.0/instances/platega00 - /1.0/instances/platega01 project: default asir@incus:~$ ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host noprefixroute 
      valid_lft forever preferred_lft forever

2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000

   link/ether 08:00:27:ea:0d:42 brd ff:ff:ff:ff:ff:ff
   inet 192.168.1.40/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s3
      valid_lft 29661sec preferred_lft 29661sec
   inet6 fe80::e492:220c:7e0f:c8b8/64 scope link noprefixroute 
      valid_lft forever preferred_lft forever

3: incusbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000

   link/ether 10:66:6a:73:84:27 brd ff:ff:ff:ff:ff:ff
   inet 10.103.214.1/24 brd 10.103.214.255 scope global incusbr0
      valid_lft forever preferred_lft forever
   inet6 fd42:5fbb:5bb1:46a5::1/64 scope global 
      valid_lft forever preferred_lft forever
   inet6 fe80::1266:6aff:fe73:8427/64 scope link 
      valid_lft forever preferred_lft forever

... Gráficamente a rede incusbr0 podería entenderse como:

Interfaz lxdbr0

Fig. Rede en Incus - interfaz incusbr0

Acceso a un servizo correndo nun contedor mediante netfilter/iptables

Os servizos correndo nun contedor son directamente accesibles dende o equipo anfitrión grazas ó dispositivo incusbr0; sen embargo, se desexamos facer accesible algún servizo dos contedores dende o exterior hai que facer DNAT. Por exemplo, os contenedores ó crealos xa veñen co servidor openssh-server instalado e para permitir o acceso por ssh ó contenedor platega00 que ten a IP 10.122.236.9 a través da IP do 'equipo real' polo porto tcp/22000:

~$ sudo iptables -t nat -A PREROUTING -p tcp -i enp0s3 --dport 22000 -j DNAT --to 10.103.214.4:22

Accedendo dende un equipo externo á IP do equipo anfitrión porto 22000/tcp poderíamos abrir unha sesión ssh en platega00 (previamente habería que poñer un contrasinal ó usuario ubuntu e habilitar o acceso por ssh mediante contrasinal como se indicou no apartado 2.4 do tema):

$ ssh ubuntu@192.168.1.150 -p 22000
The authenticity of host '[192.168.1.150]:22000 ([192.168.1.150]:22000)' can't be established.
...
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 6.14.0-37-generic x86_64)
...

Acceso a un servizo correndo nun contedor mediante un dispositivo proxy

Pódese asociar a un contedor un dispositivo de tipo proxy que faga o traballo das regras NAT vistas no punto anterior. A modo de exemplo, faremos que un servidor web correndo en platega00 sexa accesible dende calquera ordenador a través da IP do equipo real:

En platega00 instalamos o servidor Apache:

~$ incus exec platega00 bash
~# apt update
~# apt install apache2 net-tools
~# netstat -putan
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      190/systemd-resolve 
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      235/sshd            
tcp6       0       0 :::80                    :::*                     LISTEN      1742/apache2     
...

No equipo real creamos un dispositivo de tipo proxy que mapeamos ó porto 80 do contedor:

~$ incus config device add platega00 apache proxy listen=tcp:0.0.0.0:80 connect=tcp:127.0.0.1:80
Device apache added to platega00
asir@incus:~$ incus config show platega00
architecture: x86_64
config:
  image.architecture: amd64
  image.description: Ubuntu jammy amd64 (20260116_07:42)
  image.os: Ubuntu
  image.release: jammy
  image.serial: "20260116_07:42"
  image.type: squashfs
  image.variant: default
  volatile.base_image: fc7f50dfa54d2b78a38ecf381aae912cbac338be01ff08c3c1c61cc74c502aad
  volatile.cloud-init.instance-id: 240792e5-4b41-4f9d-8dcc-9f5de51fba06
  volatile.eth0.host_name: veth7dfe3eb5
  volatile.eth0.hwaddr: 10:66:6a:a2:d9:0b
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.idmap: '[]'
  volatile.last_state.power: RUNNING
  volatile.uuid: 5254a789-4f45-4411-873c-f8b0a524b1db
  volatile.uuid.generation: 5254a789-4f45-4411-873c-f8b0a524b1db
devices:
  apache:
    connect: tcp:127.0.0.1:80
    listen: tcp:0.0.0.0:80
    type: proxy
ephemeral: false
profiles:
- default
stateful: false
description: ""

Atacando a IP do equipo real porto tcp/80 poderemos acceder ó servidor Apache correndo no contedor:

Accedendo ó servidor Apache a través do dispositivo proxy

Fig. Accedendo ó servidor apache grazas o dispositivo proxy

A rede incusbr0 e o seu modo de funcionamento; aínda que é práctico, noutras ocasións non é o que precisamos. Non hai problema xa que LXC/Incus soportan diversos modos de funcionamento de rede, semellantes o modo ponte e rede interna de Virtualbox .

Redes en Incus

Vou plantexar a solución que empregaría nas miñas clases e que permite que todo o alumnado traballe coas mesmas direccións IPs facilitando as explicacións do profesorado e o seguimento por parte do alumnado. Básicamente construirase a infraestrutura da figura no noso equipo anfitrión de forma illada, e deste xeito non haberá interferencias coas do resto do alumnado. Centrándonos no noso escenario vemos que precisamos dúas redes:

Unha que da servizo ós servidores web01, web02, web03 e a unha interface de rede do contedor chamado HAProxy. Unha que da servizo á outra interface de HAProxy e que consideraremos como interface externa ou pública. Escenario 2B. LXD

Fig. Esquema de rede do Escenario 2B.

Para ver as redes ou dispositivos de rede ós que conectar os contedores executamos o comando incus network list

~$ incus network list 
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
|   NAME   |   TYPE   | MANAGED |      IPV4       |           IPV6            | DESCRIPCIÓN | USED BY |  STATE  |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| enp0s3   | physical | NO      |                 |                           |             | 0       |         |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| incusbr0 | bridge   | YES     | 10.103.214.1/24 | fd42:5fbb:5bb1:46a5::1/64 |             | 3       | CREATED |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| lo       | loopback | NO      |                 |                           |             | 0       |         |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+

No meu caso teño á miña disposición dous interfaces:

enp0s3: interface de rede real que conecta ó equipo á rede local (e que podería usarse para traballar en modo macvlan ou physical). incusbr0: xa falamos dela e ademais de interface de rede temos que vela como unha rede tipo rede NAT (fixarse en que aparece como bridge no tipo de rede). Comezamos creando unha nova interface/rede para simular á rede externa da figura usando o comando incus network create:

~$ incus network create wan ipv4.address=192.0.2.1/24 ipv6.address=none ipv4.dhcp=true ipv4.dhcp.ranges="192.0.2.100-192.0.2.150" ipv4.firewall=true ipv4.nat=true
Network wan created
~$ incus network list
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
|   NAME   |   TYPE   | MANAGED |      IPV4       |           IPV6            | DESCRIPCIÓN | USED BY |  STATE  |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| enp0s3   | physical | NO      |                 |                           |             | 0       |         |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| incusbr0 | bridge   | YES     | 10.103.214.1/24 | fd42:5fbb:5bb1:46a5::1/64 |             | 3       | CREATED |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| lo       | loopback | NO      |                 |                           |             | 0       |         |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| wan      | bridge   | YES     | 192.0.2.1/24    | none                      |             | 0       | CREATED |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
~$ incus network show wan 
config:
  ipv4.address: 192.0.2.1/24
  ipv4.dhcp: "true"
  ipv4.dhcp.ranges: 192.0.2.100-192.0.2.150
  ipv4.firewall: "true"
  ipv4.nat: "true"
  ipv6.address: none
description: ""
name: wan
type: bridge
used_by: []
managed: true
status: Created
locations:
- none
project: default

Por suposto podemos usar a rede incusbr0 como rede externa pero a modo de exemplo creo unha nova (o alumnado faría o mesmo). A rede ten as seguintes características:

Nome wan e de tipo bridge (todos os contedores situados nela poderán comunicarse entre sí e co anfitrión). Asociada a unha nova interface no equipo anfitrión chamada wan coa IP 192.0.2.1 e máscara /24. Sen IPv6 asignada. Cun servidor dhcp e dns correndo para dar ese servizo ós contedores conectados a ela que así o requiran. As IPs reservas para otorgar por dhcp van da 192.0.2.100 ata a 192.0.2.150 (queda ó voso criterio seleccionar o rango que desexedes). Creáronse as regras iptables/netfilter de filtrado e NAT necesarias para funcionar o servizo dhcp/dns e permitir a saída ó exterior ós contedores conectados a esta rede. Na sección network da documentación de Incus pódense atopar todos os parámetros de configuración: https://linuxcontainers.org/incus/docs/main/howto/network_create/

NOTA

Ó longo do curso empregarei nos exemplos direccións de rede privada:

  • Clase A: 10.0.0.0/8
  • Clase B: de 172.16.0.0 a 172.31.0.0 /16
  • Clase C: de 192.168.0.0 a 192.168.0.255 /24

E direccións de rede reservadas para documentación:

  • 192.0.2.0/24 test-net-1
  • 198.51.100.0/24 test-net-2
  • 203.0.113.0/24 test-net-3

Ó longo do curso traballaremos coas seguintes redes:

  • wan --> 192.0.2.0/24 servirá para simular direccións IP públicas
  • dmz --> 172.16.0.0/16
  • lan --> 192.168.100.0/24

Repetimos o proceso para crear a rede DMZ pero neste caso sen crear regras NAT. Creamos a rede sen NAT a modo de exemplo e por que usaremos esta rede en escenarios onde os equipos situados nela usarán outras máquinas a modo de router para saír a Internet. En calquera momento podemos editar as características da rede e activar o NAT usando o comando incus network edit <nome_da_rede>:

NOTA: se no voso centro/casa estades a empregar a rede 172.16.0.0/16 creade outra rede diferente para non deixar inaccesibles ós equipos da rede 172.16 do centro/casa dende o equipo anfitrión dos contedores

~$ incus network create dmz ipv4.address=172.16.0.1/16 ipv6.address=none ipv4.dhcp=true ipv4.dhcp.ranges="172.16.0.100-172.16.0.150" ipv4.firewall=true ipv4.nat=false
Network dmz created
~$ incus network list
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
|   NAME   |   TYPE   | MANAGED |      IPV4       |           IPV6            | DESCRIPCIÓN | USED BY |  STATE  |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| dmz      | bridge   | YES     | 172.16.0.1/16   | none                      |             | 0       | CREATED |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| enp0s3   | physical | NO      |                 |                           |             | 0       |         |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| incusbr0 | bridge   | YES     | 10.103.214.1/24 | fd42:5fbb:5bb1:46a5::1/64 |             | 3       | CREATED |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| lo       | loopback | NO      |                 |                           |             | 0       |         |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
| wan      | bridge   | YES     | 192.0.2.1/24    | none                      |             | 0       | CREATED |
+----------+----------+---------+-----------------+---------------------------+-------------+---------+---------+
~$ incus network show dmz
config:
  ipv4.address: 172.16.0.1/16
  ipv4.dhcp: "true"
  ipv4.dhcp.ranges: 172.16.0.100-172.16.0.150
  ipv4.firewall: "true"
  ipv4.nat: "false"
  ipv6.address: none
description: ""
name: dmz
type: bridge
used_by: []
managed: true
status: Created
locations:
- none
project: default

A nova rede ten as seguintes características:

  • Nome dmz e de tipo bridge (todos os contedores situados nela poderán comunicarse entre si e co anfitrión).
  • Asociada a unha nova interface no equipo anfitrión chamada dmz e coa IP 172.16.0.1 con máscara /16.
  • Sen IPv6 asignada.
  • Cun servidor dhcp e dns correndo para dar ese servizo ós contedores conectados a ela que así o requiran. As IPs reservas para otorgar por dhcp van da 172.16.0.100 ata a 172.16.0.150.
  • Creáronse as regras iptables/netfilter de filtrado para funcionar o servizo dhcp/dns
  • Non se crearon regras NAT; de xeito que de querer ter saída ó exterior dos contedores conectados a esta rede, haberá que proporcionarlles outra forma (p.e. un contedor que funcione coma un router-nat).

Aínda que non é necesaria para este escenario, crearemos unha nova rede lan para temas posteriores:

~$ incus network create lan ipv4.address=192.168.100.1/24 ipv6.address=none ipv4.dhcp=true ipv4.dhcp.ranges="192.168.100.100-192.168.100.150" ipv4.firewall=true ipv4.nat=true
Network lan created
~$ incus network show lan
config:
  ipv4.address: 192.168.100.1/24
  ipv4.dhcp: "true"
  ipv4.dhcp.ranges: 192.168.100.100-192.168.100.150
  ipv4.firewall: "true"
  ipv4.nat: "true"
  ipv6.address: none
description: ""
name: lan
type: bridge
used_by: []
managed: true
status: Created
locations:
- none
project: default

Se facemos un ip addr aparecerán as novas interfaces asociadas ás redes creadas (se temos arrincados contedores aparecerán outras interfaces de nome vethXXXX que se corresponden con dispositivos de rede efímeros asociados ós contedores e que permiten as súas comunicacións):

~$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute 
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:ea:0d:42 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.40/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s3
       valid_lft 40427sec preferred_lft 40427sec
    inet6 fe80::e492:220c:7e0f:c8b8/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: incusbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:73:84:27 brd ff:ff:ff:ff:ff:ff
    inet 10.103.214.1/24 brd 10.103.214.255 scope global incusbr0
       valid_lft forever preferred_lft forever
    inet6 fd42:5fbb:5bb1:46a5::1/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::1266:6aff:fe73:8427/64 scope link 
       valid_lft forever preferred_lft forever
...
56: wan: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 10:66:6a:fc:79:9e brd ff:ff:ff:ff:ff:ff
    inet 192.0.2.1/24 brd 192.0.2.255 scope global wan
       valid_lft forever preferred_lft forever
57: dmz: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 10:66:6a:61:11:17 brd ff:ff:ff:ff:ff:ff
    inet 172.16.0.1/16 brd 172.16.255.255 scope global dmz
       valid_lft forever preferred_lft forever
58: lan: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 10:66:6a:cc:cf:c3 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.1/24 brd 192.168.100.255 scope global lan
       valid_lft forever preferred_lft forever

Outros comandos interesantes para traballar con redes en Incus son:

  • incus network create <nome_da_rede> --> crea unha nova rede encargándose Incus de asignarlle unha IP ó chou e as características por defecto.
  • incus network edit <nome_da_rede> --> abrirase un editor permitido editar as características da rede.
~$ incus network edit lan
### This is a YAML representation of the network.
### Any line starting with a '# will be ignored.
###
### A network consists of a set of configuration items.
###
### An example would look like:
### name: mybr0
### config:
###   ipv4.address: 10.62.42.1/24
###   ipv4.nat: true
###   ipv6.address: fd00:56ad:9f7a:9800::1/64
###   ipv6.nat: true
### managed: true
### type: bridge
###
### Note that only the configuration can be changed.

config:
  ipv4.address: 192.168.100.1/24
  ipv4.dhcp: "true"
  ipv4.dhcp.ranges: 192.168.100.100-192.168.100.150
  ipv4.firewall: "true"
  ipv4.nat: "true"
  ipv6.address: none
description: ""
name: lan
type: bridge
used_by: []
managed: true
status: Created
locations:
- none
project: default
incus network delete <nome_da_rede> --> para borrar unha rede.

Con incus network podemos ver todas as opcións:

~$ incus network 
Usage:
  incus network [flags]
  incus network [command]

Available Commands:
  acl              Manage network ACLs
  attach           Attach network interfaces to instances
  attach-profile   Attach network interfaces to profiles
  create           Create new networks
  delete           Delete networks
  detach           Detach network interfaces from instances
  detach-profile   Detach network interfaces from profiles
  edit             Edit network configurations as YAML
  forward          Manage network forwards
  get              Get values for network configuration keys
  info             Get runtime information on networks
  integration      Manage network integrations
  list             List available networks
  list-allocations List network allocations in use
  list-leases      List DHCP leases
  load-balancer    Manage network load balancers
  peer             Manage network peerings
  rename           Rename networks
  set              Set network configuration keys
  show             Show network configurations
  unset            Unset network configuration keys
  zone             Manage network zones

Global Flags:
      --debug          Show all debug messages
      --force-local    Force using the local unix socket
  -h, --help           Print help
      --project        Override the source project
  -q, --quiet          Don't show progress information
      --sub-commands   Use with help or --help to view sub-commands
  -v, --verbose        Show all information messages
      --version        Print version number

Use "incus network [command] --help" for more information about a command.

Ahora que xa están creadas as redes para a nosa infraestrutura procederemos a crear uns perfís para poder indicarlle ós contedores que as usen.

Perfís e creación de contedores

Imos crear un profile que usaremos cos contedores da rede DMZ que ten que posuír unha interface de rede conectada á rede DMZ. A forma máis sinxela é partir dun perfil xa creado e modificalo para adaptalo ás nosas necesidades.

NOTA: o formato dos profiles está na linguaxe YAML polo que os espazos en branco que se ven son espazos en branco e non tabuladores.

~$ incus profile copy default dmz
~$ incus profile edit dmz
### This is a YAML representation of the profile.
### Any line starting with a '# will be ignored.
###
### A profile consists of a set of configuration items followed by a set of
### devices.
###
### An example would look like:
### name: onenic
### config:
###   raw.lxc: lxc.aa_profile=unconfined
### devices:
###   eth0:
###     nictype: bridged
###     parent: mybr0
###     type: nic
###
### Note that the name is shown but cannot be changed

config: {}
description: perfil DMZ
devices:
  eth0:
    name: eth0
    network: dmz
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: dmz
used_by: []
project: default

Como pode verse modificamos o parámetro network que serve para indicar cal das interfaces de rede do anfitrión vai estar ligada á interface virtual do contedor. Neste perfil queremos que a tarxeta de rede do contedor esté conectada á dmz e non a incusbr0.

Repetimos o proceso para crear un novo perfil que neste caso terá dúas tarxetas de rede, unha conectada á rede externa (rede wan xestionada por incus) e outra á rede DMZ (rede dmz xestionada por incusXD):

~$ incus profile copy default 2NICs
~$ incus profile edit 2NICs
### This is a YAML representation of the profile.
### Any line starting with a '# will be ignored.
###
### A profile consists of a set of configuration items followed by a set of
### devices.
###
### An example would look like:
### name: onenic
### config:
###   raw.lxc: lxc.aa_profile=unconfined
### devices:
###   eth0:
###     nictype: bridged
###     parent: mybr0
###     type: nic
###
### Note that the name is shown but cannot be changed

config: {}
description: perfil WAN-DMZ
devices:
  eth0:
    name: eth0
    network: wan
    type: nic
  eth1:
    name: eth1
    network: dmz
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: 2NICs
used_by: []
project: default

Neste caso os contedores que usen este perfil terán dúas tarxetas de rede (eth0 e eth1), a primeira conectada á rede externa (network: wan) e a segunda conectadas á rede DMZ (network: dmz).

Creadas as redes e listos os perfís, o único que falta é crear os contedores aplicándolles o perfil axeitado.

Contedor HAProxy con Ubuntu 22.04

Comezamos co equipo HAProxy que debe usar o perfil 2NICs:

~$ incus launch images:ubuntu/jammy haproxy -p 2NICs
Launching haproxy
~$ incus list -c n,4,s,P,S,l
+-----------+----------------------+---------+----------+-----------+----------------------+
|   NAME    |         IPV4         |  STATE  | PROFILES | SNAPSHOTS |     LAST USED AT     |
+-----------+----------------------+---------+----------+-----------+----------------------+
| haproxy   | 192.0.2.132 (eth0)   | RUNNING | 2NICs    | 0         | 2026/01/17 16:21 CET |
+-----------+----------------------+---------+----------+-----------+----------------------+
Creamos os contedores web executando o comando: incus launch images:ubuntu/jammy <nome_contedor> -p dmz. Podemos axilizar a creación cun bucle for:

~$ for i in {1..3}; do incus launch images:ubuntu/jammy web0$i -p dmz ; done
Launching web01
Launching web02
Launching web03
~$ incus list -c n,4,s,P,S,l
+---------+---------------------+---------+----------+-----------+----------------------+
|  NAME   |        IPV4         |  STATE  | PROFILES | SNAPSHOTS |     LAST USED AT     |
+---------+---------------------+---------+----------+-----------+----------------------+
| haproxy | 192.0.2.132 (eth0)  | RUNNING | 2NICs    | 0         | 2026/01/17 16:21 CET |
+---------+---------------------+---------+----------+-----------+----------------------+
| web01   | 172.16.0.142 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+
| web02   | 172.16.0.149 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+
| web03   | 172.16.0.138 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+

Mirando a saída anterior vemos que os contedores web01, web02 e web03 colleron por dhcp unha configuración de rede da rede DMZ (172.16.0.1/16) e a interface eth0 de haproxy unha IP da rede WAN (192.0.2.1/24).

Aínda que pola saída do incus list parece que haproxy ten unha única tarxeta de rede. A verdade é que ten dúas pero eth1 non aparece no arquivo de configuración da rede do contedor, e polo tanto non está configurada:

~$ incus exec haproxy -- ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
59: eth0@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:a6:42:1f brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.0.2.132/24 metric 100 brd 192.0.2.255 scope global dynamic eth0
       valid_lft 3355sec preferred_lft 3355sec
    inet6 fe80::1266:6aff:fea6:421f/64 scope link 
       valid_lft forever preferred_lft forever
61: eth1@if62: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:be:cf:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::1266:6aff:febe:cf5a/64 scope link 
       valid_lft forever preferred_lft forever
~$ incus shell haproxy 
~#  vi /etc/netplan/10-lxc.yaml 
network:
    version: 2
    ethernets:
        eth0:
            dhcp4: true
        eth1:
            dhcp4: true
~# netplan apply
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.
~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
59: eth0@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:a6:42:1f brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.0.2.133/24 metric 100 brd 192.0.2.255 scope global dynamic eth0
       valid_lft 3598sec preferred_lft 3598sec
    inet6 fe80::1266:6aff:fea6:421f/64 scope link 
       valid_lft forever preferred_lft forever
61: eth1@if62: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:be:cf:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.16.0.140/16 metric 100 brd 172.16.255.255 scope global dynamic eth1
       valid_lft 3598sec preferred_lft 3598sec
    inet6 fe80::1266:6aff:febe:cf5a/64 scope link 
       valid_lft forever preferred_lft forever
~# exit
logout
~$ incus list -c n,4,s,P,S,l
+---------+---------------------+---------+----------+-----------+----------------------+
|  NAME   |        IPV4         |  STATE  | PROFILES | SNAPSHOTS |     LAST USED AT     |
+---------+---------------------+---------+----------+-----------+----------------------+
| haproxy | 192.0.2.133 (eth0)  | RUNNING | 2NICs    | 0         | 2026/01/17 16:21 CET |
|         | 172.16.0.140 (eth1) |         |          |           |                      |
+---------+---------------------+---------+----------+-----------+----------------------+
| web01   | 172.16.0.142 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+
| web02   | 172.16.0.149 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+
| web03   | 172.16.0.138 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+

HAProxy ten conexión cos servidores da DMZ:

~$ incus exec haproxy -- ping -c 2 172.16.0.142
PING 172.16.0.142 (172.16.0.142) 56(84) bytes of data.
64 bytes from 172.16.0.142: icmp_seq=1 ttl=64 time=0.205 ms
64 bytes from 172.16.0.142: icmp_seq=2 ttl=64 time=0.098 ms

E os servidores da DMZ poden comunicarse entre sí e co HAProxy:
<pre>
~$ incus exec web01 -- ping -c 2 172.16.0.140
PING 172.16.0.140 (172.16.0.140) 56(84) bytes of data.
64 bytes from 172.16.0.140: icmp_seq=1 ttl=64 time=0.169 ms
64 bytes from 172.16.0.140: icmp_seq=2 ttl=64 time=0.108 ms

--- 172.16.0.140 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1046ms
rtt min/avg/max/mdev = 0.108/0.138/0.169/0.030 ms
asir@incus:~$ incus exec web01 -- ping -c 2 172.16.0.149
PING 172.16.0.149 (172.16.0.149) 56(84) bytes of data.
64 bytes from 172.16.0.149: icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from 172.16.0.149: icmp_seq=2 ttl=64 time=0.117 ms

--- 172.16.0.149 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1062ms
rtt min/avg/max/mdev = 0.079/0.098/0.117/0.019 ms

As configuracións IP dos contedores deste escenario son vía servidor dhcp de cada rede á que están conectados; polo tanto, ollo coa saída a Internet:

web01, web02 e web03 reciben como default gw a IP 172.16.0.1 pero como vimos na definición da rede DMZ, ésta non tiña o NAT activado polo que estes equipos non poderán saír a Internet. De feito, unha infraestrutura parecida a esta será montada nun tema posterior e veremos que os servidores non precisan saír a Internet xa que utilizarán ó equipo HAProxy para atender ás peticións dos clientes. haproxy está conectado a dúas redes distintas polo que pode haber problemas co default gw que configura. Aquí si que habería que editar a configuración de rede.

Neste tipo de escenarios o mellor é configurar de forma estática a configuración de rede asignando os valores axeitados. Por exemplo, para haproxy:

NOTAS Ubuntu 20.04, 22.04 e 24.04 empregan por defecto netplan para a configuración de rede. O arquivo de configuración usa de novo YAML polo que os espazos en branco son espazos en branco e non tabuladores Para configurar o default gw Ubuntu 22.04 xa non usa a directiva gateway4 polo o arquivo de configuración debería ser o que se amosa a continuación. Esta nova forma de coniguración é compatible tamén con Ubuntu 20.04 Pasouse desta configuración válida para Ubuntu 20.04 e anteriores:

network:
    version: 2
    ethernets:
        eth0:
            addresses: [192.0.2.151/24]
            gateway4: 192.0.2.1
            nameservers:
              addresses: [8.8.8.8,8.8.4.4]
        eth1:
            addresses: [172.19.0.151/16]

a esta outra que será a que usemos ó longo do curso xa que é compatible coas novas versións e as antigas

network:
    version: 2
    ethernets:
        eth0:
            addresses: [192.0.2.151/24]
            nameservers:
              addresses: [8.8.8.8,8.8.4.4]
            routes:
              - to: default
                via: 192.0.2.1
        eth1:
            addresses: [172.19.0.151/16]
~$ incus shell haproxy 
~# vi /etc/netplan/10-lxc.yamlnetwork
network:
  version: 2
  ethernets:
     eth0:
         addresses: [192.0.2.151/24]
         nameservers:
            addresses: [8.8.8.8,8.8.4.4]
         routes:
            - to: default
              via: 192.0.2.1
     eth1:
         addresses: [172.19.0.151/16]
~# netplan apply
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.
root@haproxy:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
59: eth0@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:a6:42:1f brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.0.2.151/24 brd 192.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::1266:6aff:fea6:421f/64 scope link 
       valid_lft forever preferred_lft forever
61: eth1@if62: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 10:66:6a:be:cf:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.19.0.151/16 brd 172.19.255.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::1266:6aff:febe:cf5a/64 scope link 
       valid_lft forever preferred_lft forever
~# ip route
default via 192.0.2.1 dev eth0 proto static 
172.19.0.0/16 dev eth1 proto kernel scope link src 172.19.0.151 
192.0.2.0/24 dev eth0 proto kernel scope link src 192.0.2.151 
~# exit
logout
~$ incus list -c n,4,s,P,S,l
+---------+---------------------+---------+----------+-----------+----------------------+
|  NAME   |        IPV4         |  STATE  | PROFILES | SNAPSHOTS |     LAST USED AT     |
+---------+---------------------+---------+----------+-----------+----------------------+
| haproxy | 192.0.2.151 (eth0)  | RUNNING | 2NICs    | 0         | 2026/01/17 16:21 CET |
|         | 172.19.0.151 (eth1) |         |          |           |                      |
+---------+---------------------+---------+----------+-----------+----------------------+
| web01   | 172.16.0.142 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+
| web02   | 172.16.0.149 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+
| web03   | 172.16.0.138 (eth0) | RUNNING | dmz      | 0         | 2026/01/17 16:23 CET |
+---------+---------------------+---------+----------+-----------+----------------------+

Aproveitamos este punto para crear un perfil que use a rede lan creada no puntos anterior:

~$ incus profile copy default lan
~$ incus profile edit lan
### This is a YAML representation of the profile.
### Any line starting with a '# will be ignored.
###
### A profile consists of a set of configuration items followed by a set of
### devices.
###
### An example would look like:
### name: onenic
### config:
###   raw.lxc: lxc.aa_profile=unconfined
### devices:
###   eth0:
###     nictype: bridged
###     parent: mybr0
###     type: nic
###
### Note that the name is shown but cannot be changed

config: {}
description: perfil LAN
devices:
  eth0:
    name: eth0
    network: lan
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: lan
used_by: []
project: default
Neste perfil queremos que a tarxeta de rede do contedor esté conectada á lan e non a incusbr0.

Para rematar este punto, reflexionar sobre algunhas das cousas vistas:

  • crear/parar/arrincar/borrar contedores é sinxelo --> un comando
  • crear e configurar unha rede incus é sinxelo --> un comando
  • crear e configurar profiles é sinxelo --> editar un arquivo
  • asignar profiles é sinxelo --> un comando
  • configurar a rede de equipos Ubuntu é sinxelo --> editar un arquivo (lembrarse da sintaxe é un lío pero non deixa de ser un arquivo de texto)

Todo o anterior vainos permitir automatizar o despregamento de escenarios e un escenario como éste, partindo de cero créase en menos de dous minutos. Pensade na primeria unidade: IaC, infraestrutura como código. En unidades posteriores farémolo.

Control de recursos