docker网络访问
Table of Contents
1 安装docker
1.1 Mac
Mac上可以去 官网 上下载一个docker.img文件,然后直接安装就可以了。启 动后,命令行下自动就会有docker命令。
1.2 ubuntu
ubuntu14.04上,docekr的安装包名字不叫docker,而是叫 docker.io 。
所以需要这样安装:
sudo apt-get install -susdo docker.io
安装好后,需要把当前用户加入docker组内:
sudo usermod -a -G docker <username>
重新登陆后,启动docker服务即可:
sudo service docker start
2 如何访问docker中的容器
拉起ras容器很简单:
docker run -d xxx:xxx
重点是解决如何在“外部”访问容器。也就是网络方面的问题。Mac上通过端 口映射的方式太“原始”。在纯Linux的环境中,可以有更好的选择。
Linux下默认docker使用的网络结构如下图所示:
    +------------------------------------------------------------------------+
    |                             Host                                       |
    |                                                                        |
    |     +------------------+                     +------------------+      |
    |     |                  |                     |                  |      |
    |     |                  |                     |                  |      |
    |     |    Container1    |                     |    Container2    |      |
    |     |                  |                     |                  |      |
    |     |    +--------+    |                     |    +--------+    |      |
    |     |    |  eth0  |    |                     |    |  eth0  |    |      |
    |     +----+---+----+----+                     +----+----+---+----+      |
    |              ^  172.17.42.2                            ^  172.17.42.3  |
    |              |                                         |               |
    |              |                                         |               |
    |              |                                         |               |
    |              |                                         |               |
    |              v                                         v               |
    |          +---+-----+                              +----+----+          |
    |          |         |                              |         |          |
    |     +----+ vethXX  +------------------------------+ vethYY  +----+     |
    |     |    |         |                              |         |    |     |
    |     |    +---------+           docker0            +---------+    |     | 
    |     |                       +------------+                       |     |
    |     +-----------------------+  docker0   +-----------------------+     |
    |                             +-----+------+ 172.17.42.1/16              |
    |                                                                        |
    |                       +--------------------------+                     |
    +-----------------------|         eth0             |---------------------+
                            +--------------------------+
                                                 10.10.10.1
默认情况下会新建一个名叫 docker0 的网桥。可以理解为 docker0 就是
Linux在内部使用软件虚拟出了一个交换机。拉起的容器中的 eth0 都通过
特殊的技术(veth pair 可以参考 veth )连接在这个交换机上。这样,宿主机
和容器以及容器和容器之间都可以相互通信。如上图所示的,172网段也就是
该宿主机中的虚拟网络。容器中如果需要访问外部10网段,可以通过NAT来实
现。
但是这样 会导致宿主机以外的机器不能访问到容器。为了实现“外部”也可以 访问容器。我们可以这样设计:
    +------------------------------------------------------------------------+
    |                             Host                                       |
    |                                                                        |
    |     +------------------+                     +------------------+      |
    |     |                  |                     |                  |      |
    |     |                  |                     |                  |      |
    |     |    Container1    |                     |    Container2    |      |
    |     |                  |                     |                  |      |
    |     |    +--------+    |                     |    +--------+    |      |
    |     |    |  eth0  |    |                     |    |  eth0  |    |      |
    |     +----+---+----+----+                     +----+----+---+----+      |
    |              ^  10.10.10.2                             ^  10.10.10.3   |
    |              |                                         |               |
    |              |                                         |               |
    |              |                                         |               |
    |              |                                         |               |
    |              v                                         v               |
    |          +---+-----+                              +----+----+          |
    |          |         |                              |         |          |
    |     +----+ vethXX  +------------------------------+ vethYY  +----+     |
    |     |    |         |                              |         |    |     |
    |     |    +---------+         bridge-eth0          +---------+    |     | 
    |     |                     +---------------+                      |     |
    |     +---------------------+  bridge-eth0  +----------------------+     |
    |                           +---------------+                            |
    |                                   ^   10.10.10.1                       |
    |                                   |                                    |
    |                                   v                                    |
    |                       +-----------+--------------+                     |
    +-----------------------|         eth0             |---------------------+
                            +--------------------------+                   
- 把宿主机上的eth0网卡用的ip地址“移”到网桥上 
bridge-eth0。 - 设置宿主机中的eth0网卡也连到 
bridge-eth0上。 - 配置docker服务使用名为 
bridge-eth0的网桥。 
下面的脚本接受一个 <interface> 参数。实现如下功能:
- 新建一个名为 
bridge-<interface-name>的网桥。 - 把原来 
<interface>的ip地址分配给了bridge-<interface-name>。 - 把原来 
<interface>的连到bridge-<interface-name>网桥。 
#!/bin/bash moveHostIntf(){ IFINDEX=$1 BRIDGE=bridge-$IFINDEX bridge link show|cut -d\ -f 2|grep "^$IFINDEX\$" #brctl show $BRIDGE | grep "\<$IFINDEX\>" >/dev/null if [ $? = 0 ];then echo "host interface $IFINDEX already in bridge $BRIDGE" return 1 fi #save route table related to this interface myRoute=$(ip route show scope global dev $IFINDEX | while read dst via gw;do if [ "$via" = "via" ]; then echo "route add -net $dst gw $gw";fi;done;) #save IP of this interface myIp=$(getIpAddr $IFINDEX) brctl addbr $BRIDGE ip addr flush dev $IFINDEX brctl addif $BRIDGE $IFINDEX #restore IP of the old interface to new one ifconfig $BRIDGE $myIp #restore route table related to this interface for r in "$myRoute";do $r done } getIpAddr(){ ip addr show $1|grep -o "inet [^[:space:]]*"|cut -d\ -f2 } moveHostIntf $1
最后配置docker使用名为 bridge-<interface-name> 网桥,需要先停止
docker服务:
sudo service docker stop
修改docker配置文件 /etc/default/docker ,加入这句:
    DOCKER_OPTS="-b=bridge-eth0"
最后该文件可能看起来像这样:
    # Here in Debian, this file is sourced by:
    #   - /etc/init.d/docker (sysvinit)
    #   - /etc/init/docker (upstart)
    #   - systemd's docker.service
    # Use of this file for configuring your Docker daemon is discouraged.
    # The recommended alternative is "/etc/docker/daemon.json", as described in:
    #   https://docs.docker.com/v1.11/engine/reference/commandline/daemon/#daemon-configuration-file
    # If that does not suit your needs, try a systemd drop-in file, as described in:
    #   https://docs.docker.com/v1.11/engine/admin/systemd/#custom-docker-daemon-options
    DOCKER_OPTS="-b=bridge-eth0"
这样拉起的容器,就可以分到10网段的ip地址。它们也就暴露在外部网络中了。
这样再拉起ras容器后,可以直接通过ip来访问了。比如这里两个容器就可以
分别用 http://10.10.10.2:80 和 http://10.10.10.3:80 访问对应容器
的端口。
3 TODO Mac上使用
由于Mac上的一些限制(没有网桥这个概念,host不通ping通容器),目前Mac 上拉起vm后,只能通过端口映射的方式访问拉起的vm :(
docker run -d -p 20145:20145 -p 20146:20146 -p 20147:20147 -p 20148:20148 -p 20149:20149 -p 20150:20150 -p 20151:20151 -p 20152:20152 -p 20153:20153 -p 20154:20154 -p 20155:20155 -p 20156:20156 -p 20157:20157 -p 20158:20158 -p 20159:20159 -p 20160:20160 xxx:2.2.4