时隔二十天,喵哥又开始设置docker里centos容器的网络。目标是实现在宿主——Windows10下面可以访问docker中centos容器里的MySQL数据库。
之前一篇博客记录的是喵哥妥协解决这个问题的方案——在172.17.0.0这个网段里面设置两个centos容器,这样就可以保证两者互相访问数据库,但这没有达到喵哥对数据库服务器的要求——在宿主(Windows10)下编程使用数据库。
这一次,喵哥从docker的网络模式开始学习、理解、然后去解决问题。
1.docker的网络模式
Docker常见的网络模式有:
- Bridge模式 --net=bridge(默认)
- Host模式 --net=host
- Container模式 --net=container:指定容器名
- None模式 --net=none
- 用户自定义模式
1.1bridge模式
Docker网络的默认模式,在docker run启动容器的时候,如果不加--net参数,就默认采用这种网络模式。其特点如下:
-
使用一个 linux bridge,默认为 docker0
-
使用 veth 对,一头在容器的网络 namespace 中,一头在 docker0 上
-
该模式下Docker Container不具有一个公有IP,因为宿主机的IP地址与veth pair的 IP地址不在同一个网段内
-
Docker采用 NAT 方式,将容器内部的服务监听的端口与宿主机的某一个端口port 进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部
-
外界访问容器内的服务时,需要访问宿主机的 IP 以及宿主机的端口 port
-
NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。
-
容器拥有独立、隔离的网络栈;让容器和宿主机以外的世界通过NAT建立通信
Docker完成以上网络配置的过程大致是这样的:
1. 在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
2. Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。另一端放在主机中,以veth65f9这样类似的名字命名,并将这个网络设备加入到docker0网桥中。
容器要跟外埠网络通信,还需要一个NAT路由器,在Windows下它的名称为dockerNAT。
外界的机器要访问docker容器,可以用端口映射的办法把docker容器的端口跟宿主的端口做一个映射即可。
iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.19:8000
在Windows下是:
netsh interface portproxy add v4tov4 listenaddress=主机的IP listenport=50001 connectaddress=172.17.0.2 connectport=3306
然而,对于我来说,这些还是不够。虽然,仿佛打通了外界机器与容器的通信,但是消息往往就到宿主就找不到路了。因为没有路由表。在宿主添加10.0.75.1到172.17.0.0网段的路由表,这样就可以了。
1.2host模式
定义:
Host 模式并没有为容器创建一个隔离的网络环境。而之所以称之为host模式,是因为该模式下的 Docker 容器会和 host 宿主机共享同一个网络 namespace,故 Docker Container可以和宿主机一样,使用宿主机的eth0,实现和外界的通信。换言之,Docker Container的 IP 地址即为宿主机 eth0 的 IP 地址。其特点包括:
-
这种模式下的容器没有隔离的 network namespace
-
容器的 IP 地址同 Docker host 的 IP 地址
-
需要注意容器中服务的端口号不能与 Docker host 上已经使用的端口号相冲突
-
host 模式能够和其它模式共存
1.3container模式
Container 网络模式是 Docker 中一种较为特别的网络的模式。处于这个模式下的 Docker 容器会共享其他容器的网络环境,因此,至少这两个容器之间不存在网络隔离,而这两个容器又与宿主机以及除此之外其他的容器存在网络隔离。
1.4none模式
网络模式为 none,即不为 Docker 容器构造任何网络环境。一旦Docker 容器采用了none 网络模式,那么容器内部就只能使用loopback网络设备,不会再有其他的网络资源。Docker Container的none网络模式意味着不给该容器创建任何网络环境,容器只能使用127.0.0.1的本机网络。
2.解决
其实在1.1中已经把解决的方案大致说明了。
只要添加一个10.0.75.1网关到172.17.0.0网段的路由表即可。由于是在宿主访问,不需要添加端口映射表。
route add -p 172.17.0.0 mask 255.255.255.0 10.0.75.2
然后只要在容器中的MySQL设置好访问权限即可:
mysql> grant all PRIVILEGES on db_name.* to 'username'@'xxx.xxx.xx.x' identified by 'password' WITH GRANT OPTION;
#说明#
/*
数据库的授权用grant:
grant 权限 on 数据库.表 to 用户 【identified by '密码'】 with grant option;
其中,
权限有:select、insert、update、delete和all privileges。
数据库为本地存在的数据库名,表为数据库中的表,如果要全选某个项目,可用*代替,如
*.*表示所有数据库的表,exp_country.*表示exp_country中的所有表,max_sal.k1表示max_sal中的k1表。
用户,可以在本地自建。也可以是远程的,用'username'@'IP地址'表示。
密码为可选项。
附带的with grant option可以使得被授权用户也有赋予其他用户权限的权力
数据库收回权限用revoke:
revoke 权限 【on 数据库.表】 option from 用户;
*/
例如,喵哥的centos容器需要通过10.0.75.1来转发数据包,所以在MySQL中赋予权限的对象是10.0.75.1.
grant all PRIVILEGES on db_name.* to 'username'@'10.0.75.1' identified by 'password' WITH GRANT OPTION;
然后就可以在Windows端的MySQL登录centos的MySQL数据库了。