Atribuir interface física ao docker exclusivamente

12

Gostaria de executar um teste de rede de alto desempenho em um contêiner de docker e não quero a sobrecarga da ponte (para que os pipeworks não funcionem no AFAIK). Gostaria de atribuir (além do dispositivo docker normal veth) uma interface de rede física de 40GbE do host para um contêiner docker, como no modo lxc "phys". Isso deve fazer com que a interface física fique invisível para o host.

NeilenMarais
fonte

Respostas:

4

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, clique aqui .

Christoph Zauner
fonte
1
Eu aceito esta resposta porque parece simples, mas eu não tentei me (eu usei a longa resposta que eu escrevi antes pipeworks cresceu essa funcionalidade)
NeilenMarais
7

Na minha pesquisa, me deparei com soluções antigas que invocavam 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, de modo que não podem funcionar.

Seguindo a sugestão aqui: https://groups.google.com/d/msg/docker-user/pL8wlmiuAEU/QfcoFcKI3kgJ, uma solução foi encontrada. Eu não procurei modificar o script de tubagem conforme mencionado acima, em vez de usar diretamente os comandos necessários. Consulte também a postagem subsequente do blog: http://jason.digitalinertia.net/exposing-docker-containers-with-sr-iov/ .

Os seguintes comandos da ferramenta de espaço para nome de rede de baixo nível (isto é, não específico 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 ressalva na interface, que indica se o seu host possui muitos dispositivos ethX (o meu tinha eth0 -> eth5). Por exemplo, digamos que você mova eth3 para o contêiner como eth1 no espaço para nome dos contêineres. Quando você para o contêiner, o kernel tenta mover o dispositivo eth1 do contêiner de volta para o host, mas observe que já existe um dispositivo eth1. Ele irá renomear a interface para algo arbitrário; Levei um tempo para encontrá-lo novamente. Por esse motivo, editei o /etc/udev/rules.d/70-persistent-net.rules (acho que esse nome de arquivo é comum às distribuições Linux mais populares; estou usando o 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 essa configuração, as ferramentas padrão do ciclo de vida do docker (por exemplo, docker run --restart = on-fail: 10 ...) não podem ser usadas. A máquina host em questão executa o Debian Wheezy, então escrevi o seguinte script init:

#!/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

Ligeiramente hacky, mas funciona :)

NeilenMarais
fonte
Por que seus nomes de interface de rede começam eth? O Debian não faz nomes de dispositivos de rede consistentes?
Michael Hampton
Para qualquer outra pessoa que estivesse se perguntando por que o link simbólico /var/run/netns/$PIDé necessário: Você precisa dele para que os ip netns exec $PID ...comandos funcionem.
quer
2

Eu escrevo um plug-in 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
jolestar
fonte