docker工人:如何轻松获得veth桥接口对?

我有2个容器由docker,和桥这样的:

root@venus-166:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ef99087167cb images.docker.sae.sina.com.cn/ubuntu:latest /bin/bash -c /home/c 2 days ago Up 21 minutes 0.0.0.0:49240->22223/tcp night_leve3 c8a7b18ec20d images.docker.sae.sina.com.cn/ubuntu:latest /bin/bash -c /home/c 2 days ago Up 54 minutes 0.0.0.0:49239->22223/tcp night_leve2 bridge name bridge id STP enabled interfaces docker0 8000.72b675c52895 no vethRQOy1I vethjKYWka 

我怎样才能得到哪个容器匹配veth*

 ef99 => vethRQOy1I or ef99 => vethjKYWka 

// ———————————————— ———-

我知道它通过ethtool ,但有没有更好的办法?

这是上面提到的ethtool技巧的一个变种,没有实际使用ethtool:

 function veth_interface_for_container() { # Get the process ID for the container named ${1}: local pid=$(docker inspect -f '{{.State.Pid}}' "${1}") # Make the container's network namespace available to the ip-netns command: mkdir -p /var/run/netns ln -sf /proc/$pid/ns/net "/var/run/netns/${1}" # Get the interface index of the container's eth0: local index=$(ip netns exec "${1}" ip link show eth0 | head -n1 | sed s/:.*//) # Increment the index to determine the veth index, which we assume is # always one greater than the container's index: let index=index+1 # Write the name of the veth interface to stdout: ip link show | grep "^${index}:" | sed "s/${index}: \(.*\):.*/\1/" # Clean up the netns symlink, since we don't need it anymore rm -f "/var/run/netns/${1}" } 

有很多“黑客”的方式来做到这一点:

  • 扫描内核日志,正如Jiri所说(但是你必须在启动容器后立即执行,否则会变得麻烦);
  • 检查容器中的接口计数器(发送/接收的数据包/字节),然后与主机中的接口进行比较,find匹配的对(但是发送和接收方向翻转);
  • 使用iptables LOG规则。

最后一个选项是,恕我直言,更可靠的(也是最容易使用),但它仍然非常hackish。 这个想法很简单:

  1. 添加一个iptables规则来logging例如到达Docker网桥的ICMPstream量:

    sudo iptables -I INPUT -i docker0 -p icmp -j LOG

  2. 发送一个ping到你想识别的容器:

    IPADDR=$(docker inspect -format='{{.NetworkSettings.IPAddress}}' 0c33)

    ping -c 1 $IPADDR

  3. 检查内核日志:

    dmesg | grep $IPADDR

    你会看到这样的一行:

    […] IN=docker0 OUT= PHYSIN=vethv94jPK MAC=fe:2c:7f:2c:ab:3f:42:83:95:74:0b:8f:08:00 SRC=172.17.0.79 …

    如果你想要PHYSIN=… ,只需提取PHYSIN=…用awk或sed。

  4. 除去iptables日志logging规则(除非你想把它留在那里,因为你会定期ping容器来识别它们)。

如果您需要防弹版本,则可以安装ulogd并使用ULOG目标。 而不是仅仅将数据包标头写入内核日志,它将通过一个netlink套接字发送它们,然后用户态程序可以正确地处理它们。

如果有人仍然对此感兴趣。 我在docker邮件列表中发现了这个: http : //permalink.gmane.org/gmane.comp.sysutils.docker.user/3182

您可以通过传递lxc-conf参数“lxc.network.veth.pair”来定义veth的名称。 例如:

docker run -rm -i -t -lxc-conf =“lxc.network.veth.pair = foobar”ubuntu / bin / bash

创build一个名为“foobar”的veth接口的容器。

看到这个页面更方便的lxc-conf参数: http : //manpages.ubuntu.com/manpages/precise/man5/lxc.conf.5.html

试试这个脚本:

 get_network_mode() { docker inspect --format='{{.HostConfig.NetworkMode}}' "$1" } for container_id in $(docker ps -q); do network_mode=$(get_network_mode "${container_id}") # skip the containers whose network_mode is 'host' or 'none'. if [[ "${network_mode}" = "host" || "${network_mode}" = "none" ]]; then continue fi # if one container's network_mode is 'other container', # then get its root parent container's network_mode. while grep container <<< "${network_mode}" -q; do network_mode=$(get_network_mode "${network_mode/container:/}") # if one of its parent container's network_mode is 'host' or 'none' # then skip the current container. if [[ "${network_mode}" = "host" || "${network_mode}" = "none" ]]; then continue 2 fi done # get current container's 'container_id'. pid=$(docker inspect --format='{{.State.Pid}}' "${container_id}") # get the 'id' of veth device in the container. veth_id=$(nsenter -t "${pid}" -n ip link show eth0 |sed -nr 's/.*eth0@if([0-9]+).*/\1/p') # get the 'name' of veth device in the 'docker0' bridge, # which is the peer of veth device in the container. veth_name=$(ip link show |sed -nr "/^${veth_id}/s/.*(veth.*)@if.*/\1/p") echo "${container_id} => ${veth_name}" done 

解释:

  • 避免在container执行命令。
  • 避免创build临时文件夹和文件。
  • 最重要的是,避免为NetworkModehostnonecontainer:<name|id>获取不正确的答案container:<name|id> (与另一个容器共享network stack ,例如:kubernetes中一个容器中的user's容器与pause pod共享network stack pause pod容器的network stack

我不知道如何正确地得到它,但是你使用了一个黑客:在运行你的容器之后,你可以扫描系统日志中添加的接口:

 #!/bin/sh JOB=$(sudo docker run -d ...) sleep 1s INTERFACE=$(grep "docker0: port" /var/log/syslog | tail -n 1 | sed -rs/^.*\(veth[^\)]+\).*$/\\1/) echo "job: $JOB interface: $INTERFACE" 
 dmesg --clear for i in $(docker inspect $(docker ps -a -q) | grep IPAddress | cut -d\" -f4); do ping -c 1 -w 1 $i >/dev/null; done while read line do IPADDRESS=$(docker inspect $line | grep IPAddress | cut -d\" -f4) NAME=$(docker inspect $line | grep Name | cut -d/ -f2 | cut -d\" -f1) FOUND=$(dmesg | grep $IPADDRESS | grep -Po 'vet[A-Za-z0-9]+' | sort -u) echo "GEVONDEN $IPADDRESS MET NAAM : $NAME en INTERFACE: $FOUND" | grep NAAM done < <(docker ps -a -q)