011、docker管理容器之间的互联
本文最后更新于 66 天前,其中的信息可能已经过时,如有错误请发送邮件到wuxianglongblog@163.com

docker管理容器之间的互联

一.跨容器通讯概述

1.多容器互联概述

    在学习本章节之间,我们所学习的容器都有一个特点,就是所有的程序都被我们封装在同一个容器了,我们时常说"all-in-one"也不为过哈。
    但在实际工作中,难免会遇到多容器相互通信的场景,比如单节点多容器通信,跨主机的多容器通信等。这又该如何是好呢?接下来我们就一起来探究一下多容器互联的案例。

2.容器通信面临哪些难题

如下图所示,容器在通信时,并不能固定IP地址,当我们重新启动新容器时,不难发现,IP地址会发生改变哟~

image-20210621093802354

3.跨主机通信案例

如下图所示,启动容器时,我们可以使用"--link"选项来关联指定的容器,本质上是将关联容器的名称的机器IP地址添加到容器的"/etc/hosts"解析中。

使用"--link"有一个美中不足的情况,就是要求被关联的容器必须处于运行状态!否则就会抛出"Cannot link to a non running container"异常。

值得一提的是,"--link"参数只是单向的配置,本质上是你在某个容器的"/etc/hosts"添加了相应的解析,对其它容器的"/etc/hosts"并没有任何影响哟~

温馨提示:
    关于"--link"的使用了解即可,如果有别人这样写你要明白啥意思,我们在生产环境中建议大家为各个服务使用自定义网络。

image-20210621103039153

二.docker单机容器网络通信概述:star:

1.docker五种基础网络类型

bridge:
    默认类型,桥接到宿主机docker0的网络,类似于VM的Nat模式。

host:
    host类型,使用宿主机网络,网络性能最高。

container:
    容器类型,使用其它容器的共享网络,这在K8S中频繁使用。比如同一个Pod中可以有多个容器共存。

none:
    没有网络,该容器不能上外网。

network:
    自定义网络,我们可以使用docker network create创建自定义网络。   

温馨提示:
    (1)从严格意义上来说docker就只有3种基础网络类型,分别为bridge,host和none;
    (2)其中container和network本质上都是基于上述3种基础网络类型哟;

2.创建brigde网络类型的容器

[root@docker201.oldboyedu.com ~]# docker container run --network bridge -it -d alpine:latest
d3191721357a44e8898f0ab7f5605dfb7a6cd71c1ee6f4a4311fe46f5b212fa1
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container ps -a
CONTAINER ID   IMAGE           COMMAND     CREATED              STATUS              PORTS     NAMES
d3191721357a   alpine:latest   "/bin/sh"   5 seconds ago        Up 4 seconds                  condescending_chatterjee
fa9573e66949   alpine:latest   "/bin/sh"   About a minute ago   Up About a minute             loving_poincare
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container inspect --format='{{.NetworkSettings.Networks}}' condescending_chatterjee
map[bridge:0xc00015c000]
[root@docker201.oldboyedu.com ~]# 

温馨提示:
    如下图所示,创建容器时,如果创建容器时不显式指定网络,则默认的网络类型为bridge。

image-20210624154736920

3.创建host网络类型的容器

[root@docker201.oldboyedu.com ~]# docker container run --network host -it -d alpine:latest 
1102bf99d3356ab9bb2068a7ce6878883a4022eda87bf42799f3d251275c4f66
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container ps -a
CONTAINER ID   IMAGE           COMMAND     CREATED         STATUS         PORTS     NAMES
1102bf99d335   alpine:latest   "/bin/sh"   3 seconds ago   Up 2 seconds             jolly_neumann
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container inspect --format='{{.NetworkSettings.Networks}}' jolly_neumann
map[host:0xc00015c000]
[root@docker201.oldboyedu.com ~]# 

温馨提示:
    由于容器和宿主机使用相同的网络,那会存在当容器占用了特定的网络端口时,宿主机将无法在再次占用该端口哟~比如我们可以运行两个nginx镜像用来测试。

image-20210624155856748

4.创建none网络类型的容器

[root@docker201.oldboyedu.com ~]# docker container run --network none -it -d alpine:latest 
818507229a523c69a9c6d1f4a8bb4b791ed56eec9aff03e7ee457dc664bcad49
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container ps -a
CONTAINER ID   IMAGE           COMMAND     CREATED         STATUS        PORTS     NAMES
818507229a52   alpine:latest   "/bin/sh"   2 seconds ago   Up 1 second             nifty_lovelace
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container inspect --format='{{.NetworkSettings.Networks}}' nifty_lovelace
map[none:0xc000574000]
[root@docker201.oldboyedu.com ~]# 

