文章目录
容器的原生网络
Docker网络是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),
即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器
容器网卡信息查看
首先是通过ip addr
查看查看docker的虚拟网卡信息,如下图看到,有个叫docker0的网卡,其网关是172.17.0.1
,网段是16位的,它代表的是容器默认的连接方式,网桥(bridge)模式。
后面创建的容器如果没有指定–net,那么都是基于这个docker0的网段来分配IP.
容器网络模式
docker在创建时默认会创建三种网络模式,bridge
,host
,none
docker network ls
如果容器指定了网络,docker run --network=
,就会多一种网络模式,container模式,如下是对这4种模式来做一个说明
网络模式 | 配置 | 说明 |
---|---|---|
bridge | –net=bridge | 默认就是该模式,此模式会为每个容器分配,设置IP等,并将容器连接到一个docker0的虚拟网桥,再通过docker0网桥以及Iptables nat表配置与宿主机通信。 |
host | –net=host | 容器和宿主机共享网络。容器不会虚拟出自己的网卡,配置自己的ip,而是使用宿主机的ip和端口 |
container | –net=[容器名字或容器id] | 容器和另外一个容器共享网络,创建容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围 |
none | –net=none | 该模式关闭了容器的网络功能 |
桥接模式
桥接模式有以下特点:
- 同一个网络下的容器可以相互访问
- 可以通过端口转发将其映射到宿主机上的另一个端口,可以被其他服务器访问到。
- 因为根据桥接的特性,可以直接访问外网。
通过上面的NETWORK ID
得到网络的详情信息
docker network inspect 98d7
如下图中,我们能看到其网络的网管信息,所关联的容器信息,以及代表的是docker0的网桥
brctl
可以通过
brctl
命令查看网桥详情,如果没有的话先安装
yum -y install brctl
brctl show
此图展示了容器在桥接模式下,和宿主机之间关系图
下图就是容器在访问外网internet,以及访问其他服务器的工作原理图:
- 容器中要访问外网,其实先要通过桥接模式,连接到宿主机上,将其内部的IP,端口转换成可以被访问的宿主机的IP,然后再通过路由器去访问公网。
- 容器在访问和宿主机同一网段的服务器时可以访问,但不能访问其内部的容器,因为容器网络不一样,要想要通信需要使用swarm来构建同一个网络。同时另外一个服务器不能直接访问宿主机上的容器,反之亦然;两台服务器上容器如果要进行通信只能通过端口转发后通过宿主机来进行。
注:一般宿主机的内网地址是,容器网络的网关地址,
docker network inspect bridge
host模式
- host的网络空间和宿主机是共享同一个的,它没有自己的端口和IP,而是使用宿主机的端口和IP。
- 它好处是外部主机与容器直接通信,不用再去NAT转发,提高性能。
- 它不好的地方,就是网络隔离性差,容易出现端口冲突。
- 应用场景:能确认所有容器端口不冲突且默认都需要对外暴露时使用。
如下图则是容器host模式和bridge模式的区别
可以看启动busybox容器为例子:
通过运行busybox容器可以看到,它的ip信息是宿主机的IP信息
container模式
此模式指定新创建的容器和已经存在的另一个容器共享同一个Network Namespace,而不是和宿主机共享。新建立容器不会创建自己的网卡,配置自己的IP。而是和一个容器共享IP,端口范围。
同样,两个容器除了网络方面,文件系统,进程都是隔离。两个容器的进程可以通过lo网卡进行通信。
举例:
假如构建一个busybox1,网络使用的是ubuntu容器的网络
none模式
none模式是指禁用网络功能,只有lo接口,在容器创建时使用--network none
none模式关闭了容器的网络功能,这种场景使用的很少,容器并不需要网络(例如只需要写磁盘卷的批处理任务)
比如需要创建一个busybox的容器,不需要网络的
docker run -d --name=busybox1 --net=none busybox:latest
端口映射
在docker中我们很多时候需要将容器中的服务能够被外部访问到,但它因为是内网不能直接被访问,只能通过将端口映射到宿主机上的端口才能被访问。其端口映射的参数是两个分别是-p
和-P
分别进行介绍:
-P(大写):
这表示外部端口,没有被使用过就行,内部端口使用默认,所以不需要去指定它
以创建redis的容器为例:
docker run -d --name=redis -P redis:latest
外部端口:32678
容器端口:默认的6379
-p(小写):
这是指定外部访问端口,需要指定宿主机端口以及容器端口,格式如下:
-p 宿主机端口:容器口号
在设定之前,需要先验证下宿主机上的端口号是否被占用
lsof -i:[宿主机端口]
以nginx配置为例子
docker run -d --name=nginx1 -p 81:80 nginx:latest
自定义网络
容器在使用集群swarm,或者固定ip 时,我们需要自己来创建网络,来方便管理。我们在创建网络时可以指定ip的网段,网络名称等
创建网络的格式:docker network create -d 网络类型 --subnet 网段内容 网络名称
让一个容器连接两个网络
docker network create -d bridge my_network
同时一个容器可以连接多个不同的网络
# 准备一个容器 busybox,专门来做测试,默认连接到bridge
docker run --name busybox -itd busybox:latest
# 将busybox连接mybridge 中
docker network connect mybridge busybox
连接后,容器将同时拥有 my-app-net 和 public-net 两个网络接口,可以通过这两个接口分别访问不同的网络。下面两个图片来查看busybox 的两个连接情况:
mybridge 网络:
bridge网络:
新建网络设置网段地址
新建网络
创建网段为172.10.0.0/16,网关为–gateway=172.10.0.1
docker network create --subnet=172.10.0.0/16 --gateway=172.10.0.1 -d bridge [网络名]
如何固定容器ip
容器一般默认使用了名叫 bridge的网络,在服务器重启后,容器的 ip 会自动变更 IP,这样子会导致,像一些项目环境,如nginx服务连接 fpm,连接 mysql,redis时 IP 变了都连接不了。所以需要固定下来
- 再和原先的名为 bridge的网络解除连接
请注意,如果容器已加入一个Docker网络中,则必须首先将其从该网络中删除,然后再将其加入到新网络中。
docker network disconnect bridge [容器]
- 新连接网络,并设置 ip
docker network connect [新网络名] --ip=172.10.0.2 [容器]
- 如果需要删除网络
使用以下命令将容器从当前Docker网络中删除:
docker network rm old_network