对于MySQL而言,网络很重要,这是客户端应用程序和其他副本能够成功访问服务器所依赖的基础资源。容器化的MySQL服务的行为由运行“docker run”命令的时候如何生成MySQL镜像来决定。使用Docker单主机网络,MySQL容器可以运行在隔离的环境里(仅仅可以被在相同网络里的容器访问),或者运行在开放环境里(这时MySQL服务完全暴露给外部),或者MySQL实例只是运行着但是没有任何网络。 这篇博文里,将继续介绍Docker是如何处理单主机网络的,以及MySQL容器如何利用这个功能。 3种类型网络默认来说,Docker安装时在宿主机上创建了3个网络:$ docker network ls NETWORK ID NAME DRIVER 1a54de857c50 host host 1421a175401a bridge bridge 62bf0f8a1267 none null 每个网络的驱动都有自己的特征,下面将详细讨论。 Host网络host网络将容器添加到宿主机的网络堆栈上。你可以认为容器所运行的网络连接到了和宿主机相同的网络接口上。它的特征如下:
让我们使用“--net=host”在宿主网络上创建一个容器: $ docker run \ --name=mysql-host \ --net=host \ -e MYSQL_ROOT_PASSWORD=mypassword \ -v /storage/mysql-host/datadir:/var/lib/mysql \ -d mysql 查看容器网络接口,可以看到容器内的网络配置和宿主机是完全一样的: [machine-host]$ docker exec -it mysql-host /bin/bash [container-host]$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:0c:29:fa:f6:30 brd ff:ff:ff:ff:ff:ff inet 192.168.55.166/24 brd 192.168.55.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fefa:f630/64 scope link valid_lft forever preferred_lft forever 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:93:50:ee:c8 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:93ff:fe50:eec8/64 scope link 这么设置时,容器不需要在iptables里添加任何转发规则,因为它已经attach到了和宿主一样的网络上。所以,不支持使用参数“-p”的端口映射,并且Docker不会管理运行在这种类型网络上的容器的防火墙规则。 查看宿主机的侦听端口,可以看到3306端口正在侦听: [machine-host]$ netstat -tulpn | grep 3306 tcp6 0 0 :::3306 :::* LISTEN 25336/mysqld 在Docker宿主网络上运行MySQL容器类似于在宿主机上安装了一个标准的MySQL服务器。这仅仅在你希望将这台宿主机作为独占的MySQL服务器,同时由Docker管理的时候才有用。 这里,容器架构如下图所示: 在host网络上创建的容器能够访问在默认docker0以及用户定义的bridge网络上的容器。 Bridge网络桥接网络允许多个网络独立通信,同时保证同一台物理宿主机上网络之间的隔离。你可以认为这类似于宿主机内的另一种内部网络。仅仅那些处在相同网络里的容器才能够互相访问,并且能够访问宿主机。如果宿主机能够访问外界,那么容器也就可以。有两种类型的bridge网络:
默认bridge(docker0)默认的bridge网络,docker0在Docker安装的时候会自动创建出来。可以使用“ifconfig”或者“ip a”命令来验证这一点。默认的IP范围是172.17.0.1/16,可以在/etc/default/docker (Debian) 或者/etc/sysconfig/docker (RedHat)里改变该值。如何更改参考Docker文档。直接开始示例。如果不在“docker run”命令里显式指定“-net”参数,Docker会在默认的docker0网络下创建容器: $ docker run \ --name=mysql-bridge \ -p 3307:3306 \ -e MYSQL_ROOT_PASSWORD=mypassword \ -v /storage/mysql-bridge/datadir:/var/lib/mysql \ -d mysql 查看容器的网络接口,可以看到Docker创建了一个网络接口,eth0(不包含localhost): [machine-host]$ docker exec -it mysql-container-bridge /bin/bash [container-host]$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever 默认来说,Docker利用iptables来管理转发到bridge网络的包。每个出站的连接看上去都是从宿主机自己的IP地址之一发送出去的。如下是上述容器启动后机器的NAT chain: [machine-host]$ iptables -L -n -t nat Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0 MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:3306 Chain DOCKER (2 references) target prot opt source destination DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3307 to:172.17.0.2:3306 上述规则,基于“docker run” 命令行里指定的端口映射参数 “-p 3307:3306”,允许3307端口暴露在宿主机上。查看宿主机的netstat输出,可以看到MySQL在端口3307上侦听,属于docker-proxy进程: [machine-host]$ netstat -tulpn | grep 3307 tcp6 0 0 :::3307 :::* LISTEN 4150/docker-proxy 这种情况下,容器搭建如下图所示: 默认的bridge网络支持端口映射和容器链接的使用,允许docker0网络上的容器间的通信。关于如何通过暴露环境变量链接容器,以及如何通过/etc/hosts文件自动配置主机映射,Docker文档提供了详尽的信息。 用户定义的bridgeDocker让用户可以创建自定义的bridge网络,也就是用户定义的bridge网络(也可以创建用户定义的overlay网络,但是我们计划在下一篇博文里讨论这一点)。它的行为和docker0网络一样,网络里的每个容器能够立即和网络里的其他容器通信。但是,网络本身将容器和外部网络隔离开了。该网络方式的最大的好处在于,所有容器都能够解析容器名。考虑如下网络: [machine-host]$ docker network create mysql-network 然后,在用户定义网络里创建5个MySQL容器: [machine-host]$ for i in {1..5}; do docker run --name=mysql$i --net=mysql-network -e MYSQL_ROOT_PASSWORD=mypassword -d mysql; done 现在,登录进其中一个容器(mysql3): [machine-host]$ docker exec -it mysql3 /bin/bash 我们随后可以ping通该网络里的所有容器,而完全不需要链接它们: [mysql3-container]$ for i in {1..5}; do ping -c 1 mysql$i ; done PING mysql1 (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.151 ms --- mysql1 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.151/0.151/0.151/0.000 ms PING mysql2 (172.18.0.3): 56 data bytes 64 bytes from 172.18.0.3: icmp_seq=0 ttl=64 time=0.138 ms --- mysql2 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.138/0.138/0.138/0.000 ms PING mysql3 (172.18.0.4): 56 data bytes 64 bytes from 172.18.0.4: icmp_seq=0 ttl=64 time=0.087 ms --- mysql3 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.087/0.087/0.087/0.000 ms PING mysql4 (172.18.0.5): 56 data bytes 64 bytes from 172.18.0.5: icmp_seq=0 ttl=64 time=0.353 ms --- mysql4 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.353/0.353/0.353/0.000 ms PING mysql5 (172.18.0.6): 56 data bytes 64 bytes from 172.18.0.6: icmp_seq=0 ttl=64 time=0.135 ms --- mysql5 ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.135/0.135/0.135/0.000 ms 如果查看resolver的设置,可以看到Docker配置为一个内嵌的DNS服务器: [mysql3-container]$ cat /etc/resolv.conf search localdomain nameserver 127.0.0.11 options ndots:0 内嵌的DNS服务器在容器连接到的网络上,这里是mysql-network时,维护容器名称和其IP地址的映射。该功能辅助网络里的节点发现,在使用MySQL集群技术,比如MySQL复制,Galera Cluster或者MySQL Cluster,构建MySQL容器集群的时候非常有用。 这里,容器搭建如下图所示: 默认 vs. 用户定义Bridge下表展示了这两种网络的主要不同点:No网络我们还可以通过在“docker run”命令里指定“--net=none”创建出没有任何网络的容器。只能通过交互式shell才能访问这样的容器。该节点上不会配置任何额外的网络接口。如下命令: [machine-host]$ docker run --name=mysql0 --net=none -e MYSQL_ROOT_PASSWORD=mypassword -d mysql 通过查看容器的网络接口,仅仅localhost的接口是可用的: [machine-host]$ docker exec -it mysql0 /bin/bash [mysql0-container]$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 在network none里的容器意味着它无法加入任何网络。虽然如此,MySQL容器仍然在运行,用户可以从shell里通过localhost或者socket使用mysql客户端命令行直接访问该实例: [mysql0-container]$ mysql -uroot -pmypassword -h127.0.0.1 -P3306 mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 6 Server version: 5.7.13 MySQL Community Server (GPL) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> 在该网络上运行的实例的用例是验证MySQL的备份,通过测试恢复流程,准备通过使用,比如Percona Xtrabackup,所创建备份,或者在不同版本的MySQL服务器上测试查询语句。 这里,容器搭建如下图所示: 本片博文至此完结。下一篇博文里,会继续研究和Docker Swarm一起使用的多主机网络(使用overlay网络),Docker Swarm是管理多台宿主机上容器的编排工具。(责任编辑:最模板) |