温馨提示:
    生产环境中,我们很少会遇到容器的网络类型为"none",除非专门给客户用来测试的环境,该容器仅能做一些基础性的实验,因为该容器无法联网。

image-20210624221919369

5.创建container网络类型的容器

[root@docker201.oldboyedu.com ~]# docker container run --network container:oldboyedu_kod -d -it alpine:latest 
e6341f990e6f99da3da16c9377312968a5b97415de86cc2cc86301707b327753
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container ps -a
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS            NAMES
e6341f990e6f   alpine:latest      "/bin/sh"                3 seconds ago    Up 3 seconds                     cranky_nobel
e0b18ced7796   oldboyedu_kod:v3   "/bin/bash /start_in…"   38 seconds ago   Up 37 seconds   22/tcp, 80/tcp   oldboyedu_kod
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container inspect --format='{{.NetworkSettings.Networks}}' cranky_nobel
map[]
[root@docker201.oldboyedu.com ~]# 

温馨提示:
    这种网络容器在Kubernetes中频繁使用,还记得同一个Pod资源是可以容纳多个容器吗?这些容器在同一个Pod资源共享的是相同的网络类型。

image-20210624224012120

6.创建自定义网络

[root@docker201.oldboyedu.com ~]#  docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
16a2b2b8a5b9   bridge    bridge    local
6f73cd7e0326   host      host      local
da59e2f161a4   none      null      local
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker network create -d bridge --subnet 172.28.0.0/16 --gateway 172.28.0.254 jasonyin2020
696e38de3b8ef925813497ebeb216999b7bc0f6a770cd30ca47e601e5b842cd5
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]#  docker network ls
NETWORK ID     NAME           DRIVER    SCOPE
16a2b2b8a5b9   bridge         bridge    local
6f73cd7e0326   host           host      local
696e38de3b8e   jasonyin2020   bridge    local
da59e2f161a4   none           null      local
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container run -it -d --name oldboyedu_kod --network jasonyin2020 -p 80:80 oldboyedu_kod:v3 
bb74bf2310d664a98294f0cee846ce1df08992db89ce5e58d5acf061cd774b51
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# docker container run -it --network jasonyin2020 oldboyedu_linux:v1

温馨提示:
    (1)如下图所示,我们创建容器时,可以使用"--network"选项为该容器指定所述网络类型;
    (2)关于创建容器时的相关参数说明,请参考"docker network create --help";

image-20210625082329287

7.自定义网络分配IP地址案例

(1)创建自定义网络
docker network create -d bridge --gateway 172.26.1.254 --subnet 172.26.1.0/24 --ip-range 172.26.1.100/28  oldboyedu2021

(2)使用自定义网络
docker container run -itd --network oldboyedu2021 --rm alpine

温馨提示:
    有关子网掩码计算可以借助网上的工具即可,如下图所示.

1636039422756

三.docker单机容器网络通信案例-基于专用的网络实现zabbix的容器间通信

1.zabbix架构图

如下图所示,是一个简单的zabbix架构图,此处我并没有考虑zabbix-proxy角色。

基于docker环境部署最新版本的zabbix:
    https://www.zabbix.com/documentation/current/manual/installation/containers

image-20210621120928274

2.创建专用于Zabbix组件容器的网络

docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net

image-20210621131415967

3.启动空的MySQL服务器实例(该步骤有个小坑,请参考提示第三点)

docker run --name mysql-server -t \
      -e MYSQL_DATABASE="zabbix" \
      -e MYSQL_USER="zabbix" \
      -e MYSQL_PASSWORD="zabbix_pwd" \
      -e MYSQL_ROOT_PASSWORD="root_pwd" \
      --network=zabbix-net \
      -d mysql:8.0 \
      --restart unless-stopped \
      --character-set-server=utf8 --collation-server=utf8_bin \
      --default-authentication-plugin=mysql_native_password

温馨提示:(以上代码摘自官方,以下注解为我个人见解)
(1)使用相关的参数:
    "-e":
        是"--env"的简称,表示启动容器时传入一个环境变量;
    "--network":
        表示使用的网络组件为"zabbix-net";
    "-t":
        为容器单独分配一个终端。
    "-d":
        表示后台运行。
    "--restart":
        当容器退出时要应用的重新启动策略,默认值为"no"。
        如果设置为"unless-stopped",表示服务停止会自动触发重启操作。
    "--character-set-server":
        指定服务端的字符集。
    "--default-authentication-plugin":
        指定默认的认证插件,注意MySQL5.7和MySQL8.0默认插件有所不同哟。

