Problema

En entornos de homelab o pequeñas infraestructuras es frecuente montar discos de gran capacidad dentro de contenedores LXC y exponerlos mediante Samba (SMB). Cuando los clientes Windows o Linux acceden al recurso, la transferencia puede caer a unos pocos kilobytes por segundo, a pesar de que el disco subyacente muestra actividad mínima y el host Proxmox no presenta cuellos de botella visibles. El síntoma típico es:

  • Copias de archivos que tardan minutos en completarse.
  • Conexiones SSH al contenedor que se vuelven latentes durante la transferencia.
  • iostat del host que muestra casi nada de I/O, salvo picos cada varios segundos.
  • Uso de CPU bajo, pero memoria del contenedor saturada por buffers.

Este patrón no es exclusivo de una única configuración; aparece siempre que el flujo de datos entre el proceso Samba dentro del LXC y el bloque de disco del host está limitado por la capa de virtualización o por la forma en que se gestionan los buffers de escritura.

Causa

Varias capas pueden introducir la restricción:

  1. Montaje del disco en el host con opciones inadecuadas
    Cuando el dispositivo se monta con defaults y sin ajustes de noatime, async o data=writeback, el kernel puede forzar escrituras sincronizadas muy agresivas. En un LXC, el contenedor hereda esos comportamientos y Samba termina esperando a que el host vacíe los buffers.

  2. Cgroup v2 y limitaciones de I/O
    Proxmox usa cgroups para aislar recursos. Si el contenedor no tiene asignado un blkio.weight adecuado, el scheduler de I/O le da muy poca prioridad, provocando que los writes se acumulen en la memoria del contenedor y se descarguen al disco en ráfagas cada 10‑20 s.

  3. Configuración de smb.conf orientada a seguridad
    Parámetros como strict sync = yes, write cache size = 0 o socket options = TCP_NODELAY pueden forzar que cada bloque se escriba de forma síncrona, anulando cualquier caché del kernel.

  4. Uso de tmpfs o ramfs como punto intermedio
    Algunas guías recomiendan montar el punto de exportación en tmpfs para acelerar el acceso, pero si el contenedor no tiene suficiente RAM, el swap se activa y la velocidad se desploma.

  5. Versión del kernel del host y parches de Proxmox
    En versiones antiguas, el driver virtio-blk puede presentar una latencia alta cuando se combina con fsync frecuente. Aunque el host indique bajo uso de CPU, el path de I/O está saturado internamente.

Solución

Una estrategia robusta combina ajustes en tres niveles: host, contenedor y Samba.

1. Optimizar el montaje del disco en el host

Reemplaza la línea de /etc/fstab por una que habilite escritura asíncrona y reduzca la frecuencia de flushes:

/dev/disk/by-id/ata-ST4000DM004-2U9104_ZW63X7HJ /mnt/NetworkDrive ext4 defaults,noatime,async,data=writeback,commit=60 0 2
  • noatime evita escrituras de acceso.
  • async permite que el kernel agrupe writes.
  • data=writeback reduce la consistencia de metadatos a cambio de velocidad (aceptable en un NAS doméstico).
  • commit=60 fuerza al menos 60 s entre flushes, alineado con la observación de writes cada 20 s.

Después de editar, ejecuta mount -o remount /mnt/NetworkDrive o reinicia el host.

2. Ajustar los límites de I/O del contenedor

En la definición del contenedor (/etc/pve/lxc/ID.conf) agrega o modifica:

lxc.cgroup2.blkio.weight = 1000
lxc.cgroup2.blkio.throttle.read_bps_device = 0:0 0
lxc.cgroup2.blkio.throttle.write_bps_device = 0:0 0

weight de 1000 es el máximo, garantizando que el scheduler le dé prioridad al contenedor. Si la infraestructura comparte varios LXC, puedes bajar el valor pero nunca por debajo de 500.

Aplica los cambios con pct restart ID.

3. Configurar Samba para aprovechar caché

Edita /etc/samba/smb.conf en el contenedor y añade (o modifica) los siguientes parámetros dentro del share:

