路漫漫其修远兮
吾将上下而求索

docker学习:使用网络

容器的网络模型

虚拟网网络方面的知识看前面的虚拟化技术
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

访问网站可以看到

Image 002.jpg

防火墙查看

[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时,下面是网络拓扑图

image.png

拓扑.zip

=============

其中有些命令选项只有在	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

未经允许不得转载:江哥架构师笔记 » docker学习:使用网络

分享到:更多 ()

评论 抢沙发

评论前必须登录!