(2)如果本地没有镜像,则自动会去官网下载镜像:
    如下图所示,没有镜像会有长时间的下载镜像过程,因此建议大家使用我准备好的镜像。

(3)实际运行MySQL实例时请删除"--restart"选项,因为会导致容器无法启动。

image-20210621132107286

4.启动Zabbix Java网关实例

docker run --name zabbix-java-gateway -t \
      --network=zabbix-net \
      --restart unless-stopped \
      -d zabbix/zabbix-java-gateway:alpine-5.4-latest

温馨提示:
    如下图所示,没有镜像会有长时间的下载镜像过程,因此建议大家使用我准备好的镜像。

image-20210621133119319

5.启动Zabbix服务器实例并将该实例与创建的MySQL服务器实例链接

docker run --name zabbix-server-mysql -t \
      -e DB_SERVER_HOST="mysql-server" \
      -e MYSQL_DATABASE="zabbix" \
      -e MYSQL_USER="zabbix" \
      -e MYSQL_PASSWORD="zabbix_pwd" \
      -e MYSQL_ROOT_PASSWORD="root_pwd" \
      -e ZBX_JAVAGATEWAY="zabbix-java-gateway" \
      --network=zabbix-net \
      -p 10051:10051 \
      --restart unless-stopped \
      -d zabbix/zabbix-server-mysql:alpine-5.4-latest

image-20210621133525397

6.启动 Zabbix web 界面并将实例链接到创建的 MySQL 服务器和 Zabbix 服务器实例

docker run --name zabbix-web-nginx-mysql -t \
      -e ZBX_SERVER_HOST="zabbix-server-mysql" \
      -e DB_SERVER_HOST="mysql-server" \
      -e MYSQL_DATABASE="zabbix" \
      -e MYSQL_USER="zabbix" \
      -e MYSQL_PASSWORD="zabbix_pwd" \
      -e MYSQL_ROOT_PASSWORD="root_pwd" \
      --network=zabbix-net \
      -p 80:8080 \
      --restart unless-stopped \
      -d zabbix/zabbix-web-nginx-mysql:alpine-5.4-latest

image-20210621133950398

7.访问zabbix的登录页面

如下图所示,访问宿主机的80端口,并输入zabbix-web的默认用户名("Admin")和密码("zabbix")进行登录即可。

image-20210621152541882

8.zabbix页面登录成功

如下图所示,就是咱们自信版本的zabbix版本哟~

image-20210621152910391

9.补充内容(了解即可)

Docker容器的重启(--restart)策略如下:
    no:
        默认策略,在容器退出时不重启容器
    on-failure:
        在容器非正常退出时(退出状态非0),才会重启容器
        on-failure:3:
            在容器非正常退出时重启容器,最多重启3次
    always:
        在容器退出时总是重启容器
    unless-stopped:
        在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器.

温馨提示:
    (1)手动使用"docker container stop|kill"指令始终不会重启容器;
    (2)但是手动在宿主机kill相关的容器经常的确会重启,或者是重启操作系统也会重启哟.

推荐阅读:
    https://docs.docker.com/engine/reference/run/#restart-policies---restart

1629464832313

四.小规模跨宿主机容器网络通信案例-macvlan

1.相同macvlan网络之间的通信原理

    macvlan是Linux kernel支持的新特性,支持的版本有v3.9-3.19和 4.0+,比较稳定的版本推荐 4.0+。

    如下图所示,它一般是以内核模块的形式存在,我们可以通过以下方法判断当前系统是否支持。

    如果第一个命令报错,或者第二个命令没有返回,说明当前系统不支持 macvlan,需要升级内核。

image-20210625090356227

    根据macvlan子接口之间的通信模式,macvlan有四种网络模式,分别为private,vepa,bridge,passthru。如果这些网络感兴趣的小伙伴可自行查阅相关资料,但我并不太建议大家在这里花费太多时间。
    在Docker中,macvlan只是众多Docker网络模型中的一种,并且是一种跨主机的网络模型,作为一种驱动(driver)启用(使用"-d"参数指定),可惜呀,Docker macvlan只支持bridge模式。
    相同macvlan网络之间的通信如下图所示。

image-20210625095710201