[NetworkDrive]
   path = /mnt/NetworkDrive
   read only = no
   force user = root
   strict sync = no
   write cache size = 2097152   ; 2 MiB
   socket options = TCP_NODELAY SO_RCVBUF=65536 SO_SNDBUF=65536
   aio read size = 1M
   aio write size = 1M
   vfs objects = full_audit
  • strict sync = no permite que Samba agrupe writes.
  • write cache size habilita una caché interna de 2 MiB.
  • aio (asynchronous I/O) reduce la latencia al delegar al kernel la gestión de buffers.

Reinicia Samba: systemctl restart smbd.

4. Desactivar swap dentro del contenedor

El swap dentro del LXC puede ser el culpable de los “picos” cada 20 s. Desactívalo temporalmente:

swapoff -a

Si necesitas swap permanente, ajusta vm.swappiness a un valor bajo en /etc/sysctl.conf del contenedor:

vm.swappiness = 10

Aplica con sysctl -p.

5. Verificar la latencia de red

Aunque el problema suele ser de I/O, una MTU mal configurada en la interfaz veth del contenedor puede generar retransmisiones que ralentizan SMB. Asegúrate de que la MTU sea 1500 en ambos extremos:

ip link set dev eth0 mtu 1500

Cuándo aplicar esta solución

Utiliza este conjunto de ajustes cuando observes:

  • Transferencias SMB por debajo de 1 MiB/s en un entorno LXC bajo Proxmox.
  • iostat del host muestra actividad de escritura cada varios segundos.
  • El contenedor tiene uso de RAM constante alrededor del 100 % y swap activo.
  • Otros servicios (SSH, HTTP) dentro del mismo LXC también presentan latencia.

No es necesario aplicar todo si ya has identificado la causa principal. Por ejemplo, si el fstab ya usa async y el problema persiste, enfócate en los cgroup y en la configuración de Samba.

No apliques estos cambios si:

  • El NAS está en producción crítica y no puedes sacrificar la consistencia de metadatos (data=writeback).
  • El host comparte discos con bases de datos que requieren fsync estricto.
  • La política de la empresa prohíbe desactivar strict sync.

Código

# 1. Montaje optimizado en el host
sed -i 's|/dev/disk/by-id/ata-ST4000DM004-2U9104_ZW63X7HJ /mnt/NetworkDrive ext4.*|/dev/disk/by-id/ata-ST4000DM004-2U9104_ZW63X7HJ /mnt/NetworkDrive ext4 defaults,noatime,async,data=writeback,commit=60 0 2|' /etc/fstab
mount -o remount /mnt/NetworkDrive

# 2. Ajuste de cgroup para el contenedor (ID=101)
cat <<EOF >> /etc/pve/lxc/101.conf
lxc.cgroup2.blkio.weight = 1000
lxc.cgroup2.blkio.throttle.read_bps_device = 0:0 0
lxc.cgroup2.blkio.throttle.write_bps_device = 0:0 0
EOF
pct restart 101

# 3. Configuración de Samba dentro del contenedor
cat >> /etc/samba/smb.conf <<'EOS'
[NetworkDrive]
   path = /mnt/NetworkDrive
   read only = no
   force user = root
   strict sync = no
   write cache size = 2097152
   socket options = TCP_NODELAY SO_RCVBUF=65536 SO_SNDBUF=65536
   aio read size = 1M
   aio write size = 1M
EOS
systemctl restart smbd

# 4. Desactivar swap y ajustar swappiness
swapoff -a
echo "vm.swappiness = 10" >> /etc/sysctl.conf
sysctl -p

# 5. Forzar MTU 1500 en la interfaz del contenedor
ip link set dev eth0 mtu 1500

Verificación

  1. Medir velocidad SMB
    Desde un cliente Windows ejecuta robocopy o usa smbclient con -c 'stat'. Deberías ver tasas superiores a 20 MiB/s en un disco SATA/HDD y >100 MiB/s en SSD.

  2. Comprobar I/O del host
    iostat -x 5 3 debe mostrar actividad constante en el dispositivo, sin los largos silencios de 20 s.

  3. Revisar buffers del contenedor
    cat /proc/meminfo | grep -i dirty debe indicar valores menores a 1 MiB después de la transferencia.

  4. Validar que no hay swap
    free -h muestra Swap: 0B 0B 0B.

  5. Confirmar cgroup weight
    cat /sys/fs/cgroup/blkio/lxc/101/blkio.weight debe devolver 1000.

Si alguna métrica sigue fuera de lo esperado, revisa los logs de dmesg y