Me gustaría ejecutar una prueba de red de alto rendimiento en un contenedor acoplable y no quiero la sobrecarga del puente (por lo que las tuberías no funcionarán, AFAIK). Me gustaría asignar (además del dispositivo Docker Veth normal) una interfaz de red física de 40 GbE desde el host a un contenedor Docker como en el modo lxc "phys". Esto debería hacer que la interfaz física se vuelva invisible para el host.
Respuesta1
pipework
Puede mover una interfaz de red física desde el valor predeterminado al espacio de nombres de la red del contenedor:
$ sudo pipework --direct-phys eth1 $CONTAINERID 192.168.1.2/24
Para más información, veraquí.
Respuesta2
En mi búsqueda encontré soluciones antiguas que implicaban pasar parámetros lxc-config a Docker, pero las versiones más nuevas de Docker ya no usan las herramientas lxc, por lo que eso no puede funcionar.
Siguiendo la sugerencia aquí:https://groups.google.com/d/msg/docker-user/pL8wlmiuAEU/QfcoFcKI3kgJse encontró una solución. No busqué modificar el script de tubería como se mencionó anteriormente, sino que usé los comandos requeridos directamente. Consulte también la siguiente publicación del blog:http://jason.digitalinertia.net/exposing-docker-containers-with-sr-iov/.
Los siguientes comandos de herramienta de espacio de nombres de red de bajo nivel (es decir, no específicos de Docker) se pueden utilizar para transferir una interfaz desde el host a un contenedor de 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
Una pequeña advertencia sobre el nombre de la interfaz si su host tiene muchos dispositivos ethX (el mío tenía eth0 -> eth5). Por ejemplo, digamos que mueve eth3 al contenedor como eth1 en el espacio de nombres del contenedor. Cuando detiene el contenedor, el kernel intentará mover el dispositivo eth1 del contenedor nuevamente al host, pero observe que ya existe un dispositivo eth1. Luego cambiará el nombre de la interfaz a algo arbitrario; Me tomó un tiempo encontrarlo de nuevo. Por esta razón edité /etc/udev/rules.d/70-persistent-net.rules (creo que este nombre de archivo es común a las distribuciones de Linux más populares; estoy usando Debian) para darle a la interfaz en cuestión un nombre único e inconfundible. y utilícelo tanto en el contenedor como en el host.
Dado que no utilizamos Docker para realizar esta configuración, no se pueden utilizar las herramientas estándar del ciclo de vida de Docker (por ejemplo, Docker Run --restart=on-failure:10...). La máquina host en cuestión ejecuta Debian Wheezy, así que escribí el siguiente script de inicio:
#!/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
Un poco complicado, pero funciona :)
Respuesta3
Escribo un complemento de red Docker para hacer esto.
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