Una solución

Una solución

El demonio Strongswan coloca sus archivos .pid y .ctl en /var/run para detectar si ya se está ejecutando.

Quiero ejecutar varios de estos demonios en la misma máquina dentro de diferentes espacios de nombres de red. Estoy tratando de lograr esto vinculando el montaje de diferentes directorios (por ejemplo, /etc/namespace1 al /var/run del namespace1 y /etc/namespace2 al /var/run del namespace2). /var/run es un enlace simbólico a /run, así que vinculo el montaje a /run como se muestra a continuación.

Casi puedo lograr esto así:

""En el espacio de nombres predeterminado""

$:~ sudo echo "red" >> /etc/red/run/pidfile
$:~ sudo echo "blue" >> /etc/blue/run/pidfile
$:~ sudo ip netns exec red

""En el espacio de nombres rojo""

$:~ mount --bind /etc/red/run/ /run/
$:~ cat /var/run/pidfile

rojo

""En el espacio de nombres azul""

 $:~ mount --bind /etc/blue/run/ /run/
 $:~ cat /var/run/pidfile

azul

Entonces esto funciona bien. De esta manera, el demonio, cuando crea /var/run/charon.pid mientras está dentro del rojo, no se confundirá con el /var/run/charon.pid del espacio de nombres azul y pueden iniciarse dos instancias.

Sin embargo, aquí está el problema: si "salgo" del espacio de nombres rojo y luego vuelvo a ingresar a través de "ip netns exec red bash", entonces el montaje ya no está presente. Es decir, no hay ningún /var/run/redfile en absoluto.

Entonces la pregunta es ¿cómo puedo hacer que esto quede pegajoso? ¿Necesito cambios en /etc/fstab? Pero no funciona. Si me lo piden, puedo proporcionar detalles de "no funciona".

Estoy perdido. Agradeceré un poco de ayuda.

¡Gracias!

Respuesta1

La solución simple sería indicarle a cada instancia de strongswan que use un directorio diferente para almacenar el archivo PID estableciendo el valor correcto deIPSEC_PIDDIRvariable de entorno en su secuencia de comandos de inicio y parada.

Respuesta2

