Docker网络原理
本文最后更新于110 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

对于网络来说,只要能解决连通性和隔离性,那么这个网络就是可靠的

1.docker网络通讯

可以把网桥理解为一个三层交换,三层交换就是二层交换+三层转发,相当于加了简单路由功能的交换机

  • 虚拟网卡对:
    • 创建的时候就是一对。两端的,一个放在网桥上(或者网卡),一个放在容器内部,在网桥上的不需要配置地址,就像是在交换机上,插上就能用
    • 虚拟网卡对一定要在根空间下创建才可以拿到子空间,但是不能从子空间拿到根空间

目前linux支持的名字空间隔离:

file

  • UTS:假如一台机器上有Apache和nginx,那么如果想让他们有不同的主机名,那么名字空间内就需要有UTS
  • IPC:一种编程的概念
  • PID:每个容器有自己的PID为一的进程号,在linux中基本都是linux,init,systemd.也就是说,如果一个进程在启动过程中调用了namespace的CLONE_NEWPID,那么他就可以在相对的空间内部设置自己的独立的PID
  • NetWork:可以在相对的新的空间中设置新的端口等等
  • MOUNT:设置新的挂载点
  • User:有自己独立的用户和用户组(这个要求内核3.8版本)
    但是这些都是docker基于Linux系统内核模拟出来的,或者说是二次开发的,一定是没有原生的稳定性好

Namespace - 网络

netns 是在 linux 中提供网络虚拟化的一个项目,使用 netns 网络空间虚拟化可以在本地虚拟化出多个网络环境,目前 netns 在 lxc 容器中被用来为容器提供网络

使用 netns 创建的网络空间独立于当前系统的网络空间,其中的网络设备以及 iptables 规则等都是独立的,就好像进入了另外一个网络一样

创建虚拟空间的网桥以及网卡信息需要在docker安装之前,因为docker为了防止别的网络和他们冲突,他把别的创建禁用了,只能自己创建网桥出来,否则极有可能两个相同网段的空间ping不通

# 创建虚拟网络空间
$ ip netns add r1

# 进入虚拟网络空间
$ ip netns exec ns1 bash

# 添加一对 veth 设备
$ ip link add veth1.1 type veth peer name veth1.2

# 将其中一块网卡放入至 ns1 网络名称空间之中
$ ip link set veth1.1 netns r1

# 更改网络名称
$ ip link set veth1.1 name eth0

# 启动网卡
$ ip link set eth0 up

# 设置网卡名称
$ ip addr add 10.0.0.11/24 dev eth0

# 启动回环网卡
$ ip link set lo up
# 创建 bridge
$ ip link add name br0 type bridge
$ ip link set br0 up
$ ip addr add 192.168.3.101/24 dev br0

# 将设备连接至网桥
$ sudo ip link set dev veth2.2  master br0

网络通信原理docker

file

# docker进程会创建两个(或多个)虚拟空间(可以ip  netns  ls查看)
ip netns add r1
# 先创建一个虚拟网卡对
ip link add veth1.1 type veth peer name veth1.2
# 并且把其中一个放在空间中当这个子空间的网卡
ip link set veth1.1 netns r1
# docker会进入这个的虚拟空间
ip netns exec ns1 bash
# 更改这个网络名称空间(子空间)的网卡的名称(ipconfig  -a  查看所有网卡信息)
ip link set veth1.1 name eth0
# 启动这张网卡和本地lo网卡
ip link set eth0 up
# 添加这个网卡的ip等信息
 ip addr add 10.0.0.11/24 dev eth0
# 退出网络名称空间回到根空间,启动虚拟网卡对的另一张网卡(虚拟网卡对都需要手动启动)
exit
ip link set veth1.2  up
# 此时,子空间和对应的网卡都已经设置好了,就需要把他们放在同一个交换机上就可以互相通信了,也就是我们的网桥
# 创建网桥,启动网桥,给网桥设置IP地址(随意值,不一定都是10.1,但是需要和容器内的属于一个网段)
 ip link add name br0 type bridge
 ip link set br0 up
 ip addr add 10.0.0.111/24 dev br0
# 将容器内部的IP地址搭在网桥上
sudo ip link set dev veth2.2  master br0

每有一个容器重复一遍上述操作(同一网段的)!!!


2. 容器与传统虚拟化与外界网络通讯原理

2.1DOCKER原理

file

  • 容器内部的虚拟网卡对都是搭在网桥上的,而网桥和物理机的真实网卡工作在同一个网络栈内,只需要在网络栈内做对应的SNAT和DANT转发就可以实现容器内部与外界的通信了(网桥是带有三层交换的,也就是带有转发功能),而容器与容器之间只要通过网桥的二层交换就可以实现了

