
O daemon Strongswan coloca seus arquivos .pid e .ctl em /var/run para detectar se já está em execução.
Quero executar vários desses daemons na mesma máquina em diferentes namespaces de rede. Estou tentando conseguir isso ligando a montagem de diretórios diferentes (digamos /etc/namespace1 para /var/run do namespace1 e /etc/namespace2 para /var/run do namespace2). /var/run é um link simbólico para /run, então vinculo mount a /run como abaixo.
Quase posso conseguir isso assim:
""No namespace padrão""
$:~ sudo echo "red" >> /etc/red/run/pidfile
$:~ sudo echo "blue" >> /etc/blue/run/pidfile
$:~ sudo ip netns exec red
""No namespace vermelho""
$:~ mount --bind /etc/red/run/ /run/
$:~ cat /var/run/pidfile
vermelho
""No namespace azul""
$:~ mount --bind /etc/blue/run/ /run/
$:~ cat /var/run/pidfile
azul
Então isso funciona bem. Dessa forma, o daemon, ao criar /var/run/charon.pid enquanto estiver dentro do vermelho, não será confundido com o /var/run/charon.pid do namespace azul e duas instâncias poderão ser iniciadas.
No entanto, aqui está o problema: se eu "sair" do namespace vermelho e entrar novamente via "ip netns exec red bash", a montagem não estará mais presente. Ou seja, não existe /var/run/redfile.
Então, a questão é como posso tornar isso pegajoso? Preciso de alterações no /etc/fstab? Mas não funciona. Se solicitado, posso fornecer detalhes de "não funciona".
Eu estou perdido. Apreciaremos alguma ajuda.
Obrigado!
Responder1
A solução simples seria instruir cada instância do Strongswan a usar um diretório diferente para armazenar o arquivo PID, definindo o valor correto doIPSEC_PIDDIR
variável de ambiente em seu script de início e parada.
Responder2
ip netns exec
já vincule montagens /etc/netns/<netns name>/*
no arquivo/diretório correspondente em /etc
. Portanto, você pode compilar o StrongSwan com, por exemplo, --with-piddir=/etc/ipsec.d/run
e criar os diretórios necessários para que cada instância crie seus arquivos PID em diretórios 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
Mais detalhes podem ser encontrados nowiki do StrongSwan.
Responder3
Causa do problema AFAIK
ip netns add ${NSNAME}
cria um namespace persistente, montando-o em /run/netns/${NSNAME}
. Isso por si só ainda não envolve namespaces de montagem.
Fazer ip netns exec ${NSNAME} cmd
gera umtemporáriomount namespace que existe até cmd
a saída, depois disso o namespace de montagem é limpo, apenas o namespace de rede permanece. Isto é necessário para conseguir a montagem mágica do /etc/netns/${NSNAME}/*
. Infelizmente, todas as montagens feitas por eles cmd
também são limpas.
De man ip-netns
:
ip netns exec
automatiza o tratamento dessa configuração, convenção de arquivos para aplicativos que não reconhecem namespace de rede, criando um namespace de montagem e montagem vinculada de todos os arquivos de configuração de namespace por rede em seu local tradicional em /etc.
Uma solução
Versão curta
# 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
Versão longa
É possível criar namespaces de rede e de montagem persistentes.
Isso é amplamente adaptado de exemplos na unshare
página de manual:http://man7.org/linux/man-pages/man1/unshare.1.html
A principal implicação é que, em vez de ip netns exec
agora nsenter
, deve ser usado para usar ambos os namespaces de rede + montagem, pelo menos onde as montagens são importantes.
Passo 1. Prepare-se. Criar diretório para namespaces de montagem persistentes
Isto precisa ser feito uma vez, por exemplo, após a inicialização, NÃO para cada namespace. O caminho aqui é arbitrário. Estou tentando usar uma nomenclatura semelhante à usada 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
Observe que eles mkdir ... && mount ...
não são atômicos e onde há vários serviços iniciando simultaneamente fazendo essa sequência, uma condição de corrida pode ocorrer.
Etapa 2. Criar namespaces persistentes de rede + montagem
2a. método A, simples, sem montagens mágicas.
Isso cria namespaces de montagem + rede persistentes. É simples, mas não cria montagens mágicas para arquivos /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, aproveite ip netns exec
para fazer montagens, mas torne-as persistentes.
Para fazer essas montagens de ligação, ip netns exec ...
mas torná-las persistentes, você pode fazer a configuração da seguinte maneira. Observe que isso deve ser feito SOMENTE uma vez ao criar o namespace, não sempre.
$ 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 uma tentativa de explicação, veja no final.
Etapas 3. Use-o
Agora, o nsenter
deve ser usado para iniciar comandos dentro de ambos os namespaces, conforme necessário para obter resultados de montagem persistentes. Isso ocorre independentemente de a configuração ter sido feita com unshare
ou 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 exemplo, com comandos do 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
Essa abordagem funciona, mas em vez de usar ip netns exec
use nsenter --net=... --mount=...
! Se ip netns exec ...
for usado, ele substituirá (durante sua execução) o namespace de montagem, o que pode ser aceitável para comandos que não se importam com a persistência da montagem, por exemplo
# This does not touch any files, only operates on network device
ip netns exec ${NSNAME} ip link set up dev lo
Etapa Z. - Limpar
Independentemente de qual dos dois métodos acima foi usado para criar os namespaces, a limpeza pode ser feita por qualquer um dos dois 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}"
ou
# Unmount and delete both namespaces' holders
umount "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}" \
&& rm "/mnt/mntns/${NSNAME}" "/mnt/netns/${NSNAME}"
Explicação
Desculpas pelo texto longo. Isto é em parte para meu próprio benefício.
Este comando da etapa2bacima merece alguma explicação.
O comando novamente.
$ 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, os namespaces podem se tornar persistentes vinculando a montagem de arquivos /proc/pid/ns/type a um caminho do sistema de arquivos e inseridos com nsenter(1) mesmo após o término do programa (exceto namespaces PID onde o processo init em execução permanente é necessário). Quando um namespace persistente não for mais necessário, sua persistência poderá ser cancelada com umount(8).
Início da explicação
Aqui está o que ele faz, se dividido em etapas simples. Observe que dois shells são necessários para esta demonstração.
# 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}"
Agora, ambos os namespaces de rede + montagem são persistentes e podem ser inseridos novamente nsenter
como mostrado anteriormente.
A parte importante é a ip netns exec
montagem/proc/pid/ns/net
namespace de montagem do shell externoantes ip netns exec..
saídas.
Explicação cont.
Portanto, a resposta é: de dentro ip netns exec ...
do do nsenter
, mas não como um comando direto , porque isso ip netns exec ${NSNAME} nsenter ...
exec()
deixaria fork()
e destruiria o namespace temporário, mas causaria um fork() executando um shell intermediário que mantém o namespace temporário ativo, e o fork nsenter
faz mount
. O seguinte está mais próximo de como funciona o comando longo.
# 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 algumas versões bash
invocadas com -c command
para um único comando otimizam o fork()
e que fork() é realmente necessário aqui, então force-o a fork() com && :
no final do comando (veja a versão resumida no início).
Montagem manual/etc/netns/${NSNAME}/*
A resposta original tinha esta seção, então aqui está, embora provavelmente não seja muito útil.
Recriando /mnt/netns/${NSNAME}/vincular montagens*
A desvantagem de usar unshare
é que você não obtém a montagem automática de ligação /etc/netns/NETNS_NAME/*
fornecida pelo ip netns exec ${NSNAME} cmd
, o que não é difícil de adicionar 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;'