ip netns execya vincula los montajes /etc/netns/<netns name>/*sobre el archivo/directorio correspondiente en /etc. Por lo tanto, puede compilar strongSwan con, por ejemplo, --with-piddir=/etc/ipsec.d/runy luego crear los directorios necesarios para que cada instancia cree sus archivos PID en directorios separados:

# mkdir -p /etc/ipsec.d/run
# mkdir -p /etc/netns/<netns name 1>/ipsec.d/run
# mkdir -p /etc/netns/<netns name 2>/ipsec.d/run

Se pueden encontrar más detalles en elwiki de cisne fuerte.

Respuesta3

Causa del problema AFAIK

ip netns add ${NSNAME}crea un espacio de nombres persistente, montándolo en /run/netns/${NSNAME}. Esto en sí mismo todavía no implica montar espacios de nombres.

Hacer ip netns exec ${NSNAME} cmdgenera untemporarioespacio de nombres de montaje que existe hasta que cmdsale, después de eso, el espacio de nombres de montaje se limpia, solo queda el espacio de nombres de red. Esto es necesario para lograr el montaje mágico de /etc/netns/${NSNAME}/*. Desafortunadamente, todos los montajes realizados por ellos cmdtambién se limpian.

De man ip-netns:

ip netns execautomatiza el manejo de esta configuración, convención de archivos para aplicaciones que no reconocen el espacio de nombres de red, mediante la creación de un espacio de nombres de montaje y el montaje vinculante de todos los archivos de configuración por espacio de nombres de red en su ubicación tradicional en /etc.

Una solución

Version corta

    # Init for persistent mount namespaces
    $ mkdir /run/mntns \
        && mount --bind --make-private /run/mntns /run/mntns

    $ NSNAME=red

    # Create persistent network+mount namespaces
    $ ip netns add ${NSNAME} \
        && touch "/run/mntns/${NSNAME}" \
        && ip netns exec "${NSNAME}" \
            sh -x -c "nsenter -t $$ --mount mount --bind /proc/\$\$/ns/mnt '/run/mntns/${NSNAME}' && :"

    # Do NOT use `ip netns exec`
    # (Re)enter the namespaces with `nsenter`, mounts are persistent
    $ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
          program arg1 arg2

Versión larga

Es posible crear espacios de nombres persistentes tanto de red como de montaje.

Esto está adaptado en gran medida de los ejemplos de la unsharepágina de manual:http://man7.org/linux/man-pages/man1/unshare.1.html

La principal implicación es que en lugar de ip netns execahora nsenterse debe usar ambos espacios de nombres de red+montaje, al menos donde los montajes importan de todos modos.

Paso 1. Prepárate. Crear directorio para espacios de nombres de montaje persistentes

Esto debe hacerse una vez, por ejemplo, después del arranque, NO para cada espacio de nombres. El camino aquí es arbitrario. Estoy intentando utilizar nombres similares a los utilizados por ip netns.

    # Try to create a dir for persistent mount namespaces
    # and if it got created (e.g. first attempt since boot),
    # then bind mount it with --make-private as required by `unshare --mount=/path`
    $ mkdir /run/mntns \
        && mount --bind --make-private /run/mntns /run/mntns

Tenga en cuenta que mkdir ... && mount ...no son atómicos y cuando hay varios servicios que se inician simultáneamente realizando esta secuencia, puede ocurrir una condición de carrera.

Paso 2. Crear red y montar espacios de nombres persistentes

2a. Método A, montajes simples, sin vínculos mágicos.

Esto crea espacios de nombres de red y montaje persistentes. Es simple pero no crea monturas mágicas para archivos /etc/netns/${NSNAME}/*.

    $ NSNAME=red # give it a name

    # For network namespace use same paths as used by `ip netns` for interoperability
    # touch can fail to update timestamp if file is already mounted
    # Try to create files for persistent mounts.
    # and if touch is successful
    # then create persistent mount and network namespaces
    # Instead of `true` can run a command right away e.g. /bin/bash
    # As it is this is approximate equivalent of `ip netns add ${NANAME}`
    $ touch /run/netns/${NSNAME} /run/mntns/${NSNAME} \
        && unshare --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} true

2b. Método B, aprovechar ip netns execpara hacer montajes pero ser persistente.

Para realizar el montaje de enlace ip netns exec ...pero hacerlos persistentes, puede realizar la configuración de la siguiente manera. Tenga en cuenta que esto debe hacerse SÓLO una vez al crear el espacio de nombres, no cada vez.

    $ ip netns add ${NSNAME} \
        && touch "/run/mntns/${NSNAME}" \
        && ip netns exec "${NSNAME}" \
            sh -x -c "nsenter -t $$ --mount mount --bind /proc/\$\$/ns/mnt '/run/mntns/${NSNAME}' && :"

Para un intento de explicación, consulte hacia el final.

Pasos 3. Úselo

Ahora se nsenterdebe utilizar para ejecutar comandos dentro de ambos espacios de nombres según sea necesario para lograr resultados de montaje persistentes. Esto es independiente de si la configuración se realizó con unshareo ip netns exec NAME sh ... nsneter ... mount ....

    # Get a shell inside the namespaces
    $ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
        /bin/bash

por ejemplo, con los comandos de OP:

    # Do your additional mounts (can also be done above as command to `unshare`)
    # This is approximate equivalent of 
    #   `ip netns exec ${NANAME} mount --bind /etc/red/run/ /run/`
    $ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
          mount --bind /etc/${NSNAME}/run/ /run/

    # Re-enter the namespaces, check that the mounts are still there
    $ nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
          sh -c 'ls /run/'

Importante

Este enfoque funciona, pero en lugar de utilizar ip netns execuse nsenter --net=... --mount=...! Si ip netns exec ...se usa, reemplazará (durante su ejecución) el espacio de nombres de montaje, lo que puede estar bien para comandos a los que no les importa la persistencia del montaje, por ejemplo.

    # This does not touch any files, only operates on network device
    ip netns exec ${NSNAME} ip link set up dev lo

Paso Z.- Limpiar

Independientemente de cuál de los dos métodos anteriores se utilizó para crear los espacios de nombres, la limpieza se puede realizar mediante cualquiera de los dos métodos:

    # This deletes the /mnt/netns/${NSNAME} for us
    ip netns del ${NSNAME}
    # Unmount and delete mount namespace holder
    umount "/mnt/mntns/${NSNAME}" \
        && rm "/mnt/mntns/${NSNAME}"

o

    # Unmount and delete both namespaces' holders
    umount "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}" \
        && rm "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}"

Explicación

Disculpas por el texto largo. Esto es en parte para mi propio beneficio.

Este comando del paso2bLo anterior merece alguna explicación.

El comando otra vez.

    $ ip netns add ${NSNAME} \
        && touch "/run/mntns/${NSNAME}" \
        && ip netns exec "${NSNAME}" \
            sh -x -c "nsenter -t $$ --mount mount --bind /proc/\$\$/ns/mnt '/run/mntns/${NSNAME}' && :"

Deman unshare

Opcionalmente, los espacios de nombres se pueden hacer persistentes montando archivos /proc/pid/ns/type en una ruta del sistema de archivos e ingresando con nsenter(1) incluso después de que finalice el programa (excepto los espacios de nombres PID donde se requiere la ejecución permanente del proceso init). Una vez que ya no se necesita un espacio de nombres persistente, se puede eliminar su persistencia con umount(8).

inicio de explicacion

Esto es lo que hace, si se divide en pasos simples. Tenga en cuenta que se requieren dos shells para esta demostración.

    # SHELL-1

    # Init
    $ mkdir /run/mntns \
        && mount --bind --make-private /run/mntns /run/mntns

    # Prep
    $ NSNAME=red

    # Create namespace
    $ ip netns add ${NSNAME}
    # Start a shell inside the namespace
    $ ip netns exec "${NSNAME}" /bin/bash

    # Now inside a shell inside a namespace.
    # Now need to make a bind mount it this shell's mount namespace
    $ echo $$ # Use this in SHELL2 AS SHELL1_PID
    # Go to SHELL-2 before exiting this one
    # SHELL-2

    # Set this to PID from SHELL-1
    $ SHELL1_PID=????

    $ NSNAME=red
    $ touch "/run/mntns/${NSNAME}"

    $ mount --bind /proc/${SHELL1_PID}/ns/mnt "/run/mntns/${NSNAME}"

Ahora ambos espacios de nombres de red+montaje son persistentes y se pueden volver a ingresar nsentercomo se mostró anteriormente.

La parte importante es montar ip netns exec's /proc/pid/ns/neten el espacio de nombres de montaje de la carcasa exterior.antes ip netns exec..salidas.

Explicación continuación.

Entonces la respuesta es: desde dentro de ip netns exec ...do nsenter, pero no como un comando directo ip netns exec ${NSNAME} nsenter ..., porque eso, exec()sin fork()embargo, dejaría y destruiría el espacio de nombres temporal, sino que causaría una bifurcación() al ejecutar un shell intermedio que mantiene activo el espacio de nombres temporal y el bifurcado. nsenterhace mount. Lo siguiente se acerca más a cómo funciona el comando largo.

    # Init
    $ mkdir /run/mntns \
        && mount --bind --make-private /run/mntns /run/mntns

    # Prep
    $ export NSNAME=red
    $ touch "/run/mntns/${NSNAME}"

    $ export MOUNT_PARENT_PID=$$ # for simplicity

    # Create namespace
    $ ip netns add ${NSNAME}
    # Start a shell inside the namespace, the intermediate shell is important
    $ ip netns exec "${NSNAME}" /bin/bash
    # Now inside a forked namespaced shell

    # Need to mount `ip netns exec` temporary mount namespace to a file
    # within MOUNT_PARENT_PID's namespace to make it persistent
    # nsenter will reference it later

    $$ nsenter -t ${MOUNT_PARENT_PID} --mount \
           mount --bind /proc/$$/ns/mnt "/run/mntns/${NSNAME}"

    # Yes, here $MOUNT_PARENT_PID can be replaced by $PPID
    # But if any intermediate sub-shells and forks get introduced
    # then $PPID can point to a different process.

Parece que algunas versiones de bashinvoked with -c commandpara un solo comando optimizan fork()y ese fork() es realmente necesario aquí, así que fuercelo a fork() al && :final del comando (consulte la versión breve al principio).

Montaje manual/etc/netns/${NSNAME}/*

La respuesta original tenía esta sección, así que aquí está, aunque probablemente no sea muy útil.

Recreando /mnt/netns/${NSNAME}/unir montajes*

La desventaja de usarlo unsharees que no obtienes el montaje de enlace automático /etc/netns/NETNS_NAME/*que proporciona ip netns exec ${NSNAME} cmd, lo cual no es difícil de agregar manualmente.

    # either during unshare or later as nsenter.
    # The important difference is here it is done once and result persists
    # unlike with `ip netns exec` which does this every time
    NSNAME="${NSNAME}" \
      nsenter --net=/run/netns/${NSNAME} --mount=/run/mntns/${NSNAME} \
      /bin/sh -e -x -c \
      'cd "/etc/netns/${NSNAME}"; for f in *; do mount --bind "/etc/netns/${NSNAME}/${f}" "/etc/${f}"; done;'

información relacionada