docker容器网络配置

文章目录

    • Linux内核实现名称空间的创建
      • 创建Network Namespace
      • 操作Network Namespace
      • 转移设备
      • 创建veth pair
      • 实现Network Namespace间通信
      • veth设备重命名
    • 容器的常用操作
      • 查看容器主机名
      • 在容器启动时注入主机名
      • 手动指定容器要使用的DNS
      • 手动往/etc/hosts文件中注入主机名到IP地址的映射
      • 开放容器端口

Linux内核实现名称空间的创建

创建Network Namespace

通过命令创建一个名为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 等和网络相关的资源。

操作Network Namespace

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等)是不可以转移的。

创建veth pair

[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

实现Network Namespace间通信

下面我们利用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

veth设备重命名

[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

手动指定容器要使用的DNS

[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

手动往/etc/hosts文件中注入主机名到IP地址的映射

[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选项的使用格式:

  • -p
    将指定的容器端口映射至主机所有地址的一个动态端口
  • -p :
    将容器端口映射至指定的主机端口
  • -p ::
    将指定的容器端口映射至主机指定的动态端口
  • -p ::
    将指定的容器端口映射至主机指定的端口

动态端口指的是随机端口,具体的映射结果可使用docker port命令查看。

你可能感兴趣的:(Linux课程)