前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Docker重学系列之高级网络篇

Docker重学系列之高级网络篇

作者头像
大忽悠爱学习
发布2022-05-10 15:29:30
1.1K0
发布2022-05-10 15:29:30
举报
文章被收录于专栏:c++与qt学习

Docker重学系列之高级网络篇


高级网络配置

说明

当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。

同时,Docker 随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给 docker0 接口。比如典型的 172.17.42.1,掩码为 255.255.0.0。此后启动的容器内的网口也会自动分配一个同一网段(172.17.0.0/16)的地址。

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

在这里插入图片描述
在这里插入图片描述

veth-pair技术

顾名思义,veth-pair 就是一对的虚拟设备接口,和 tap/tun 设备不同的是,它都是成对出现的。一端连着协议栈,一端彼此相连

我们每启动一个docker容器,docker就会给docker容器分配一个ip,并会生成一对(2个)网卡,因为我们在安装docker容器时就会安装一个docker专用的网卡;所以启动后,不但容器里面会有一个网卡,宿主机也有有一个网卡用来专门绑定容器用的;所以它们的网卡是一对一对出现的, 这就是veth-pair技术;

在这里插入图片描述
在这里插入图片描述

网络小结

在这里插入图片描述
在这里插入图片描述
  • 默认docker在创建容器时将所有容器都连接到docker0网桥上,默认在docker0网桥的容器都可以使用容器内ip地址进行通信

进入到tomcat01的bash命令行界面,可以通过tomcat02在容器内的ip地址,如: http://172.17.0.2:8080/访问tomcat02的欢迎界面,容器内ip可以通过docker inspect 容器id/name 进行查看

  • 默认docker在创建容器时将所有容器都连接到docker0网桥上,默认在docker0网桥的容器都可以使用容器名字进行通信,注意: 使用容器名称必须使用自定义网桥,不能使用默认的docker0

瓶颈:

在这里插入图片描述
在这里插入图片描述

相信大家也看出问题所在了,如果有多个项目都部署在同一个网桥下面,那么会导致该网桥负载压力过大,会造成内网瓶颈,因此最好的解决办法就是一个项目一个网桥


Docker 网络相关的命令列表

其中有些命令选项只有在 Docker 服务启动的时候才能配置,而且不能马上生效。

  • -b BRIDGE 或 --bridge=BRIDGE 指定容器挂载的网桥
  • --bip=CIDR 定制 docker0 的掩码
  • -H SOCKET… 或 --host=SOCKET… Docker 服务端接收命令的通道
  • --icc=true|false 是否支持容器之间进行通信
  • --ip-forward=true|false 请看下文容器之间的通信
  • --iptables=true|false 是否允许 Docker 添加 iptables 规则
  • --mtu=BYTES 容器网络中的 MTU

下面2个命令选项既可以在启动服务时指定,也可以在启动容器时指定。在 Docker 服务启动的时候指定则会成为默认值,后面执行 docker run 时可以覆盖设置的默认值。

  • --dns=IP_ADDRESS… 使用指定的DNS服务器
  • --dns-search=DOMAIN… 指定DNS搜索域

最后这些选项只有在 docker run 执行时使用,因为它是针对容器的特性内容。

  • -h HOSTNAME 或 --hostname=HOSTNAME 配置容器主机名
  • --link=CONTAINER_NAME:ALIAS 添加到另一个容器的连接
  • --net=bridge|none|container:NAME_or_ID|host 配置容器的桥接模式
  • -p SPEC 或 --publish=SPEC 映射容器端口到宿主主机
  • -P or --publish-all=true|false 映射容器所有端口到宿主主机

容器访问控制

容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现。iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。

容器访问外部网络

容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。

代码语言:javascript
复制
$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

如果为 0,说明没有开启转发,则需要手动打开。

代码语言:javascript
复制
$sysctl -w net.ipv4.ip_forward=1

如果在启动 Docker 服务的时候设定 --ip-forward=true, Docker 就会自动设定系统的 ip_forward 参数为 1。


容器之间访问

容器之间相互访问,需要两方面的支持。

容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到 docker0 网桥上。

本地系统的防火墙软件 – iptables 是否允许通过。


访问所有端口

当启动 Docker 服务(即 dockerd)的时候,默认会添加一条转发策略到本地主机 iptables 的 FORWARD 链上。策略为通过(ACCEPT)还是禁止(DROP)取决于配置–icc=true(缺省值)还是 --icc=false。当然,如果手动指定 --iptables=false 则不会添加 iptables 规则。

