对于网络来说,只要能解决连通性和隔离性,那么这个网络就是可靠的
1.docker网络通讯
可以把网桥理解为一个三层交换,三层交换就是二层交换+三层转发,相当于加了简单路由功能的交换机
- 虚拟网卡对:
- 创建的时候就是一对。两端的,一个放在网桥上(或者网卡),一个放在容器内部,在网桥上的不需要配置地址,就像是在交换机上,插上就能用
- 虚拟网卡对一定要在根空间下创建才可以拿到子空间,但是不能从子空间拿到根空间
目前linux支持的名字空间隔离:
- 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
# 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原理
- 容器内部的虚拟网卡对都是搭在网桥上的,而网桥和物理机的真实网卡工作在同一个网络栈内,只需要在网络栈内做对应的SNAT和DANT转发就可以实现容器内部与外界的通信了(网桥是带有三层交换的,也就是带有转发功能),而容器与容器之间只要通过网桥的二层交换就可以实现了
2.3优缺点对比
-
容器:
资源消耗更高,NAT消耗的资源还是蛮大的,容器每次通讯都需要nat转发,效率低
(实际上lamp中只有Apache需要SNAT,DNAT转发,)
所有的通过NAT转换显示的都是真实机的MAC地址,永远不会冲突
对无线网络非常支持 -
传统:
效率高
容易冲突,每个网卡都有自己的MAC地址,但是每个虚拟机的网卡都是虚拟出来的,如果有几百台MAC地址,并且都是在同一个局域网中,就容易出现冲突
隧道设备(tun,tap)对无线网络的支持非常差,但凡你的机器中出现无线网络,那么你的整个网络都容易瘫痪
3.多个物理机上搭建同一个项目不适合DOCKER
- Apache在向MySQL请求动态数据时,会做很多NAT转换,浪费很多的资源,所以DOCKER不适合在多个物理机上搭建同一个项目
- 而如果都在一个物理机上,那么都是通过网桥进行传输的,只有一部分服务需要对外通讯进行NAT转换。
- 外部访问内部时的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...
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 用于指定容器的网络通讯方式,有以下四个值
-
用docker network ls 查看容器的网络通讯方式
网卡ID————名字————驱动类型————作用域
如果有overly的话,overly表示扁平化网络
-
bridge:Docker 默认方式,网桥模式
默认的都是网桥模式 -
none:容器没有网络栈
- 没有网络栈,导致他无法和其他的容器,以及其他的虚拟机通讯
比如交通管理的时候离线分析,车牌扫描系统,先给他提供数据,然后她离线分析,直接上报,防止被篡改。
用目录共享的方式提供给R1数据,R1 和R2 都是在同一个物理机内,通过目录共享到容器内部
- 没有网络栈,导致他无法和其他的容器,以及其他的虚拟机通讯
-
container:使用其它容器的网络栈,Docker容器会加入其它容器的 network namespace
- --network container:(ContainerName)
非常好用,十分适合lnmp的环境中,nginx是网桥模式,PHP --net container:上一个容器名
只是网络共享,各自有各自的用户,目录,空间等等
在后面的k8s中被广泛使用,但是叫POD,豆荚
- --network container:(ContainerName)
-
host:表示容器使用 Host 的网络,没有自己独立的网络栈。容器可以完全访问 Host 的网络,不安全 --network host
- 网络是和物理机用一个,但是进程编号,文件系统,目录,空间等等都是各有各的,比如,安了一个nginx,你要是想删除的话,在原本的Linux中会遗留很多目录和文件之类,但是在容器中的nginx就可以删除的干干净净,这就是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 修改网桥信息
了解一下就好
网桥地址——安全的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的服务,只不过是用户态的
他先启动,你可以在它的配置文件中写很多子配置文件,写着服务该怎么启动,哪怕服务挂了,他也会帮你重启服务
-
可以看一下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命令一建创建虚拟网卡对,安装并启动