通过命令创建一个名为ns0的命名空间:
[root@docker ~]# ip netns list
[root@docker ~]# ip netns add ns0
[root@docker ~]# ip netns list
ns0
新创建的 Network Namespace 会出现在/var/run/netns/目录下。如果相同名字的 namespace 已经存在,命令会报Cannot create namespace file “/var/run/netns/ns0”: File exists的错误。
[root@docker ~]# ls /var/run/netns/
ns0
[root@docker ~]# ip netns add ns0
Cannot create namespace file "/var/run/netns/ns0": File exists
对于每个 Network Namespace 来说,它会有自己独立的网卡、路由表、ARP 表、iptables 等和网络相关的资源。
ip命令提供了ip netns exec子命令可以在对应的 Network Namespace 中执行命令。
查看新创建 Network Namespace 的网卡信息
root@docker ~]# ip netns exec ns0 ip addr
1: lo: mtu 65536 qdisc noop state DOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
可以看到,新创建的Network Namespace中会默认创建一个lo回环网卡,此时网卡处于关闭状态。此时,尝试去 ping 该lo回环网卡,会提示Network is unreachable
[root@docker ~]# ip netns exec ns0 ping 127.0.0.1
connect: Network is unreachable
通过下面的命令启用lo回环网卡:
[root@docker ~]# ip netns exec ns0 ip link set lo up
[root@docker ~]# ip netns exec ns0 ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.099 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.077 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.078 ms
我们可以在不同的 Network Namespace 之间转移设备(如veth)。由于一个设备只能属于一个 Network Namespace ,所以转移后在这个 Network Namespace 内就看不到这个设备了。
其中,veth设备属于可转移设备,而很多其它设备(如lo、vxlan、ppp、bridge等)是不可以转移的。
[root@docker ~]# ip link add type veth
[root@docker ~]# ip a
36: veth0@veth1: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 42:a8:5e:58:b7:1d brd ff:ff:ff:ff:ff:ff
37: veth1@veth0: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 8e:4e:f5:7e:7e:b8 brd ff:ff:ff:ff:ff:ff
下面我们利用veth pair实现两个不同的 Network Namespace 之间的通信。刚才我们已经创建了一个名为ns0的 Network Namespace,下面再创建一个信息Network Namespace,命名为ns1
[root@docker ~]# ip netns add ns1
[root@docker ~]# ip netns list
ns1
ns0
然后我们将veth0加入到ns0,将veth1加入到ns1
[root@docker ~]# ip link set veth0 netns ns0
[root@docker ~]# ip link set veth1 netns ns1
然后我们分别为这对veth pair配置上ip地址,并启用它们
[root@docker ~]# ip netns exec ns0 ip link set veth0 up
[root@docker ~]# ip netns exec ns0 ip addr add 10.0.0.1/24 dev veth0
[root@docker ~]# ip netns exec ns1 ip link set veth1 up
[root@docker ~]# ip netns exec ns1 ip addr add 10.0.0.1/24 dev veth1
[root@docker ~]# ip netns exec ns1 ip link set lo up
查看这对veth pair的状态
[root@docker ~]# ip netns exec ns0 ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
36: veth0@if37: mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 42:a8:5e:58:b7:1d brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 10.0.0.1/24 scope global veth0
valid_lft forever preferred_lft forever
inet6 fe80::40a8:5eff:fe58:b71d/64 scope link
valid_lft forever preferred_lft forever
[root@docker ~]# ip netns exec ns1 ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
37: veth1@if36: mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 8e:4e:f5:7e:7e:b8 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.0.0.1/24 scope global veth1
valid_lft forever preferred_lft forever
inet6 fe80::8c4e:f5ff:fe7e:7eb8/64 scope link
valid_lft forever preferred_lft forever
从上面可以看出,我们已经成功启用了这个veth pair,并为每个veth设备分配了对应的ip地址。我们尝试在ns1中访问ns0中的ip地址:
[root@docker ~]# ip netns exec ns1 ping 10.0.0.1
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.086 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.060 ms
[root@docker ~]# ip netns exec ns0 ifconfig -a
eth0: flags=4098 mtu 1500
inet 10.0.0.1 netmask 255.255.255.0 broadcast 0.0.0.0
ether 42:a8:5e:58:b7:1d txqueuelen 1000 (Ethernet)
RX packets 8 bytes 648 (648.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 648 (648.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 1 (Local Loopback)
RX packets 10 bytes 840 (840.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 10 bytes 840 (840.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@docker ~]# ip netns exec ns0 ip link set eth0 up
[root@salt1 ~]# docker run -it --name t1 --network bridge --rm busybox
/ # hostname
2caa42691e68
[root@salt1 ~]# docker run -it --name t1 --network bridge --hostname hello --rm busybox
/ # hostname
hello
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 hello //注入主机名时会自动创建主机命名到IP映射关系
/ # cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 114.114.114.114 //DNS也会自动配置为宿主机的DNS
/ # ping www.baidu.com
PING www.baidu.com (39.156.66.18): 56 data bytes
64 bytes from 39.156.66.18: seq=0 ttl=127 time=63.355 ms
64 bytes from 39.156.66.18: seq=1 ttl=127 time=54.062 ms
64 bytes from 39.156.66.18: seq=2 ttl=127 time=52.691 ms
[root@salt1 ~]# docker run -it --name t1 --network bridge --hostname hello --dns 192.168.174.2 --rm busybox
/ # cat /etc/resolv.conf
nameserver 192.168.174.2
/ # nslookup -type=a www.baidu.com
Server: 192.168.174.2
Address: 192.168.174.2:53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 39.156.66.14
Name: www.a.shifen.com
Address: 39.156.66.18
[root@salt1 ~]# docker run -it --name t1 --network bridge --hostname hello --add-host www.a.com:1.1.1.1 --rm busybox
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
1.1.1.1 www.a.com
172.17.0.2 hello
执行docker run的时候有个-p选项,可以将容器中的应用端口映射到宿主机中,从而实现让外部主机可以通过访问宿主机的某端口来访问容器内应用的目的。
-p选项能够使用多次,其所能够暴露的端口必须是容器确实在监听的端口。
-p选项的使用格式:
动态端口指的是随机端口,具体的映射结果可使用docker port命令查看。