可见,默认情况下,不同容器之间是允许网络互通的。如果为了安全考虑,可以在 /etc/docker/daemon.json 文件中配置 {“icc”: false} 来禁止它。


访问指定端口

在通过 -icc=false 关闭网络访问后,还可以通过 --link=CONTAINER_NAME:ALIAS 选项来访问容器的开放端口。

例如,在启动 Docker 服务时,可以同时使用 icc=false --iptables=true 参数来关闭允许相互的网络访问,并让 Docker 可以修改系统中的 iptables 规则。

此时,系统中的 iptables 规则可能是类似

代码语言:javascript
复制
$ sudo iptables -nL
...
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  0.0.0.0/0            0.0.0.0/0
...

之后,启动容器(docker run)时使用 --link=CONTAINER_NAME:ALIAS 选项。Docker 会在 iptable 中为 两个容器分别添加一条 ACCEPT 规则,允许相互访问开放的端口(取决于 Dockerfile 中的 EXPOSE 指令)。

当添加了 --link=CONTAINER_NAME:ALIAS 选项后,添加了 iptables 规则。

代码语言:javascript
复制
$ sudo iptables -nL
...
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  172.17.0.2           172.17.0.3           tcp spt:80
ACCEPT     tcp  --  172.17.0.3           172.17.0.2           tcp dpt:80
DROP       all  --  0.0.0.0/0            0.0.0.0/0

注意:–link=CONTAINER_NAME:ALIAS 中的 CONTAINER_NAME 目前必须是 Docker 分配的名字,或使用 --name 参数指定的名字。主机名则不会被识别。


映射容器端口到宿主主机的实现

默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。

容器访问外部实现

容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址。这是使用 iptables 的源地址伪装操作实现的。

查看主机的 NAT 规则。

代码语言:javascript
复制
$ sudo iptables -t nat -nL
...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16       !172.17.0.0/16
...

其中,上述规则将所有源地址在 172.17.0.0/16 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址。


外部访问容器实现

容器允许外部访问,可以在 docker run 时候通过 -p 或 -P 参数来启用。

不管用那种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则。

使用 -P 时:

代码语言:javascript
复制
$ iptables -t nat -nL
...
Chain DOCKER (2 references)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:49153 to:172.17.0.2:80

使用 -p 80:80 时:

代码语言:javascript
复制
$ iptables -t nat -nL
Chain DOCKER (2 references)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

注意:

这里的规则映射了 0.0.0.0,意味着将接受主机来自所有接口的流量。用户可以通过 -p IP:host_port:container_port 或 -p IP::port 来指定允许访问容器的主机上的 IP、接口等,以制定更严格的规则。

如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件 /etc/docker/daemon.json 中添加如下内容。

代码语言:javascript
复制
{
  "ip": "0.0.0.0"
}

查看网络信息

代码语言:javascript
复制
# docker network ls

创建一个网桥

代码语言:javascript
复制
# docker network create -d bridge 网桥名称

删除一个网桥

代码语言:javascript
复制
# docker network rm 网桥名称

容器之间使用网络通信

