容器的网络模型
虚拟网网络方面的知识看前面的虚拟化技术 docker支持的网络模式 bridge模式:--net=BRIDGE_NAME 创建一对虚拟网卡,一半在宿主机,一半在容器中,默认是--net=docker0 host模式:--net=host, container模式: none模式: 容器互联 在两个容器之间创建一个隧道,两个容器可以互相通信 --link 设计用来运行单一的程序,只为运行单一程序所需要的环境即可 集装箱:比如说客户需要运行java程序,我们只需将java文件,和java运行需要的环境打包成一个集装箱,用户拿到这个集装箱直接运行就可以运行,大大提高了运行的便捷性,
1、closed container:仅有一个回环网络接口,不参与网络通信,仅适用于无需网络通信的应用场景,例如备份,程序调试等
–network string Connect a container to a network (default "default")
[root@localhost ~]#docker run --rm --network none -it busybox:latest /bin/sh / # / # 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)
退出后container就删除
2、自定义ip
启动Docker容器的时候,使用默认的网络是不支持指派固定IP的,如下: docker run -itd --net bridge --ip 172.17.0.10 centos:latest /bin/bash 6eb1f228cf308d1c60db30093c126acbfd0cb21d76cb448c678bab0f1a7c0df6 docker: Error response from daemon: User specified IP address is supported on user defined networks only. 因此,需要创建自定义网络,下面是具体的步骤: 步骤1: 创建自定义网络 创建自定义网络,并且指定网段:172.18.0.0/16 docker network create --subnet=172.18.0.0/16 mynetwork docker network ls NETWORK ID NAME DRIVER SCOPE 9781b1f585ae bridge bridge local 1252da701e55 host host local 4f11ae9c85de mynetwork bridge local 237ea3d5cfbf none null local 步骤2: 创建Docker容器 docker run -itd --name networkTest1 --net mynetwork --ip 172.18.0.2 centos:latest /bin/bash 这个时候,创建的Docker容器就会持有 172.18.0.2 这个IP.
3、启动容器的时候设置容器的dns,就是启动的时候添加一个dns服务器地址
[root@localhost ~]#docker run -it --rm --name test --hostname=myhost --dns 192.168.175.2 centos:latest /bin/bash [root@myhost /]# [root@myhost /]# [root@myhost /]# ping www.baidu.com PING www.a.shifen.com (119.75.217.109) 56(84) bytes of data. 64 bytes from 119.75.217.109 (119.75.217.109): icmp_seq=1 ttl=127 time=3.91 ms 64 bytes from 119.75.217.109 (119.75.217.109): icmp_seq=2 ttl=127 time=4.79 ms ^C --- www.a.shifen.com ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1003ms rtt min/avg/max/mdev = 3.916/4.357/4.798/0.441 ms [root@myhost /]# dig www.baidu.com bash: dig: command not found [root@myhost /]# nslookup www.baidu.com bash: nslookup: command not found [root@myhost /]# cat /etc/resolv.conf nameserver 192.168.175.2
启动容器的时候添加一个名称解析,就是在hosts文件中加一个条目
[root@localhost ~]#docker run --rm -it --name test --dns 192.168.175.2 --add-host "docker.com:192.168.175.3" centos:latest /bin/bash [root@5da6ea60e6ad /]# [root@5da6ea60e6ad /]# 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 192.168.175.3 docker.com 172.17.0.2 5da6ea60e6ad
网络映射
为了能让外部网络访问docker里面的container,需要在物理机上做dnat
docker0 nat桥模型上的容器发布给外部网络访问
-p <container Port>
仅给出了容器的端口,表示将指定的容器端口映射到主机上的某个随机端口
物理机地址:192.168.175.21
[root@localhost ~]#docker run -it --rm -p 80 --net bridge --name web busybox:latest /bin/sh / # / # mkdir -p /web/html / # vi /web/html/index.html / # cat /web/html/index.html <h1> web container </h1> / # httpd -f -v -h /web/html #启动web服务,不以守护进程启动,前台能看到,终端被占用,-h:指明home文件目录 / # httpd -v -h /web/html #以守护进程方式启动,终端可以做其他事情 / # netstat -tnl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 :::80 :::* LISTEN
显示docker端口映射图,或者docker ps 也可以看到,在宿主机的iptables上面也可以看到映射图,宿主机上面可以看到在监听这个高位端口,这个比较特别,不光有nat转发,还有端口监听
[root@localhost ~]#docker port web 80/tcp -> 0.0.0.0:32768 [root@bogon ~]#docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c1765d1f185a busybox:latest "/bin/sh" 9 minutes ago Up 9 minutes 0.0.0.0:32768->80/tcp web [root@localhost ~]#ss -tnl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 :::32768 :::*
物理机ip:192.168.175.30
访问网站可以看到
防火墙查看
[root@localhost ~]#iptables -t nat -nvL Chain PREROUTING (policy ACCEPT 3 packets, 349 bytes) pkts bytes target prot opt in out source destination 3 156 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL Chain INPUT (policy ACCEPT 3 packets, 349 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 2 packets, 146 bytes) pkts bytes target prot opt in out source destination 0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL Chain POSTROUTING (policy ACCEPT 4 packets, 250 bytes) pkts bytes target prot opt in out source destination 8 536 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 2 271 RETURN all -- * * 192.168.122.0/24 224.0.0.0/24 0 0 RETURN all -- * * 192.168.122.0/24 255.255.255.255 0 0 MASQUERADE tcp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535 0 0 MASQUERADE udp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535 0 0 MASQUERADE all -- * * 192.168.122.0/24 !192.168.122.0/24 0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80 Chain DOCKER (2 references) pkts bytes target prot opt in out source destination 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0 2 104 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32768 to:172.17.0.2:80
将容器停止,端口映射会自动关闭,不用人工干涉
-p <hostPort>:<containerPort> 主机端口映射到容器端口 -p <hostIP>::<containerPort> 主机的某随机端口映射到容器某一个端口(固定) -p <hostIP>:<hostPort>:<containerPort> 主机的某个端口映射到容器某一个端口(固定) -P,--publish-all 发布所有的端口,跟--expose选项一起指定要暴露的端口 docker run -it --rm -P --expose 80 --expose 8080 --expose 443 --net bridge --name web busybox:latest /bin/sh 会将容器的80,8080,443端口映射到物理机的高位随机端口
如果不想启动容器的时候使用默认的docker0桥接口,需要在运行docker daemon命令时使用-b选项,指明要用的桥
–
联盟式容器,两个容器使用同一个网络空间, 启动一个容器时,让其使用某个已经存在的容器网络名称空间, 一个容器:docker run -it --rm -P --expose 80 --expose 8080 --expose 443 --net bridge --name web busybox:latest /bin/sh 另一个容器:docker run --rm --name joined_web --net container:web busybox:latest ifconfig -a 显示的是同一个网卡 开放式容器 docker run -it --rm --net host --name web centos:latest /bin/bash #当容器没有网络,没有ifconfig命令,可以使用这种模式,能直接连上互联网, 执行yum安装操作 容器运行在后台,容器就会终止, 运行服务在容器中不能运行在后台,一运行在后台,就表示释放控制台,一释放控制台,就表示终止 应该将httpd运行在前台:docker run --name web --net bridge -p 80:80 busybox:latest httpd -f 但是终端会一直会被占用,有一个-d选项,将docker自己运行在守护进程,取代了服务应该以守护进程运行在后台的这个角色 docker run -d --name web --net bridge -p 80:80 busybox:latest httpd -f
网络拓扑
当使用docker默认网络,即:–net=docker0时,下面是网络拓扑图
=============
其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效。 -b BRIDGE or --bridge=BRIDGE --指定容器挂载的网桥 配置 Docker 服务,默认桥接到创建的网桥上。 $ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker $ sudo service docker start 这些选项只有在 docker run 执行时使用,因为它是针对容器的特性内容。 -h HOSTNAME or --hostname=HOSTNAME --配置容器主机名 --link=CONTAINER_NAME:ALIAS --添加到另一个容器的连接 --net=bridge|none|container:NAME_or_ID|host --配置容器的桥接模式 容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。 $sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 1 如果在启动 Docker 服务的时候设定 --ip-forward=true , Docker 就会自动设定系统的 ip_forward 参数为 1 容器访问外部实现 容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。这是使用iptables 的源地址伪装操作实现的。 iptables -t nat -nL 外部访问容器实现 容器允许外部访问,可以在 docker run 时候通过 -p 或 -P 参数来启用。不管用那种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则。 当容器需要使用和物理机相同的网络,即桥接的时候,下面的脚本可以参考 cat set_bridge.sh #!/bin/sh brctl addbr bridge0 ip link set dev bridge0 up brctl addif bridge0 eth1 ip addr del 192.168.10.4/24 dev eth1 ip addr add 192.168.10.4/24 dev bridge0 cat set_docker_ip.sh #!/bin/sh pid=`docker inspect -f '{{.State.Pid}}' $(docker ps -l -q)` echo $pid mkdir -p /var/run/netns ln -s /proc/$pid/ns/net /var/run/netns/$pid ip link add vetha type veth peer name vethb brctl addif bridge0 vethb ip link set vethb up ip link set vetha netns $pid #ip netns exec $pid ip link del dev eth0 ip netns exec $pid ip link set dev vetha name eth0 ip netns exec $pid ip link set eth0 up ip netns exec $pid ip addr add 192.168.10.104/24 dev eth0 ip netns exec $pid ip route add default via 192.168.10.1
怎么找 docker 和 宿主机上 veth 设备的关系
# 宿主机上 $ ip link ...... 9: veth0e9cd8d@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether 6a:fb:59:e5:7e:da brd ff:ff:ff:ff:ff:ff link-netnsid 1 # 容器内 $ sudo docker exec -it e151 bash root@e1517e9d9e1a:/# cat /sys/class/net/eth0/iflink 9 这样就可以确定 container e1517e9d9e1a 在物理机上对应的 veth pair 是 veth0e9cd8d 了。 这种方式需要登录到 docker 里执行命令,不是所有的容器都能这么做,不过 github 上有人专门做了个脚本来用实现这个功能,可以参考一下: https://github.com/micahculpepper/dockerveth
参考文档1:docker快速上手指南
参考文档2:docker搭建lnmp
–
–
–
评论前必须登录!
注册