2.3优缺点对比

  • 容器:
    资源消耗更高,NAT消耗的资源还是蛮大的,容器每次通讯都需要nat转发,效率低
    (实际上lamp中只有Apache需要SNAT,DNAT转发,)
    所有的通过NAT转换显示的都是真实机的MAC地址,永远不会冲突
    对无线网络非常支持

  • 传统:
    效率高
    容易冲突,每个网卡都有自己的MAC地址,但是每个虚拟机的网卡都是虚拟出来的,如果有几百台MAC地址,并且都是在同一个局域网中,就容易出现冲突
    隧道设备(tun,tap)对无线网络的支持非常差,但凡你的机器中出现无线网络,那么你的整个网络都容易瘫痪


3.多个物理机上搭建同一个项目不适合DOCKER

file

  • Apache在向MySQL请求动态数据时,会做很多NAT转换,浪费很多的资源,所以DOCKER不适合在多个物理机上搭建同一个项目
  • 而如果都在一个物理机上,那么都是通过网桥进行传输的,只有一部分服务需要对外通讯进行NAT转换。
    file
  • 外部访问内部时的DOCKER动作是docker自己开发的,这就是装完docker需要重启的原因
    判断这个报文是不是找docker的,是的话就匹配到docker链,DOCKER链上有一个DNAT转换的规则

3.1 隐藏名字空间

# 查看当前容器的名字空间 ID
$ docker inspect --format='{{.State.Pid}} '  容器名

# 创建目录,防止未创建
$ mkdir /var/run/netns
#ip netns show  就是在  /var/run/netns下找数据,如果有的话,就显示出来,没有就不显示,老版本自动就是有的,但是新版本为了安全就把他给删除了,实际上是/proc/1234/ns/net链接过来的。就是为了有人能直接从这个接口进入到容器的内部

# 接下来,在 /proc 目录(保存进程的所有相关信息)下,把对应的网络名字空间文件链接到 /var/run/netns 下面
# 1234为进程号PID
$ ln -s /proc/1234/ns/net /var/run/netns/1234

# 然后,就可以通过正常的系统命令来查看或访问容器的名字空间了。例如
$ ip netns show
$ ip netns exec 1234 ifconfig eth0 172.16.0.10/16...

file


4.docker网络模式的修改

默认模式就是网桥模式

4.1 docker本身进程的修改

-b, --bridge=””

  • 指定 Docker 使用的网桥设备,默认情况下 Docker 会自动创建和使用
    docker0 网桥设备,通过此参数可以使用已经存在的设备
    实际上就是修改这个配置文件/usr/lib/systemd/system/docker.service,在exec start 后面加这些子参数

--bip

  • 指定 Docker0 的 IP 和掩码,使用标准的 CIDR 形式,如 10.10.10.10/24
    可以在不同的物理机中使用相同的网段,用在k8s中管理集群,这就是扁平化网络,每个物理机的容器之间都可以在同一个广播域工作,可用于更改docker网段,江北演示环境曾与科室网段冲突,导致改科室无法访问k8s的集群,所以更改网段,或者修改daemon.json文件
  • 选项用于设置 Docker 默认桥接网络的 IP 地址和子网。通过该选项,您可以指定 Docker 默认桥接网络的 IP 地址范围。例如:

    docker daemon -bip=172.19.0.1/16

--dns

  • 配置容器的 DNS,在启动 Docker 进程时添加,所有容器全部生效

    docker run --dns=8.8.8.8 --dns=8.8.4.4 my-container

4.2 docker容器修改

也是用在docker run 后

--dns 用于指定启动的容器的 DNS

--net 用于指定容器的网络通讯方式,有以下四个值

file

  • 用docker network ls 查看容器的网络通讯方式
    网卡ID————名字————驱动类型————作用域
    如果有overly的话,overly表示扁平化网络

    file

  • bridge:Docker 默认方式,网桥模式
    默认的都是网桥模式

  • none:容器没有网络栈

    • 没有网络栈,导致他无法和其他的容器,以及其他的虚拟机通讯
      比如交通管理的时候离线分析,车牌扫描系统,先给他提供数据,然后她离线分析,直接上报,防止被篡改。
      用目录共享的方式提供给R1数据,R1 和R2 都是在同一个物理机内,通过目录共享到容器内部
      file
  • container:使用其它容器的网络栈,Docker容器会加入其它容器的 network namespace

    • --network container:(ContainerName)
      非常好用,十分适合lnmp的环境中,nginx是网桥模式,PHP --net container:上一个容器名
      只是网络共享,各自有各自的用户,目录,空间等等
      在后面的k8s中被广泛使用,但是叫POD,豆荚
      file
  • host:表示容器使用 Host 的网络,没有自己独立的网络栈。容器可以完全访问 Host 的网络,不安全 --network host

    • 网络是和物理机用一个,但是进程编号,文件系统,目录,空间等等都是各有各的,比如,安了一个nginx,你要是想删除的话,在原本的Linux中会遗留很多目录和文件之类,但是在容器中的nginx就可以删除的干干净净,这就是host模式
      但是这种模式很少用,因为不是很安全

