docker 指定IP地址、与主机同网段IP
首先讲一下docker的网络模式:
我们使用docker run创建容器时,可以使用--net选项指定容器的网络模式,docker一共有4中网络模式:
1:bridge模式,--net=bridge(默认)。
这是dokcer网络的默认设置。安装完docker,系统会自动添加一个供docker使用的网桥docker0,我们创建一个新的容器时,容器通过dhcp获取一个与docker0同网段的ip地址。并默认连接到docker0网桥,以此实现容器与宿主机的网络互通。如下:
2:host模式,--net=host。
这个模式下创建出来的容器,将不拥有自己独立的network namespace,即没有独立的网络环境。它使用宿主机的ip和端口。
3:container模式,--net=container:name_or_id。
这个模式就是指定一个已有的容器,共享该容器的ip和端口。除了网络方面两个容器共享,其他的如文件系统,进程等还是隔离开的。
4:none模式,--net=none。
这个模式下,dokcer不为容器进行任何网络配置。需要我们自己为容器添加网卡,配置ip。
因此,若想使用pipework配置docker容器的ip地址,必须要在none模式下才可以
以下是几种分配ip的方式:
一、pipework
首先讲一下docker的网络模式:
我们使用docker run创建容器时,可以使用--net选项指定容器的网络模式,docker一共有4中网络模式:
1:bridge模式,--net=bridge(默认)。
这是dokcer网络的默认设置。安装完docker,系统会自动添加一个供docker使用的网桥docker0,我们创建一个新的容器时,容器通过dhcp获取一个与docker0同网段的ip地址。并默认连接到docker0网桥,以此实现容器与宿主机的网络互通。如下:
2:host模式,--net=host。
这个模式下创建出来的容器,将不拥有自己独立的network namespace,即没有独立的网络环境。它使用宿主机的ip和端口。
3:container模式,--net=container:name_or_id。
这个模式就是指定一个已有的容器,共享该容器的ip和端口。除了网络方面两个容器共享,其他的如文件系统,进程等还是隔离开的。
4:none模式,--net=none。
这个模式下,dokcer不为容器进行任何网络配置。需要我们自己为容器添加网卡,配置ip。
因此,若想使用pipework配置docker容器的ip地址,必须要在none模式下才可以。
pipework安装:
# wget https://github.com/jpetazzo/pipework/archive/master.zip # unzip pipework-master.zip # cp pipework-master/pipework /usr/local/bin/ # chmod +x /usr/local/bin/pipework 创建none模式的容器,为其分配ip。 #ip a show docker0 #docker run -idt --name test --net=none resin #pipework docker0 test 172.17.42.100/16@172.17.42.1 #docker attach test
以上操作给新建的test容器分配了一个172.17.42.100的ip地址。
二、 docker默认使用'bridge'来设置container的网络模式(即从与docker0同网段的未使用的ip中取一个作为container的ip),我们这里使用'none'来实现自己手动配置container的网络。
首先我们以**--net='none'**的方式启动一个container
[yaxin@cube2x ~]$docker run -i -t --rm --net='none' ubuntu /bin/bash root@db84e747c362:/# ifconfig -a lo link encap:local loopback inet addr:127.0.0.1 mask:255.0.0.0 inet6 addr: ::1/128 scope:host up loopback running mtu:65536 metric:1 rx packets:0 errors:0 dropped:0 overruns:0 frame:0 tx packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 rx bytes:0 (0.0 b) tx bytes:0 (0.0 b) root@db84e747c362:/#
可以看到,由于我们使用'none'模式,container中没有获取到ip,甚至连网卡都没有,下面我们开始给container配置ip
首先获取container的pid(我们需要通过pid获取file descriptor)
[yaxin@cube2x ~]$docker ps container id image command created status ports names db84e747c362 docker.cn/docker/ubuntu:latest "/bin/bash" 4 minutes ago up 4 minutes sharp_kirch [yaxin@cube2x ~]$docker inspect -f "{{.state.pid}}" sharp_kirch 23090
ip-netns的man page中有这样一句
by convention a named network namespace is an object at /var/run/netns/name that can be opened. the file descriptor resulting from opening/var/run/netns/name refers to the specified network namespace
因而我们需要创建一个链接
[yaxin@cube2x ~]$sudo ln -s /proc/23090/ns/net /var/run/netns/23090
然后创建一对端到端的网卡,将veth_db84e747c3绑定到docker0网桥,并启动。将另一块网卡x放到container内部
[yaxin@cube2x ~]$sudo ip link add veth_db84e747c3 type veth peer name x [yaxin@cube2x ~]$sudo brctl addif docker0 veth_db84e747c3 [yaxin@cube2x ~]$sudo ip link set veth_db84e747c3 up [yaxin@cube2x ~]$sudo ip link set x netns 23090
这时查看container的ip,会发现多了一个名为x的网卡
root@db84e747c362:/# ifconfig -ax link encap:ethernet hwaddr 5a:7e:4d:ba:63:1c broadcast multicast mtu:1500 metric:1 rx packets:0 errors:0 dropped:0 overruns:0 frame:0 tx packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 rx bytes:0 (0.0 b) tx bytes:0 (0.0 b) lo link encap:local loopback inet addr:127.0.0.1 mask:255.0.0.0 inet6 addr: ::1/128 scope:host up loopback running mtu:65536 metric:1 rx packets:0 errors:0 dropped:0 overruns:0 frame:0 tx packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 rx bytes:0 (0.0 b) tx bytes:0 (0.0 b)
然后对container内部新添加的网卡进行配置(可以通过man ip-netns更详细查看)
[yaxin@cube2x ~]$sudo ip netns exec 23090 ip link set dev x name eth0 [yaxin@cube2x ~]$sudo ip netns exec 23090 ip link set eth0 up [yaxin@cube2x ~]$sudo ip netns exec 23090 ip addr add 172.17.111.10/16 dev eth0 [yaxin@cube2x ~]$sudo ip netns exec 23090 ip route add default via 172.17.42.1
注意: 指定给container的ip必须跟docker0在同一网段,且给container的网关应该为docker0的ip
最后,写成shell脚本如下:
#!/usr/bin/env bash# filename: bind_addr.sh if [ `id -u` -ne 0 ];then echo '必须使用root权限' exitfi if [ $# != 2 ]; then echo "使用方法: $0 容器名字 ip" exit 1fi container_name=$1bind_ip=$2 container_id=`docker inspect -f '{{.id}}' $container_name 2> /dev/null` if [ ! $container_id ];then echo "容器不存在" exit 2fibind_ip=`echo $bind_ip | egrep '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'` if [ ! $bind_ip ];then echo "ip地址格式不正确" exit 3fi container_minid=`echo $container_id | cut -c 1-10` container_netmask=`ip addr show docker0 | grep "inet\b" | awk '{print $2}' | cut -d / -f2` container_gw=`ip addr show docker0 | grep "inet\b" | awk '{print $2}' | cut -d / -f1` bridge_name="veth_$container_minid" container_ip=$bind_ip/$container_netmask pid=`docker inspect -f '{{.state.pid}}' $container_name 2> /dev/null` if [ ! $pid ];then echo "获取容器$container_name的id失败" exit 4fi if [ ! -d /var/run/netns ];then mkdir -p /var/run/netns fi ln -sf /proc/$pid/ns/net /var/run/netns/$pid ip link add $bridge_name type veth peer name x brctl addif docker0 $bridge_name ip link set $bridge_name up ip link set x netns $pid ip netns exec $pid ip link set dev x name eth0 ip netns exec $pid ip link set eth0 up ip netns exec $pid ip addr add $container_ip dev eth0 ip netns exec $pid ip route add default via $container_gw 运行并写入ip和容器名称 配置容器与主机ip同一网段 先配置主机br0 vi /etc/sysconfig/network-scripts/ifcfg-br0 device=br0 type=bridge bootproto=static onboot=yes delay=0 stp=yes ipaddr=192.168.2.111 netmask=255.255.255.0 gateway=192.168.2.1 /etc/init.d/network restart docker run -itd --name test centos /bin/bash pipework br0 test 192.168.2.201/24@192.168.2.1
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。