可以借助ip netns命令来完成对 Network Namespace 的各种操作。ip netns命令来自于iproute安装包,一般系统会默认安装,如果没有的话,请自行安装。
注意:ip netns命令修改网络配置时需要 sudo 权限。
可以通过ip netns命令完成对Network Namespace 的相关操作,可以通过ip netns help查看命令帮助信息:
1 [root@localhost ~]# ip netns help 2 Usage: ip netns list # 查看名称空间 3 ip netns add NAME # 添加名称空间 4 ip netns attach NAME PID # 进到空间里去 5 ip netns set NAME NETNSID # 设置名称空间的名字 6 ip [-all] netns delete [NAME] # 删除 7 ip netns identify [PID] 8 ip netns pids NAME # pid 9 ip [-all] netns exec [NAME] cmd ... # 进到空间去并执行命令 10 ip netns monitor # 监控 11 ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT] 12 NETNSID := auto | POSITIVE-INT # 列出id
默认情况下,Linux系统中是没有任何 Network Namespace的,所以ip netns list命令不会返回任何信息。
通过命令创建一个名为ns0的命名空间:
1 [root@localhost ~]# ip netns add ns0 # 创建一个叫ns0的名称空间 2 [root@localhost ~]# ip netns list # 查看 3 ns0
新创建的 Network Namespace 会出现在/var/run/netns/目录下。如果相同名字的 namespace 已经存在,命令会报Cannot create namespace file "/var/run/netns/ns0": File exists的错误。
1 [root@localhost ~]# cd /var/run/netns/ # 进到存放名称空间的目录 2 [root@localhost netns]# ls 3 ns0 4 [root@localhost ~]# file /var/run/netns/ 5 /var/run/netns/: directory 6 [root@localhost ~]# file /var/run/netns/ns0 7 /var/run/netns/ns0: empty 8 [root@localhost ~]# touch /var/run/netns/ns1 9 [root@localhost ~]# file /var/run/netns/ns1 10 /var/run/netns/ns1: empty # touch出来的,看着都一样 11 [root@localhost ~]# ip netns list # 但是你查看就会报错 12 Error: Peer netns reference is invalid. 13 Error: Peer netns reference is invalid. # 必须要用命令创建, 14 ns1 15 ns0 16 [root@localhost ~]# ip netns add ns0 # 不能创建相同名字,会报错 17 Cannot create namespace file "/var/run/netns/ns0": File exists
对于每个 Network Namespace 来说,它会有自己独立的网卡、路由表、ARP 表、iptables 等和网络相关的资源。
ip命令提供了ip netns exec
子命令可以在对应的 Network Namespace 中执行命令。
查看新创建 Network Namespace 的网卡信息
1 [root@localhost ~]# ip netns exec ns0 ip a # 进到ns0查看网络信息 2 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000 # 就一块lo网卡,而且没有激活 3 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
可以看到,新创建的Network Namespace中会默认创建一个lo回环网卡,此时网卡处于关闭状态。此时,尝试去 ping 该lo回环网卡,会提示Network is unreachable
通过下面的命令启用lo回环网卡:
1 [root@localhost ~]# ip netns exec ns0 ping 127.0.0.1 # 进到ns0,ping自己 2 connect: 网络不可达 3 [root@localhost ~]# ip netns exec ns0 ip link set lo up # 进到ns0设置lo网卡启动 4 [root@localhost ~]# ip netns exec ns0 ip a 5 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 6 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 7 inet 127.0.0.1/8 scope host lo # 有id了激活了 8 valid_lft forever preferred_lft forever 9 inet6 ::1/128 scope host 10 valid_lft forever preferred_lft forever 11 [root@localhost ~]# ip netns exec ns0 ping 127.0.0.1 # 此时就ping的通 12 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 13 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=40.5 ms 14 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.062 ms 15 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.095 ms 16
[root@localhost ~]# ip netns exec ns1 ip link set lo up # 激活ns1的网卡
[root@localhost ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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 # 两个空间的本地网络通了,他们两个之间是不能通信的真机也不能和他们通信,内部是可以通信的,
我们可以在不同的 Network Namespace 之间转移设备(如veth)。由于一个设备只能属于一个 Network Namespace ,所以转移后在这个 Network Namespace 内就看不到这个设备了。
其中,veth设备属于可转移设备,而很多其它设备(如lo、vxlan、ppp、bridge等)是不可以转移的。
veth pair 全称是 Virtual Ethernet Pair(一对虚拟的以太网),是一个成对的端口,所有从这对端口一 端进入的数据包都将从另一端出来,反之也是一样。
引入veth pair是为了在不同的 Network Namespace 直接进行通信,利用它可以直接将两个 Network Namespace 连接起来。
1 [root@localhost ~]# ip link show # 此时只有3个网卡 2 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 3 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 4 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 5 link/ether 00:0c:29:bc:11:bf brd ff:ff:ff:ff:ff:ff 6 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 7 link/ether 02:42:e7:69:ef:af brd ff:ff:ff:ff:ff:ff 8 [root@localhost ~]# ip link add type veth # 生产了一对设备38: veth0 39: veth1而且是没有激活的状态 9 [root@localhost ~]# ip link show 10 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 11 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 12 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 13 link/ether 00:0c:29:bc:11:bf brd ff:ff:ff:ff:ff:ff 14 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 15 link/ether 02:42:e7:69:ef:af brd ff:ff:ff:ff:ff:ff 16 38: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 17 link/ether d2:62:7c:c0:44:7f brd ff:ff:ff:ff:ff:ff 18 39: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 19 link/ether 7e:b1:dd:27:56:87 brd ff:ff:ff:ff:ff:ff
可以看到,此时系统中新增了一对veth pair,将veth0和veth1两个虚拟网卡连接了起来,此时这对 veth pair 处于”未启用“状态。
下面我们利用veth pair实现两个不同的 Network Namespace 之间的通信。刚才我们已经创建了一个名为ns0的 Network Namespace,下面再创建一个信息Network Namespace,命名为ns1
然后我们将veth0加入到ns0,将veth1加入到ns1
然后我们分别为这对veth pair配置上ip地址,并启用它们
查看这对veth pair的状态
可以看到,veth pair成功实现了两个不同Network Namespace之间的网络交互
1 [root@localhost ~]# ip link set veth0 netns ns0 # 把veth0给ns0用 2 [root@localhost ~]# ip netns exec ns0 ip a 3 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 4 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 5 inet 127.0.0.1/8 scope host lo 6 valid_lft forever preferred_lft forever 7 inet6 ::1/128 scope host 8 valid_lft forever preferred_lft forever 9 38: veth0@if39: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 10 link/ether d2:62:7c:c0:44:7f brd ff:ff:ff:ff:ff:ff link-netnsid 0 11 [root@localhost ~]# ip netns exec ns0 ip link set veth0 up # 激活veth0 12 [root@localhost ~]# ip netns exec ns0 ip a # 此时已激活但是没有ip 13 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 14 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 15 inet 127.0.0.1/8 scope host lo 16 valid_lft forever preferred_lft forever 17 inet6 ::1/128 scope host 18 valid_lft forever preferred_lft forever 19 38: veth0@if39: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000 20 link/ether d2:62:7c:c0:44:7f brd ff:ff:ff:ff:ff:ff link-netnsid 0 21 [root@localhost ~]# ip netns exec ns0 ip addr add 1.1.1.1/24 dev veth0 # 给veth0手动配一个ip 22 [root@localhost ~]# ip netns exec ns0 ip a 23 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 24 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 25 inet 127.0.0.1/8 scope host lo 26 valid_lft forever preferred_lft forever 27 inet6 ::1/128 scope host 28 valid_lft forever preferred_lft forever 29 38: veth0@if39: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000 30 link/ether d2:62:7c:c0:44:7f brd ff:ff:ff:ff:ff:ff link-netnsid 0 31 inet 1.1.1.1/24 scope global veth0 #此时已经有ip 32 valid_lft forever preferred_lft forever 33 [root@localhost ~]# ip link show # 把veht0给了ns0,所以真机这里就没有了 34 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 35 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 36 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 37 link/ether 00:0c:29:bc:11:bf brd ff:ff:ff:ff:ff:ff 38 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default 39 link/ether 02:42:e7:69:ef:af brd ff:ff:ff:ff:ff:ff 40 39: veth1@if38: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 41 link/ether 7e:b1:dd:27:56:87 brd ff:ff:ff:ff:ff:ff link-netns ns0 42 [root@localhost ~]# ip link set veth1 up # 激活veth1 43 [root@localhost ~]# ip addr add 1.1.1.2/24 dev veth1 # 给veth1设置ip 44 [root@localhost ~]# ping 1.1.1.1 # ping的通 45 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 46 64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=17.3 ms 47 64 bytes from 1.1.1.1: icmp_seq=2 ttl=64 time=0.057 ms 48 [root@localhost ~]# ip link set veth1 netns ns1 # 把veth1给ns1用 49 [root@localhost ~]# ip netns exec ns1 ip a 50 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 51 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 52 inet 127.0.0.1/8 scope host lo 53 valid_lft forever preferred_lft forever 54 inet6 ::1/128 scope host 55 valid_lft forever preferred_lft forever 56 39: veth1@if38: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 # 移过的时候会禁用掉,ip也没了 57 link/ether 7e:b1:dd:27:56:87 brd ff:ff:ff:ff:ff:ff link-netns ns0 58 [root@localhost ~]# ip netns exec ns1 ip link set veth1 up # 启动veth1 59 [root@localhost ~]# ip netns exec ns1 ip addr add 1.1.1.2/24 dev veth1 # 给veth1配置ip 60 [root@localhost ~]# ip netns exec ns1 ip a 61 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 62 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 63 inet 127.0.0.1/8 scope host lo 64 valid_lft forever preferred_lft forever 65 inet6 ::1/128 scope host 66 valid_lft forever preferred_lft forever 67 39: veth1@if38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 68 link/ether 7e:b1:dd:27:56:87 brd ff:ff:ff:ff:ff:ff link-netns ns0 69 inet 1.1.1.2/24 scope global veth1 # 此时veth有ip了 70 valid_lft forever preferred_lft forever 71 inet6 fe80::7cb1:ddff:fe27:5687/64 scope link 72 valid_lft forever preferred_lft forever 73 [root@localhost ~]# ip netns exec ns1 ping 1.1.1.1 # 进到ns1,去ping1.1.1.1,能通说明ns1和ns0可以通信 74 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 75 64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=6.30 ms 76 64 bytes from 1.1.1.1: icmp_seq=2 ttl=64 time=0.076 ms 77 64 bytes from 1.1.1.1: icmp_seq=3 ttl=64 time=0.077 ms
1 [root@localhost ~]# ip netns exec ns0 ip link show # 两个veth的设备名字不一样 2 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 3 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 4 38: veth0@if39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 5 link/ether d2:62:7c:c0:44:7f brd ff:ff:ff:ff:ff:ff link-netns ns1 6 [root@localhost ~]# ip netns exec ns1 ip link show 7 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 8 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 9 39: veth1@if38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 10 link/ether 7e:b1:dd:27:56:87 brd ff:ff:ff:ff:ff:ff link-netns ns0 11 [root@localhost ~]# ip netns exec ns0 ip link set veth0 down # 停掉veth0 才能操作改名 12 [root@localhost ~]# ip netns exec ns0 ip link set dev veth0 name eth0 # 把veth0的名字改成eth0 13 [root@localhost ~]# ip netns exec ns0 ip link set eth0 up # 启动eth0 14 [root@localhost ~]# ip netns exec ns1 ip link set veth1 down # 停掉veth1 15 [root@localhost ~]# ip netns exec ns1 ip link set dev veth1 name eth0 # 把veth1的名字改成eth0 16 [root@localhost ~]# ip netns exec ns1 ip link set eth0 up # 启动 17 [root@localhost ~]# ip netns exec ns1 ping 1.1.1.1 # 也能通 18 PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data. 19 64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.121 ms 20 64 bytes from 1.1.1.1: icmp_seq=2 ttl=64 time=0.103 ms 21 64 bytes from 1.1.1.1: icmp_seq=3 ttl=64 time=0.067 ms 22 # 改名字不会影响设置的ip,但是需要先停掉,改好再启动。容器会自动分配ip,并且和docker0网桥在同一个网段,会虚拟一对veth设备一个放在容器,一个放在我们的真机上。 23 24
1 [root@localhost ~]# docker run -it --rm busybox # 桥接是默认的,不用network也可以 2 / # ifconfig 3 eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 4 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 5 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 6 RX packets:9 errors:0 dropped:0 overruns:0 frame:0 7 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 8 collisions:0 txqueuelen:0 9 RX bytes:806 (806.0 B) TX bytes:0 (0.0 B) 10 11 lo Link encap:Local Loopback 12 inet addr:127.0.0.1 Mask:255.0.0.0 13 UP LOOPBACK RUNNING MTU:65536 Metric:1 14 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 15 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 16 collisions:0 txqueuelen:1000 17 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) 18 [root@localhost ~]# docker run -it --network bridge busybox 19 / # ifconfig 20 eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 21 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 22 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 23 RX packets:10 errors:0 dropped:0 overruns:0 frame:0 24 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 25 collisions:0 txqueuelen:0 26 RX bytes:876 (876.0 B) TX bytes:0 (0.0 B) 27 28 lo Link encap:Local Loopback 29 inet addr:127.0.0.1 Mask:255.0.0.0 30 UP LOOPBACK RUNNING MTU:65536 Metric:1 31 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 32 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 33 collisions:0 txqueuelen:1000 34 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
[root@localhost ~]# docker run -it --rm --network none busybox / # ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 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:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) # 指定none模式就只有一块lo网卡,没有其他网卡和ip,无法和外界通信
启动第一个容器
1 [root@localhost ~]# docker run -it --rm --name b1 busybox 2 / # ip a 3 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 4 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 5 inet 127.0.0.1/8 scope host lo 6 valid_lft forever preferred_lft forever 7 50: eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 8 link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff 9 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 10 valid_lft forever preferred_lft forever 11 # 先启动一个正常的容器取名b1,然后在启动一个容器指定容器模式 12 和b1一样。 13 [root@localhost ~]# docker run -it --rm --network container:b1 busybox 14 / # ip a 15 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 16 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 17 inet 127.0.0.1/8 scope host lo 18 valid_lft forever preferred_lft forever 19 50: eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 20 link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff 21 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 22 valid_lft forever preferred_lft forever
1 没有名字的容器下面创建一个data目录 2 / # ls 3 bin dev etc home proc root sys tmp usr var 4 / # mkdir data 5 / # ls 6 bin data dev etc home proc root sys tmp usr var 7 / # 8 b1容器查看不到 9 / # ls 10 bin dev etc home proc root sys tmp usr var 11 共享IP,但不共享文件系统,因为文件系统是处于隔离状态,仅仅是共享了网络而已 12 / # echo 'hello world' > data/index.html # 没有名字的容器里再跑一个容器 13 / # /bin/httpd -h /data 14 / # netstat -antl 15 Active Internet connections (servers and established) 16 Proto Recv-Q Send-Q Local Address Foreign Address State 17 tcp 0 0 :::80 :::* LISTEN 18 / # wget -O - -q 127.0.0.1 # b1可以访问到,应为他们用的是同一个ip 19 hello world
启动容器时直接指明模式为host
[root@localhost ~]# docker run -it --rm --network host busybox / # ip a # 指定主机模式用的都是主机的ip 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 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 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel qlen 1000 link/ether 00:0c:29:bc:11:bf brd ff:ff:ff:ff:ff:ff inet 192.168.149.130/24 brd 192.168.149.255 scope global noprefixroute ens33 valid_lft forever preferred_lft forever 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue link/ether 02:42:e7:69:ef:af brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:e7ff:fe69:efaf/64 scope link valid_lft forever preferred_lft forever / #
此时如果我们在这个容器中启动一个http站点,我们就可以直接用宿主机的IP直接在浏览器中访问这个容器中的站点了。
1 [root@localhost ~]# docker run -it --rm busybox 2 / # hostname #查看主机名 默认情况下主机名和容器id一样 ,容器里面是只读层,改不了名字,只能在容器启动的时候注入主机名 3 6bd0cb733cbf 4 [root@localhost ~]# docker ps -a 5 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6 6bd0cb733cbf busybox "sh" 36 seconds ago Up 35 seconds inspiring_margulis 7
1 [root@localhost ~]# docker run -it --rm --hostname node1 busybox 2 / # hostname 3 node1 4 / # cat /etc/hostname 5 node1 6 / # cat /etc/hosts 7 127.0.0.1 localhost 8 ::1 localhost ip6-localhost ip6-loopback 9 fe00::0 ip6-localnet 10 ff00::0 ip6-mcastprefix 11 ff02::1 ip6-allnodes 12 ff02::2 ip6-allrouters 13 172.17.0.2 node1 14 / # mkdir data 15 / # echo 'hello world' > /data/index.html 16 / # /bin/httpd -h /data/ 17 / # netstat -antl 18 Active Internet connections (servers and established) 19 Proto Recv-Q Send-Q Local Address Foreign Address State 20 tcp 0 0 :::80 :::* LISTEN 21 / # wget -O - -q node1 # 用主机名也可以访问,因为有映射关系 22 hello world
1 / # cat /etc/resolv.conf # 默认的dns 2 # Generated by NetworkManager 3 nameserver 114.114.114.114 4 [root@localhost ~]# docker run -it --rm --hostname node1 --dns 8.8.8.8 busybox # 手动设置改变dns 5 / # cat /etc/resolv.conf 6 nameserver 8.8.8.8
7 / # mkdir /data
8 / # echo 'hello world' > data/index.html
9 / # /bin/httpd -f -h /data/
[root@localhost ~]# docker run -it --rm --hostname node2 --add-host node1:172.17.0.2 busybox # 注入主机名ip地址的映射 / # 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 node1 # 有映射关系了 172.17.0.3 node2 / # wget -O - -q http://node1 # 可以用主机名访问 hello world [root@localhost ~]# docker run -it --rm --hostname node2 --add-host node1:172.17.0.2 --add-host test1:1.1.1.1 --add-host test2:2.2.2.2 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 172.17.0.2 node1 1.1.1.1 test1 2.2.2.2 test2 172.17.0.3 node2
执行docker run的时候有个-p选项,可以将容器中的应用端口映射到宿主机中,从而实现让外部主机可以通过访问宿主机的某端口来访问容器内应用的目的。
-p选项能够使用多次,其所能够暴露的端口必须是容器确实在监听的端口。
-p选项的使用格式:
动态端口指的是随机端口,具体的映射结果可使用docker port命令查看。
[root@localhost ~]# docker run -d --rm --name web -p 80 httpd 04fde3b15e0c79356371ed6fd460c707b3d880f196a7452267fdf1bfa3bf9c23 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 04fde3b15e0c httpd "httpd-foreground" 8 seconds ago Up 7 seconds 0.0.0.0:49153->80/tcp, :::49153->80/tcp web 将指定的容器端口映射至主机所有地址的一个动态端口 [root@localhost ~]# docker run -d --rm --name web -p 80:80 httpd 71765be95b82e4fceb1a9c59a69c1097288e849f159326140016faa0d8803d0b [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 71765be95b82 httpd "httpd-foreground" 6 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp web 将容器80端口号映射到主机80端口号 [root@localhost ~]# ip addr add 192.168.149.250/24 dev ens33 [root@localhost ~]# ip a # 在ens33上增加一个250的ip,现在有两个 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 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 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 00:0c:29:bc:11:bf brd ff:ff:ff:ff:ff:ff inet 192.168.149.130/24 brd 192.168.149.255 scope global noprefixroute ens33 valid_lft forever preferred_lft forever inet 192.168.149.250/24 scope global secondary ens33 valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:e7:69:ef:af brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:e7ff:fe69:efaf/64 scope link valid_lft forever preferred_lft forever 65: veth558e8bf@if64: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 9e:42:d0:82:60:31 brd ff:ff:ff:ff:ff:ff link-netnsid 2 inet6 fe80::9c42:d0ff:fe82:6031/64 scope link valid_lft forever preferred_lft forever [root@localhost ~]# docker run -d --name web --rm -p 192.168.149.130::80 httpd # 只暴露在130ip上,随机的 741e0771eb296333442514b508ee3476898820b44de58093c0147bd205331771 [root@localhost ~]# ss -antl State Recv-Q Send-Q Local Address:Port Peer Address:Port Process LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 128 192.168.149.130:49153 0.0.0.0:* LISTEN 0 128 [::]:22 [::]:* 将指定的容器端口<containerPort>映射至主机指定<ip>的动态端口 [root@localhost ~]# docker run -d --name web --rm -p 192.168.149.130:8080:80 httpd c4e8aa8ea2456d8503e1d305dfa24c3aa3ada4b19d24e68b82ffac442a3988a1 [root@localhost ~]# ss -antl State Recv-Q Send-Q Local Address:Port Peer Address:Port Process LISTEN 0 128 192.168.149.130:8080 0.0.0.0:* LISTEN 0 128 0.0.0.0:22 0.0.0.0:* LISTEN 0 128 [::]:22 [::]:* 将指定的容器端口<containerPort>映射至主机指定<ip>的端口<hostPort>
以上命令执行后会一直占用着前端,我们新开一个终端连接来看一下容器的80端口被映射到了宿主机的什么端口上
[root@localhost ~]# docker port web 80/tcp -> 0.0.0.0:32769