Назначить физический интерфейс исключительно для docker

Я хотел бы запустить высокопроизводительный сетевой тест в контейнере docker и не хочу накладных расходов на соединение (поэтому pipeworks не будет работать AFAIK). Я хотел бы назначить (в дополнение к обычному устройству docker veth) физический сетевой интерфейс 40GbE от хоста к контейнеру docker, как в режиме lxc "phys". Это должно привести к тому, что физический интерфейс станет невидимым для хоста.

В своем поиске я наткнулся на старые решения, которые предполагали передачу параметров lxc-config в docker, но более новые версии docker больше не используют инструменты lxc, так что это не может работать.

Следуя приведенному здесь предложению: https://groups.google.com/d/msg/docker-user/pL8wlmiuAEU/QfcoFcKI3kgJ решение было найдено.Я не рассматривал возможность изменения сценария pipework, как упоминалось выше, вместо этого используя необходимые команды напрямую. Также смотрите последующее сообщение в блоге: http://jason.digitalinertia.net/exposing-docker-containers-with-sr-iov/.

Следующие низкоуровневые (т.е. не зависящие от docker) команды средства сетевого пространства имен могут использоваться для передачи интерфейса с хоста в контейнер docker:

CONTAINER=slave-play # Name of the docker containerHOST_DEV=ethHOST     # Name of the ethernet device on the hostGUEST_DEV=test10gb   # Target name for the same device in the containerADDRESS_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 workmkdir -p /var/run/netnsPID=$(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 containerip 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 containerip 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 stoppedrm /var/run/netns/$PID

>Небольшое предостережение в отношении именования интерфейса, если на вашем хосте много устройств ethX (у меня было eth0 - eth5). Например, допустим, вы перемещаете eth3 в контейнер как eth1 в пространстве имен containers. Когда вы остановите контейнер, ядро попытается переместить устройство eth1 контейнера обратно на хост, но заметит, что устройство eth1 уже существует. Затем он переименует интерфейс во что-то произвольное; мне потребовалось некоторое время, чтобы найти его снова. По этой причине я отредактировал /etc/udev/rules.d/70-persistent-net.rules (я думаю, что это имя файла является общим для большинства популярных дистрибутивов Linux; я использую Debian), чтобы присвоить рассматриваемому интерфейсу уникальное, безошибочное имя и использовать его как в контейнере, так и на хозяин.

Поскольку мы не используем docker для выполнения этой настройки, стандартные инструменты жизненного цикла docker (например, docker run --restart=on-failure:10 ...) не могут быть использованы. На хост-машине, о которой идет речь, работает Debian Wheezy, поэтому я написал следующий сценарий инициализации:

#!/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 INFOCONTAINER=slave-playSCRIPT="docker start -i $CONTAINER"RUNAS=rootLOGFILE=/var/log/$CONTAINER.logLOGFILE=/var/log/$CONTAINER.logHOST_DEV=test10gbGUEST_DEV=test10gbADDRESS_AND_NET=10.101.0.5/24start() {  if [ -f /var/run/$PIDNAME ] && kill -0 $(cat /var/run/$PIDNAME); thenecho 'Service already running' >&2return 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)stopstart;;  *)echo "Usage: $0 {start|stop|restart}"esac

Немного банально, но это работает :)

pipework может переместить физический сетевой интерфейс из пространства имен по умолчанию в пространство имен контейнерной сети:

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

Для получения дополнительной информации см. здесь.

Для этого я пишу сетевой плагин docker.

https://github.com/yunify/docker-plugin-hostnic

docker pull qingcloud/docker-plugin-hostnicdocker run -v /run/docker/plugins:/run/docker/plugins -v /etc/docker/hostnic:/etc/docker/hostnic --network host --privileged qingcloud/docker-plugin-hostnic docker-plugin-hostnicdocker network create -d hostnic --subnet=192.168.1.0/24 --gateway 192.168.1.1 hostnicdocker run -it --ip 192.168.1.5 --mac-address 52:54:0e:e5:00:f7 --network hostnic ubuntu:14.04 bash