Docker之 网络

Docker之 网络

Docker的网络实现其实利用了Linux的网络命名空间和虚拟网络设备(特别是veth pair)。
它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样一对接口叫做veth pair)。

网络创建过程

Docker创建一个容器的时候,会执行如下操作

- 创建一对虚拟接口,分别放在本地和新容器的命名空间中。
- 本地主机一端的虚拟接口连接到默认的docker0网桥,并以veth开头的唯一名字。
- 容器一端的虚拟接口将放在新创建的容器中,并修改名字为eth0。
- 从网桥可用地址中获取一个空闲地址分配给容器的eth0,并配置默认路由网关为docker0网卡的内部接口docker0的ip地址。

容器自带的网络:

docker network ls 
NETWORK ID          NAME                DRIVER              SCOPE
ec2989c51fef        bridge              bridge              local
7db9051f6518        host                host                local
1b6cb3a83fb5        none                null                local
网络描述
none容器不能访问外部网络
host使用和主机相同的网络
bridge(默认)容器通过veth连接到主机的桥接上

1、none

容器不能访问外部网络.

2、bridge

桥接是在主机上的,通常为docker0。Docker启动时会在主机上自动创建一个Docker0虚拟网桥,Docker随机分配一个本地未占用的私有网段中的一个地址给docker0接口,例如典型的172.17.42.1,掩码255.255.0.0。此后启动的容器内的网口会自动分配一个同一网段(172.17.0.0/16)地址。

当创建一个容器时,同时会创建一对veth pair接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即eth0;另一端在本地并挂载到docker0网桥,名称以veth开头。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker就在主机和所有容器之间创建了一个虚拟共享网络。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XsUP4bOt-1582447212868)(https://github.com/gmg0829/Img/blob/master/dockerImg/docker-network.png?raw=true)]
3、host

host 网络在主机网络堆栈上添加一个容器。您可以发现,容器中的网络配置与主机相同。相比于桥接,该模式由于没有通过iptable的转发,性能上要比桥接好一些。在对网络性能特别关注时,如HAProxy等负载均衡器时,可以使用host模式

对于bridge而言,默认是主机挂载在主机的docker0上的。
在主机上通过ifconfig可以查看到:

$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:e7:af:5f:93  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

通过docker network inspect bridge查看本机Docker网络的信息。

docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "ec2989c51fef4e8218487900cc2e8eb7f3657c684f3ad5c342ca3c83a8ed31ec",
        "Created": "2018-11-26T04:21:17.414945018-05:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

运行ngnix容器

$ docker run -d -p 80:80 nginx:latest

查看Docker网络信息:

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "ec2989c51fef4e8218487900cc2e8eb7f3657c684f3ad5c342ca3c83a8ed31ec",
        "Created": "2018-11-26T04:21:17.414945018-05:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "207f0308a472a1997e19eaf9966de765a3bcff5197735e810687dcb8cf9ed7d0": {
                "Name": "serene_kowalevski",
                "EndpointID": "3cc7178db0366e5f86dfcc6d4a3cd58647a14498092954f28382cd7bf3028d04",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

当启动一个容器时,在上面Containers下面加入相关的网络信息。

用户自定义网络

除默认的网络外,Docker还允许用户创建自己的网络。主要包括三种:桥接;Overlay网络;插件网络。

桥接网络

系统默认的桥接是docker0,将多个容器隔离在一个新的桥接网络中。可以使用如下命令:

$ docker network create --driver bridge mynet
1a32fd6bb26a64d37c42f7238130b10cab0a184bb10715c942878b5fe666d0db

$ docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "1a32fd6bb26a64d37c42f7238130b10cab0a184bb10715c942878b5fe666d0db",
        "Created": "2018-11-26T21:54:24.071258917-05:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

通过–net属性将容器挂接到mynet中。

$ docker run --net=mynet -it nginx

$ docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "1a32fd6bb26a64d37c42f7238130b10cab0a184bb10715c942878b5fe666d0db",
        "Created": "2018-11-26T21:54:24.071258917-05:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "33eb0b4b7e6c5bc7c2ce8088ac5b4ce3d43d47543212937201e5dd3ca02607c2": {
                "Name": "hungry_goldstine",
                "EndpointID": "316b2d65124f28661b5562b397c2ae63df0802bf8ecbd8435159b8ee95b474b3",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

在同一个桥接下,形成了一个私网,相互之间是可以访问的,但是仅限于在同一台主机上。若跨机通信,就必须使用Overlay网络。

Overlay网络

Overlay是一种虚拟交换技术,主要解决不同IP地址段之间的网络通信问题。Docke使用的Overlay技术是VXLAN,是借助于libnetwork实现的。Overlay需要一个K-V服务来存储相关的主机信息。目前Docker支持的K-V存储服务有Consul、Etcd和ZooKeeper。

overlay网络模式如下:

容器访问控制

1、容器访问外部网络

由于容器默认指定了网关为docker0网桥上的docker0内部接口,docker0内部接口是本地宿主机的一个本地接口。因此,默认容器是可以访问外部网络的。
容器想要通过宿主机访问到外部网络,需要宿主机进行网络转发。

在宿主机Linux系统中,检查转发是否打开:

$ sudo sysctl net.ipv4.ip_forward
如果为0,未开启,手动打开
$  sudo sysctl -w net.ipv4.ip_forward=1

2、外部访问容器

在启动容器的时候,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。

当容器中运行一些网络应用,要让外部访问时,可以通过-P或-p参数来指定端口映射。

3、容器之间访问

默认情况下,所有容器都会连接到docker0网桥上,这意味着网络拓扑是互通的。

  • 方式一:使用容器的IP地址来通信

  • 方式二:使用宿主机的IP加上容器暴露出的端口号来通信

  • 方式三:使用docker的link机制通信

    容器的连接,它会在源和接受容器之间创建一个隧道,接受容器能看到源容器指定的信息。连接系统依据容器的名称来执行。

    创建一个web容器并连接到db容器。

    $ docker run -d --name db  training/mysql
    $ docker run -d -P --name web --link db:db training/webapp
    

    Docker通过两种方式为容器公开连接信息:

    • 环境变量
    • 更新/etc/hosts文件
      使用env命令查看web容器的环境变量
    $ docker run --rm --name web2 --link db:db training/webapp env
    ...
    DB_NAME=web2/db
    DB_PORT=tcp://172.17.0.5:5432
    DB_PORT_5000_TCP=tcp://172.17.0.5:5432
    DB_PORT_5000_TCP_PROTO=tcp
    DB_PORT_5000_TCP_PORT=5432
    DB_PORT_5000_TCP_ADDR=172.17.0.5
    

    其中DB_开头的环境变量是提供web容器连接到db容器使用,前缀采用大写的连接别名。

    除了环境变量,Docker还添加host信息到父容器的/etc/hosts的文件。下面是父容器web的hosts文件:

    $ cat /etc/hosts
    172.17.0.7 aed84ee21bde
    .
    .
    172.17.0.7 db
    

    这两个有hosts信息,第一个是web容器,web容器使用自己的id做为默认主机名,
    第二个是db的ip和容器名。

网络相关参数

docker run执行时执行

  • -h HOSTNAME 配置容器主机名
  • -link 添加到另一个容器的连接
  • -net bridge|none 配置容器桥接模式
  • -p 映射容器端口到宿主主机
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值