2.不同 macvlan 网络之间的通信

    由于macvlan网络会独占物理网卡,也就是说一张物理网卡只能创建一个macvlan网络,如果我们想创建多个macvlan网络就得用多张网卡,但主机的物理网卡是有限的,怎么办呢?

    好在macvlan网络也是支持VLAN子接口的,所以,我们可以通过VLAN技术将一个网口划分出多个子网口,这样就可以基于子网口来创建 macvlan网络了。感兴趣的小伙伴可自行查阅相关资料。

image-20210625110708632

3.自定义macvlan网络

(1)在docker201.oldboyedu.com节点创建macvlan网络
docker network create -d macvlan --subnet=172.29.0.0/16 --gateway=172.29.0.254 -o parent=eth0 oldboyedu_macvlan

(2)在docker202.yinzhengjie.com节点创建macvlan网络
docker network create -d macvlan --subnet=172.29.0.0/16 --gateway=172.29.0.254 -o parent=ens33 oldboyedu_macvlan

image-20210625101058096

4.基于自定义的macvlan网络创建容器

(1)在docker201.oldboyedu.com节点创建容器时手动分配IP地址并指定自定义的macvlan网络
docker container run -it -d --name oldboyedu_kod2021 --network oldboyedu_macvlan --ip 172.29.0.201 oldboyedu_kod:v3

(2)在docker202.yinzhengjie.com节点创建容器时手动分配IP地址并指定自定义的macvlan网络
docker container run -it --name oldboyedu_linux2021 --network oldboyedu_macvlan --ip 172.29.0.202 jasonyin2020/oldboyedu_linux:v1

image-20210625103011941

5.macvlan网络的优缺点

优点:
    (1)docker原生支持,无需安装额外插件,配置起来相对简单。
    (2)适合小规模docker环境,例如只有1-3台,如果服务器过多,手动分配IP地址可能会无形之间增加工作量;

缺点:
    (1)需要手动分配IP地址,如果让其自动分配IP地址可能会存在多个主机自动分配的IP地址冲突的情况,到时候还需要人工介入维护;
    (2)本机相同网络(本案例为"oldboyedu_macvlan")的容器之间相互通信没问题,跨主机之间的容器进行通信也没问题,但容器无法与宿主机之间进行通信,也无法连接到外网;

五.大规模跨宿主机容器网络通信案例-overlay

1.什么是overlay网络

    overlay翻译为中文名称为"重叠网络",底层是基于vxlan技术实现的。

2.什么是vlan

3.什么是vxlan

4.部署consul键值对数据库

简而言之,consul是类似于zookeeper,etcd一样的键值对数据库,我们用它来存储已分配的IP地址。如下图所示,我们成功的部署了2台docker环境指向了同一个consul服务。

(1)加载consul进行
[root@harbor250.oldboyedu.com ~]# docker image pull consul:latest

(2)运行容器
[root@harbor250.oldboyedu.com ~]# docker container run -it -d -p 10.0.0.101:8500:8500/tcp  --restart=always consul:latest

(3)修改所有客户端的配置文件(我这里仅演示了一台,你可以根据自己的情况做相关的微调即可)
[root@docker201.oldboyedu.com ~]# vim /etc/docker/daemon.json 
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# cat /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://tuv7rqqq.mirror.aliyuncs.com"],
  # "insecure-registries": ["docker201.oldboyedu.com:5000"],
  # "data-root":"/oldboyedu/docker",
   "cluster-store": "consul://10.0.0.101:8500",
   "cluster-advertise": "10.0.0.101:6666"
}
[root@docker201.oldboyedu.com ~]# 
[root@docker201.oldboyedu.com ~]# systemctl restart docker
[root@docker201.oldboyedu.com ~]# 

参数说明:
    data-root:
        指定docker的数据存储目录。
    cluster-store:
        配置的是nginx监听的地址。
    cluster-advertise:
        指定的是docker的宿主机注册到consul中的指定网卡中的ip,也可以写ip和端口号,端口只要没被占用就可以了。

image-20210625124316744

5.在任意客户端节点创建overlay类型网络(只需要在一个节点操作即可,其他节点会通过consul服务进行同步)

docker network create -d overlay --subnet 172.30.0.0/16 --gateway 172.30.0.254 oldboyedu_overlay

温馨提示:
    如下图所示,我们只需要在任意一个节点只需该命令即可,无需在所有节点上执行,因为凡是注册在consul服务中的所有docker实例均为同一个集群,会有它自动帮咱们同步网络哟~

image-20210625154111892

6.各节点基于自定义的overlay类型网络创建容器

