Weisen Sie die physische Schnittstelle ausschließlich dem Docker zu

Weisen Sie die physische Schnittstelle ausschließlich dem Docker zu

Ich möchte einen Hochleistungsnetzwerktest in einem Docker-Container ausführen und möchte den Overhead des Bridgings vermeiden (also funktionieren Pipeworks meines Wissens nach nicht). Ich möchte (zusätzlich zum normalen Docker-Veth-Gerät) eine physische 40GbE-Netzwerkschnittstelle vom Host zu einem Docker-Container zuweisen, wie im lxc-Modus „phys“. Dadurch sollte die physische Schnittstelle für den Host unsichtbar werden.

Antwort1

pipeworkkann eine physische Netzwerkschnittstelle vom Standard- in den Container-Netzwerk-Namespace verschieben:

    $ sudo pipework --direct-phys eth1 $CONTAINERID 192.168.1.2/24

Weitere Informationen finden Sie unterHier.

Antwort2

Bei meiner Suche bin ich auf alte Lösungen gestoßen, bei denen lxc-Konfigurationsparameter an Docker übergeben wurden, aber neuere Versionen von Docker verwenden die lxc-Tools nicht mehr, sodass das nicht funktionieren kann.

Ich folge dem Vorschlag hier:https://groups.google.com/d/msg/docker-user/pL8wlmiuAEU/QfcoFcKI3kgJeine Lösung wurde gefunden. Ich habe nicht versucht, das Pipework-Skript wie oben erwähnt zu ändern, sondern habe stattdessen die erforderlichen Befehle direkt verwendet. Siehe auch nachfolgenden Blog-Beitrag:http://jason.digitalinertia.net/exposing-docker-containers-with-sr-iov/.

Die folgenden Low-Level-Befehle (also nicht Docker-spezifisch) für Netzwerk-Namespace-Tools können zum Übertragen einer Schnittstelle vom Host in einen Docker-Container verwendet werden:

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

Eine kleine Einschränkung bei der Schnittstellenbenennung, wenn Ihr Host viele ethX-Geräte hat (meiner hatte eth0 -> eth5). Nehmen wir beispielsweise an, Sie verschieben eth3 als eth1 in den Container im Container-Namespace. Wenn Sie den Container stoppen, versucht der Kernel, das eth1-Gerät des Containers zurück zum Host zu verschieben, aber beachten Sie, dass bereits ein eth1-Gerät vorhanden ist. Er wird dann die Schnittstelle in etwas Beliebiges umbenennen; es hat eine Weile gedauert, bis ich es wiedergefunden habe. Aus diesem Grund habe ich /etc/udev/rules.d/70-persistent-net.rules bearbeitet (ich glaube, dieser Dateiname ist bei den meisten gängigen Linux-Distributionen üblich; ich verwende Debian), um der betreffenden Schnittstelle einen eindeutigen, unverwechselbaren Namen zu geben und diesen sowohl im Container als auch auf dem Host zu verwenden.

Da wir für diese Konfiguration kein Docker verwenden, können die Standardtools für den Docker-Lebenszyklus (z. B. docker run --restart=on-failure:10 ...) nicht verwendet werden. Auf dem betreffenden Hostcomputer läuft Debian Wheezy, daher habe ich das folgende Init-Skript geschrieben:

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

Etwas abgedroschen, aber es funktioniert :)

Antwort3

Dazu schreibe ich ein Docker-Netzwerk-Plugin.

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

verwandte Informationen