Gostaria de executar um teste de rede de alto desempenho em um contêiner docker e não quero a sobrecarga da ponte (para que as tubulações não funcionem no AFAIK). Gostaria de atribuir (além do dispositivo docker veth normal) uma interface de rede física de 40 GbE do host para um contêiner do docker, como no modo "phys" lxc. Isso deve fazer com que a interface física fique invisível para o host.
Responder1
pipework
pode mover uma interface de rede física do padrão para o namespace da rede de contêiner:
$ sudo pipework --direct-phys eth1 $CONTAINERID 192.168.1.2/24
Para mais informações, vejaaqui.
Responder2
Na minha pesquisa me deparei com soluções antigas que envolviam a passagem de parâmetros lxc-config para o docker, mas as versões mais recentes do docker não usam mais as ferramentas lxc, então isso não pode funcionar.
Seguindo a sugestão aqui:https://groups.google.com/d/msg/docker-user/pL8wlmiuAEU/QfcoFcKI3kgJuma solução foi encontrada. Não pensei em modificar o script de tubulação conforme mencionado acima, em vez disso, usei os comandos necessários diretamente. Veja também a postagem subsequente do blog:http://jason.digitalinertia.net/exposing-docker-containers-with-sr-iov/.
Os seguintes comandos de ferramenta de namespace de rede de baixo nível (ou seja, não específicos do docker) podem ser usados para transferir uma interface do host para um contêiner do docker:
CONTAINER=slave-play # Name of the docker container
HOST_DEV=ethHOST # Name of the ethernet device on the host
GUEST_DEV=test10gb # Target name for the same device in the container
ADDRESS_AND_NET=10.101.0.5/24
# Next three lines hooks up the docker container's network namespace
# such that the ip netns commands below will work
mkdir -p /var/run/netns
PID=$(docker inspect -f '{{.State.Pid}}' $CONTAINER)
ln -s /proc/$PID/ns/net /var/run/netns/$PID
# Move the ethernet device into the container. Leave out
# the 'name $GUEST_DEV' bit to use an automatically assigned name in
# the container
ip link set $HOST_DEV netns $PID name $GUEST_DEV
# Enter the container network namespace ('ip netns exec $PID...')
# and configure the network device in the container
ip netns exec $PID ip addr add $ADDRESS_AND_NET dev $GUEST_DEV
# and bring it up.
ip netns exec $PID ip link set $GUEST_DEV up
# Delete netns link to prevent stale namespaces when the docker
# container is stopped
rm /var/run/netns/$PID
Uma pequena advertência sobre a nomenclatura da interface se o seu host tiver muitos dispositivos ethX (o meu tinha eth0 -> eth5). Por exemplo, digamos que você mova eth3 para o contêiner como eth1 no namespace do contêiner. Quando você interrompe o contêiner, o kernel tentará mover o dispositivo eth1 do contêiner de volta para o host, mas observe que já existe um dispositivo eth1. Em seguida, ele renomeará a interface para algo arbitrário; demorei um pouco para encontrá-lo novamente. Por esta razão editei /etc/udev/rules.d/70-persistent-net.rules (acho que este nome de arquivo é comum às distros Linux mais populares; estou usando Debian) para dar à interface em questão um nome único e inconfundível e use isso no contêiner e no host.
Como não estamos usando o docker para fazer esta configuração, as ferramentas padrão do ciclo de vida do docker (por exemplo, docker run --restart=on-failure:10 ...) não podem ser usadas. A máquina host em questão executa o Debian Wheezy, então escrevi o seguinte script de inicialização:
#!/bin/sh
### BEGIN INIT INFO
# Provides: slave-play
# Required-Start: $local_fs $network $named $time $syslog $docker
# Required-Stop: $local_fs $network $named $time $syslog $docker
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: some slavishness
### END INIT INFO
CONTAINER=slave-play
SCRIPT="docker start -i $CONTAINER"
RUNAS=root
LOGFILE=/var/log/$CONTAINER.log
LOGFILE=/var/log/$CONTAINER.log
HOST_DEV=test10gb
GUEST_DEV=test10gb
ADDRESS_AND_NET=10.101.0.5/24
start() {
if [ -f /var/run/$PIDNAME ] && kill -0 $(cat /var/run/$PIDNAME); then
echo 'Service already running' >&2
return 1
fi
echo 'Starting service…' >&2
local CMD="$SCRIPT &> \"$LOGFILE\" &"
su -c "$CMD" $RUNAS
sleep 0.5 # Nasty hack so that docker container is already running before we do the rest
mkdir -p /var/run/netns
PID=$(docker inspect -f '{{.State.Pid}}' $CONTAINER)
ln -s /proc/$PID/ns/net /var/run/netns/$PID
ip link set $HOST_DEV netns $PID name $GUEST_DEV
ip netns exec $PID ip addr add $ADDRESS_AND_NET dev $GUEST_DEV
ip netns exec $PID ip link set $GUEST_DEV up
rm /var/run/netns/$PID
echo 'Service started' >&2
}
stop() {
echo "Stopping docker container $CONTAINER" >&2
docker stop $CONTAINER
echo "docker container $CONTAINER stopped" >&2
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
esac
Um pouco hacky, mas funciona :)
Responder3
Eu escrevo um plugin de rede docker para fazer isso.
https://github.com/yunify/docker-plugin-hostnic
docker pull qingcloud/docker-plugin-hostnic
docker run -v /run/docker/plugins:/run/docker/plugins -v /etc/docker/hostnic:/etc/docker/hostnic --network host --privileged qingcloud/docker-plugin-hostnic docker-plugin-hostnic
docker network create -d hostnic --subnet=192.168.1.0/24 --gateway 192.168.1.1 hostnic
docker run -it --ip 192.168.1.5 --mac-address 52:54:0e:e5:00:f7 --network hostnic ubuntu:14.04 bash