4.3暴露端口

-p / P 选项的使用格式
     -p  <ContainerPort>:将制定的容器端口映射至主机所有地址的一个动态端口
     -p  <HostPort>:<ContainerPort>:映射至指定的主机端口
     -p  <IP>::<ContainerPort>:映射至指定的主机的 IP 的动态端口
     -p  <IP>:<HostPort>:<ContainerPort>:映射至指定的主机 IP 的主机端口
     -P(大):暴露所需要的所有端口,把dockerfile中的EXPORE声明的端口全部暴露出来,和物理机随机的端口绑定,假如一个容器运行十个nginx,-P暴露所有的端口,另一个LVS的容器利用脚本,比如tcpdump扫描指定机器开启的所有端口,(或者扫描他所有暴露的端口),就可以负载均衡了
  • docker port ContainerName 可以查看容器当前的映射关系

4.4 修改网桥信息

了解一下就好

file

网桥地址——安全的cidr——ipv6的cidr——数据包大小——默认网关——ipv6默认网关——dns


5.常见的隔离方式

  • 假如说我们要在当前的物理机上部署不同的项目,比如一台服务器上跑了农业公司的网站,林业的网站。某个电商的网站,某个煤矿公司的网站,某个医院的网站等等,他们公司的IT部门是很差劲的,但是需要有自己的网站,这年头皮包公司不一定有网站,但是没有网站的一定是皮包公司。
  • 如果一台机器上跑很多公司的网站,为了安全,就需要隔离,可以通过compose实现,因为docker-compose就是每个项目都在不同的广播域中

5.1 基础命令说明

# 查看当前可用的网络类型
$ docker network ls     

# 网络空间名称
$ docker network create -d 类型 
    # 类型分为:
        # overlay network
        # bridge network

5.2 独立至不同的网络命名空间进行隔离

#创建网络模式
$ docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" my-bridge-network-1
$ docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" my-bridge-network-2
create        创建网络
-d            指定驱动类型
--subnet      指定当前网段(和本机的网段不能冲突)
--gateway     指定网桥地址
​
$ docker run -d --network=my-bridge-network-1 --name 教育  hub.c.163.com/public/centos:6.7-tools

$ docker run -d --network=my-bridge-network-2 --name 种地  hub.c.163.com/public/centos:6.7-tools
#创建网络模式,主要是网段不相同,教育公司的网段下放他自己的web和db,农业种地的下也放他自己的
#可以ifconfig看见有了两个对应的br-xxxxxxxx网桥
#把对应的服务放在对应的网络模式下就好了
#测试,互相之间ping不同

5.3 使用 Linux 桥接器进行主机间的通讯

  • 直接把网桥放在物理网卡上,让br0来承载物理网卡的IP地址,网桥上承载着物理机的网络栈,其他的容器就可以通过veth来搭在br0上,效率就更高了,缺点依旧是传统虚拟化的缺点,假如有100多台物理机,物理机中又有很多容器,MAC地址冲突是很常见的,而且不通过网络栈,直接和外网想通,相对不安全

  • 网易的这个tools镜像封装了ssh服务
    可以看到启动命令是supervisord
    这个组件是Python开发的类似于systemd的服务,只不过是用户态的
    他先启动,你可以在它的配置文件中写很多子配置文件,写着服务该怎么启动,哪怕服务挂了,他也会帮你重启服务

    file

  • 可以看一下netstat,确认开启22端口,ssh的配置文件主要看允不允许root远程登录,允不允许密码,刚进去没有root密码可以passwd

  • 但是这种还是依赖于端口映射进行的远程连接,我们想要的是让容器拥有自己独立的IP地址
    首先就是删除原本的容器内部的网络信息(--network none)

  • 脚本创建
    由于Redhat数据经常变,网卡的配置文件在每个版本中都有一些变化,这就导致兼容性非常差,所以不如写个脚本,然后再/etc/rc.local中加入执行脚本

    #!/bin/bash
    ip addr del dev ens33 192.168.66.11/24
    #让网卡的所有权绑定在br0上
    ip link add link ens33 dev br0 type macvlan mode bridge
    ip addr add 192.168.66.11/24 dev br0
    ip link set dev br0 up
    #有网关就写,没有就不写
    ip route add default via 192.168.66.1 dev br0
  • 设置容器地址分配
    pipework——网桥名——容器名——给的ip——@网关(pipework命令一建创建虚拟网卡对,安装并启动)

    pipework br0 test 192.168.66.200/24@192.168.66.1

流程

  • 关闭第二张网卡,创建脚本,先删除ens33的ip,然后把ens33的ip给br0
    启动容器,基于之前的ssh镜像(要有密码),--network none,不要网卡
    pipework命令一建创建虚拟网卡对,安装并启动
    file

    file
男孩子都是香香软软的小猪
暂无评论

发送评论 编辑评论


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