Docker网络 学习笔记

该文为《深入浅出Docker》的学习笔记,感谢查看,如有错误,欢迎指正

一、基础理论

Docker 网络架构由3个主要部分构成:

  • 容器网络模型(Container Network Model,CNM)
  • Libnetwork
  • 驱动

1.1 容器网络模型(CNM)

CNM是设计标准,定义了3个基本要素:沙盒(Sandbox)终端(Endpoint)网络(Network)

  1. 沙盒是一个独立的网络栈,包括以太网接口端口路由表DNS配置
  2. 终端是虚拟网络接口,负责创建连接,在CNM中,负责将沙盒连接到网络,一个终端只能连接到某一个网络,如果容器需要加入网络,就需要多个终端;
  3. 网络是802.1d网桥的软件实现,网络是需要交互的终端的集合,并且终端之间相互独立。

1.2 Libnetwork
Libnetwork是标准的实现,除了实现了CNM中的3个基本要素外,还实现了本地服务发现(Service Discovery)基于Ingress的容器负载均衡网络控制层和管理层功能

1.3 驱动
如果说Libnetwork实现了控制层和管理层,那么驱动就负责实现数据层
Docker封装了若干内置驱动,通常被称为原生驱动或者本地驱动。在Linux中包括BridgeOverlayMacvlan,在Windows中包括NATOverlayTransportL2 Bridge
除了以上内置驱动,第三方也可以编写Docker网络驱动,这些驱动叫做远程驱动,例如CalicoContivKuryrWeave

Libnetwork支持同时激活多个网络驱动
Docker网络 学习笔记_第1张图片
1.4 Docker网络命令

命令 作用
docker network ls 列出运行在本地Docker主机上的全部网络
docker network create 创建新的Docker网络,默认情况下,Windows会使用NAT,Linux会使用Bridge,可以使用 -d 指定驱动
docker network inspect 提供Docker主机的详细配置信息
docker network prune 删除Docker主机上全部未使用的网络
docker network rm 删除Docker主机上指定的网络
二、单机桥接网络(Bridge)

是最简单的Docker网络,有以下特点:

  • 只能在单个Docker主机上运行,并且只能与所在Docker主机上的容器进行连接
  • 是802.1d的一种实现(二层交换机)

每个Docker主机都有一个默认的单机桥接网络,在Linux上网络名称为Bridge,在windows上叫做nat,默认情况下,新创建的容器都会连接到该网络。除非创建容器时指定参数--network
Docker网络 学习笔记_第2张图片
使用docker network inspect 可以查看网络更加详细的信息

[root@huanzi-001 ~]# docker network inspect bridge 
[
    {
        "Name": "bridge",
        "Id": "302c36bc3cf1b9f7d1d2bc87f34f3fbc56f617add92e83729b9e9b467d3c2c7a",
        "Created": "2020-02-04T10:10:35.753930939+08: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": {}
    }
]
[root@huanzi-001 ~]# 

创建网络
使用docker network create 创建一个新的单机桥接网络