(1)在docker202.yinzhengjie.com节点创建容器:
docker container run -it -d --name linux01 --network oldboyedu_ol01 oldboyedu_linux:v1

(2)在docker201.oldboyedu.com节点创建容器:
docker container run -it -d --name linux02 --network oldboyedu_ol01 alpine:latest

温馨提示:
    (1)如下图所示,跨主机的两个容器是可以相互ping通啦~
    (2) 

image-20210625161722672

7.overlay组件的工作原理

image-20210625163330561

如上图所示,不难发现容器内存在两块网卡,分别对应eth0和eth1,我们的跨主机容器之间不仅仅能够实现互通,各个容器还能实现外网的访问。

如下图所示,为overlay网络组件的工作原理。假设linux01容器发起ping请求,目标IP为linux02的地址172.29.0.2。其工作流程如下所示:
    (1)该请求的流量通过连接到网桥(Bridge)交换机的veth5855590接口发出。虚拟交换机并不知道将包发送到哪里,因为在虚拟交换机的MAC地址映射表(ARP 映射表)中并没有与当前目的IP对应的MAC地址;
    (2)所以虚拟网桥(Bridge)交换机会将该包发送到其上的全部端口。连接到网桥(Bridge)交换机的VTEP接口知道如何转发这个数据帧,所以会将自己的MAC地址返回。这就是一个代理ARP响应,并且虚拟网桥(Bridge)交换机根据返回结果学会了如何转发该包。接下来虚拟交换机会更新自己的ARP映射表,将172.29.0.2映射到本地VTEP的 MAC地址上。
    (3)现在虚拟网桥(Bridge)交换机已经学会如何转发目标为linux02的流量,接下来所有发送到linux02的包都会被直接转发到VTEP接口。
    (4)交换机会将包转发到VTEP接口,VTEP完成数据帧的封装,这样就能在底层网络传输。具体来说,封装操作就是把VXLAN Header信息添加以太帧当中。
    (5)VXLAN Header信息包含了VXLAN网络ID(VNID),其作用是记录 VLAN到VXLAN的映射关系。每个VLAN都对应一个VNID,以便包可以在解析后被转发到正确的VLAN。
    (6)封装的时候会将数据帧放到UDP包中,并设置UDP的目的IP 字段为docker202.yinzhengjie.com节点的VTEP的IP地址,同时设置 UDP Socket端口为4789。这种封装方式保证了底层网络即使不知道任何关于VXLAN的信息,也可以完成数据传输。
    (7)当包到达docker202.yinzhengjie.com之后,内核发现目的端口为UDP端口4789,同时还知道存在VTEP接口绑定到该 Socket。所以内核将包发给VTEP,由VTEP读取VNID,解压包信息,并根据 VNID发送到本地网桥(Bridge)交换机的连接到VLAN的交换机。在该交换机上,包被发送给容器linux02。

以上大体介绍了 Docker 覆盖网络是如何利用 VXLAN 技术的。

参考连接:
    http://c.biancheng.net/view/3198.html

image-20210626075605566

六.课堂练习

    (1)自定义docker网络,要求网段为172.30.1.0/24,网关为172.30.1.254,网络名称为oldboyedu-linux77
    (2)基于上一步的网络创建容器,容器名称为"oldboyedu-network"
    (3)自定义docker网络,要求网段为172.31.100.0/24,网关为172.31.100.254,网络名称为oldboyedu-linux78
    (4)将"oldboyedu-network"容器添加到oldboyedu-linux78网络,并查看其网络信息,截图;
    (5)删除自定义网络;

七.可能会遇到的故障

1.Cannot link to a non running container

故障原因:
    如下图所示,说明该容器未正常运行,因此不会输出。

解决方案:
    将需要使用"--link"的容器手动启动起来。

image-20210621110434879

2.Pool overlaps with other one on this address space

故障原因:
    创建网络时,指定的地址池网段与已有的网络地址池冲突。

解决方案:
    修改地址池网段,避免网段冲突即可。

image-20210625111905270

3.network with name oldboyedu_macvlan already exists

故障原因:
    创建的网络名称已存在。

解决方案:
    修改网络的名称即可,避免网络名称冲突。

image-20210625112000210

4. Error response from daemon: endpoint with name linux01 already exists in network oldboyedu_ol01.

故障原因:
    在同一个overlay中,创建了想用容器名称。

解决方案:
    修改容器名称重新创建即可。

image-20210625155855666

谨此笔记,记录过往。凭君阅览,如能收益,莫大奢望。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