代码语言:javascript
复制
# 1.查询当前网络配置
- docker network ls
代码语言:javascript
复制
NETWORK ID          NAME                DRIVER              SCOPE
8e424e5936b7        bridge              bridge              local
17d974db02da        docker_gwbridge     bridge              local
d6c326e433f7        host                host                local
代码语言:javascript
复制
# 2.创建桥接网络
- docker network create -d bridge info
代码语言:javascript
复制
[root@centos ~]# docker network create -d bridge info
6e4aaebff79b1df43a064e0e8fdab08f52d64ce34db78dd5184ce7aaaf550a2f
[root@centos ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
8e424e5936b7        bridge              bridge              local
17d974db02da        docker_gwbridge     bridge              local
d6c326e433f7        host                host                local
6e4aaebff79b        info                bridge              local
代码语言:javascript
复制
# 3.启动容器指定使用网桥
- docker run -d -p 8890:80 --name nginx001 --network info nginx 
- docker run -d -p 8891:80 --name nginx002 --network info nginx 
	`注意:一旦指定网桥后--name指定名字就是主机名,多个容器指定在同一个网桥时,可以在任意一个容器中使用主机名与容器进行互通`
代码语言:javascript
复制
[root@centos ~]# docker run -d -p 8890:80 --name nginx001 --network info nginx 
c315bcc94e9ddaa36eb6c6f16ca51592b1ac8bf1ecfe9d8f01d892f3f10825fe
[root@centos ~]# docker run -d -p 8891:80 --name nginx002 --network info nginx
f8682db35dd7fb4395f90edb38df7cad71bbfaba71b6a4c6e2a3a525cb73c2a5
[root@centos ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
f8682db35dd7        nginx               "/docker-entrypoint.…"   3 seconds ago       Up 2 seconds        0.0.0.0:8891->80/tcp   nginx002
c315bcc94e9d        nginx               "/docker-entrypoint.…"   7 minutes ago       Up 7 minutes        0.0.0.0:8890->80/tcp   nginx001
b63169d43792        mysql:5.7.19        "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        3306/tcp               mysql_mysql.1.s75qe5kkpwwttyf0wrjvd2cda
[root@centos ~]# docker exec -it f8682db35dd7 /bin/bash
root@f8682db35dd7:/# curl http://nginx001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
.....

网络常用命令总结

代码语言:javascript
复制
docker中网络类型:
bridge : 桥接(默认),B和C通过A来连接,A就是路由
none: 不配置网络
host: 主机模式,和宿主机共享网络;
container: 容器网络联通(用的少,局限性大)

自定义网桥
docker network create -d bridge(默认) 网络名称

创建网络  --driver 是网络模式,--subnet是子网掩码,后面的/16表示可以生成6万多个ip, --gateway是网关地址
docker network create 网络名称 --driver bridge --subnet 192.168.0.1/16 --gateway 192.168.0.2 mynet


查看网路
docker network ls

查看某一个网络的细节
docker network inspect 网络名

删除一个网络
docker network rm 网络名
docker network prune 删除所有未被使用到的网络名

运行多个容器在指定网络中

1.启动容器时明确指定容器使用哪个网络
docker run -d --network 网络名称

2.启动之后容器加入到某个网络中
docker network connect 网络名 容器id(name)

断开容器的网络 (容器必须是运行状态才能断开连接)
docker network disconnect 网络名称 容器名称

不同的容器只要在同一个网络下面,便可以通过容器内的ip互相访问,但是只有在自定义网络下,才可以通过容器名访问


打通自定义网络和默认网络的连接

自定义网络和默认网络默认是不通的,这样就起到了隔离的作用,那如果我们想要打通这两个网络应该怎么办呢?

其实很简答,docker已经帮我们想好了,只需要使用 connect 指令即可

代码语言:javascript
复制
# 执行以下命令打通 默认网络和自定义网络
docker network connect mynet centos_1

打通后,默认网络和自定义网络就可以互相ping啦

代码语言:javascript
复制
# 默认网络的容器 ping 自定义网络的容器 
[root@VM_0_5_centos ~]# docker exec -it centos_1 ping centos01_mynet 
PING centos01_mynet (192.168.0.1) 56(84) bytes of data.
64 bytes from centos01_mynet.mynet (192.168.0.1): icmp_seq=1 ttl=64 time=0.037 ms
64 bytes from centos01_mynet.mynet (192.168.0.1): icmp_seq=2 ttl=64 time=0.051 ms
64 bytes from centos01_mynet.mynet (192.168.0.1): icmp_seq=3 ttl=64 time=0.048 ms

#  自定义网络的容器 ping 默认网络的容器
[root@VM_0_5_centos ~]# docker exec -it centos02_mynet ping centos_1 
PING centos_1 (192.168.0.4) 56(84) bytes of data.
64 bytes from centos_1.mynet (192.168.0.4): icmp_seq=1 ttl=64 time=0.038 ms
64 bytes from centos_1.mynet (192.168.0.4): icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from centos_1.mynet (192.168.0.4): icmp_seq=3 ttl=64 time=0.048 ms

自定义网络的连接原理

当我们创建自定义网卡后,想要联通某个容器,它是直接和容器内的网卡连接的,而不是去连接自定义网络的网卡;它们之间的关系如下图

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Docker重学系列之高级网络篇
  • 高级网络配置
    • 说明
      • veth-pair技术
        • 网络小结
          • Docker 网络相关的命令列表
            • 容器访问控制
              • 容器访问外部网络
              • 容器之间访问
              • 访问所有端口
              • 访问指定端口
            • 映射容器端口到宿主主机的实现
              • 容器访问外部实现
              • 外部访问容器实现
            • 查看网络信息
              • 创建一个网桥
                • 删除一个网桥
                  • 容器之间使用网络通信
                  • 网络常用命令总结
                  • 打通自定义网络和默认网络的连接
                    • 自定义网络的连接原理
                    相关产品与服务
                    容器服务
                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档