[root@huanzi-001 ~]# docker network create lovehuanzi
d302c895b45591b8262fd0afcf306afe3a0d11b1498479c2f15c77a8e8793ac7
[root@huanzi-001 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
302c36bc3cf1        bridge              bridge              local
ac57c15024c7        docker_gwbridge     bridge              local
e863472805b3        host                host                local
7d6iv5ilwbcn        ingress             overlay             swarm
d302c895b455        lovehuanzi          bridge              local
eefd134326c4        none                null                local

Linux上默认的Bridge网络是不支持通过Docker DNS服务进行域名解析的,自定义桥接网络可以

  1. 一个Docker主机中不同单机桥接网络中的容器之间,无法正常通信。
  2. 不同Docker主机中,相同名称的单机桥接网络之间,无法正常通信。
  3. 只有一个Docker中,同一单机桥接网络中的容器,可以互相通信。
  4. 如果必须要跨单机网络,跨Docker主机进行通信,可以使用端口映射实现
三、多机覆盖网络(Overlay)

覆盖网络适用于多机环境,允许单个网络包含多个Docker主机,这样不同Docker主机上的容器间就可以实现通信。
使用docker network create --d overlay命令创建覆盖网络

root@huanzi-001 ~]# docker network create -d overlay huanzi-net
ojt9cxg2qsxegjcgu6ktoo2rs
[root@huanzi-001 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
302c36bc3cf1        bridge              bridge              local
ac57c15024c7        docker_gwbridge     bridge              local
e863472805b3        host                host                local
ojt9cxg2qsxe        huanzi-net          overlay             swarm
7d6iv5ilwbcn        ingress             overlay             swarm
d302c895b455        lovehuanzi          bridge              local
eefd134326c4        none                null                local
[root@huanzi-001 ~]# 
[root@huanzi-002 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
3afb6544913b        bridge              bridge              local
72f048c911f2        docker_gwbridge     bridge              local
83491c86f3ab        host                host                local
7d6iv5ilwbcn        ingress             overlay             swarm
31762b86ae64        none                null                local
[root@huanzi-002 ~]#

在工作节点上执行docker network ls发现看不见huanzi-net这个覆盖网络,因为只有当运行中的容器连接到了覆盖网络时,该网络才变为可用状态。
能看见ingress是因为在工作节点上运行有副本,该副本连接的是ingress,而huanzi-net是刚刚创建的,还没有副本,我们给huanzi-net分配副本之后再看一下。

  1. 创建一个huanzi-nginx的服务
[root@huanzi-001 ~]# docker service create --name huanzi-nginx --network huanzi-net --replicas 2 nginx:latest
yqkuakn91ieeo7ed01ftyyjsk
overall progress: 2 out of 2 tasks 
1/2: running   [==================================================>] 
2/2: running   [==================================================>] 
verify: Service converged 
[root@huanzi-001 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
yqkuakn91iee        huanzi-nginx        replicated          2/2                 nginx:latest        
ipvnc10w8l9h        my-nginx            replicated          5/5                 nginx:latest        *:8080->80/tcp
[root@huanzi-001 ~]# 
  1. 我们发现,在工作节点已经能看到huanzi-net了。
[root@huanzi-002 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
3afb6544913b        bridge              bridge              local
72f048c911f2        docker_gwbridge     bridge              local
83491c86f3ab        host                host                local
ojt9cxg2qsxe        huanzi-net          overlay             swarm
7d6iv5ilwbcn        ingress             overlay             swarm
31762b86ae64        none                null                local
[root@huanzi-002 ~]# 

如何查看Docker容器的IP

  1. 先查看Docker容器的ID
[root@huanzi-001 ~]# docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
4eae732468cc        nginx:latest        "nginx -g 'daemon of…"   21 minutes ago      Up 21 minutes       80/tcp              huanzi-nginx.2.s6fwv5gbuopzssbymyspu81ex
[root@huanzi-001 ~]# 

拿到ID是4eae732468cc

  1. 根据ID查询覆盖网络下的IP是多少
[root@huanzi-001 ~]# docker container inspect 4eae732468cc
<...>
"NetworkSettings": {
            <...>
            "Networks": {
                "huanzi-net": {
                    <...>
                    "IPAddress": "10.0.1.4",
                    <...>
                }
            }
        }
    }
]

IP地址是10.0.1.4,属于覆盖网络的Subnet中。

覆盖网络的Subnet查看

[root@huanzi-001 ~]# docker network inspect huanzi-net 
[
    {
        "Name": "huanzi-net",
        "Id": "ojt9cxg2qsxegjcgu6ktoo2rs",
        "Created": "2020-02-04T19:50:37.95254094+08:00",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.1.0/24",
                    "Gateway": "10.0.1.1"
                }
            ]
        },
        <...>

可以看到,"Subnet": "10.0.1.0/24"


四、接入现有网络(Macvlan)

Docker内置的Macvlan驱动可以实现,让容器化的应用,能够连接到外部物理网络上与之进行通信。通过为容器提供Mac和IP地址,让容器在外部物理网络上成为"公民"。

  • Macvlan的优点是性能优异,无须端口映射或者额外桥接,可以直接通过主机接口访问容器接口。
  • 但是缺点是需要将主机网卡设置为混杂模式,在大部分公有云平台上是不允许的。

Macvlan适用于公司内部的数据中心网络环境,但在公有云上并不可行

创建一个macvlan100网络以及eth0.100子接口。

docker network create -d macvlan --subnet=10.0.0.0/24 --ip-range=10.0.0.0/25 --gateway=10.0.0.1 -o parent=eth0.100 macvlan100

部署容器至macvlan网络中

docker container run -d --name mactainer1 --network macvlan100 alpine sleep 1d 

部署完成后,mactainer1容器可以ping通任何加入物理网络VLAN100的系统,并进行通信。

同一Docker主机上可以创建多个Macvlan网络


五、服务发现

服务发现(Service Discovery)允许容器和Swarm服务通过名称互相定位。唯一的要求就是需要处于同一网络中。

  • 每个Docker容器都有一个本地DNS解析器
  • 本地DNS服务解析器,预先配置好并知道Dcoker DNS服务器的细节
  • 每个网络都有一个独立的Docker DNS服务
  • 每个启动时使用了--name参数的Swarm服务或者独立的容器,都会将自己的名称和IP注册到Docker DNS服务

举个例子,容器 c1 与容器 c2 位于相同的网络之中,c1 通过名称ping 容器 c2。

  1. 如果c1的本地DNS服务器中有c2的映射记录,就可以直接解析出IP,进行ping操作。
  2. 如果本地DNS服务器中找不到,就会到Docker DNS服务器中找,因为Docker DNS服务器中记录了全部容器名称和IP地址的映射关系,Docker DNS服务器可以解析出c2对应的IP地址,并且将解析出的IP地址,返回给c1的本地DNS服务器,再进行ping操作。

如果两个容器位于不同的网络之中,则 Dcoker DNS 服务器中也没有对方的映射记录,两者无法互相解析


六、Ingress网络

Swarm支持两种服务发布模式,两种模式均保证服务从集群外可访问

  • Ingress模式(默认)
  • Host模式

区别:

  1. Ingress模式是默认模式;
  2. Ingress模式下,从Swarm集群任一节点(即使该节点没有运行服务的副本)都能访问该服务;
  3. Host模式下,只能通过运行了副本的节点来访问服务;
  4. 通过-p--publish发布服务时都是Ingress模式,如果需要使用Host模式,需要使用-publish参数的完整格式,并且必须加上mode=host

Host模式例子(逗号前后不允许有空格):

docker service create -d --name svc1 --publish published=5000,target=80,mode=host nginx

Ingress模式特点:

  • Swarm集群中,从任一节点都能访问服务,因为Ingress网络会将所有访问请求路由到运行了副本的节点上
  • 访问流量会平均分布在运行了副本的节点上

感谢阅读,有兴趣的小伙伴可以关注我的公众号DevOps探索之旅,大家一起学习进步
Docker网络 学习笔记_第3张图片

你可能感兴趣的:(Docker)