Atribuir interface física exclusivamente ao docker

Atribuir interface física exclusivamente ao docker

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

pipeworkpode 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

informação relacionada