网络的启动与参数配置
首先,运行如下命令:
$ sudo service docker start
如果你是第一次启动docker网络,此时会默认建立一个docker0虚拟网桥。它实质上相当于一个二层网络交换机,可以实现局域网(LAN)之间的数据转发。在linux上,可以通过命令ifconfig
命令查看。
通过上图可以得知,docker0的网络配置情况如下:
IP Address: 172.17.0.1
Mask: 255.255.0.0
由此可得,docker的网络IP地址段为172.17.0.0/16
。之后,所有新建的容器网络都会按照如下的形式通信:
在没有修改默认配置之前,网络通信状况如下:
1. 所有的docker容器之间可以相互通信。当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。
2. 宿主机可以和 docker容器之间相互通信。
3. 宿主机可以和外网通信,docker容器不行(docker可以单向访问到外部网络)
容器和外部网络通信
容器可以主动访问外部网络主要依赖于iptables的规则,通过运行sudo iptables -t nat -nvL POSTROUTING
可以看到如下结果:
$ sudo iptables -t nat -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 4273 packets, 274K bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !br-d5879024a3e9 172.21.0.0/16 0.0.0.0/0
0 0 MASQUERADE all -- * !br-567f333b9de8 172.18.0.0/16 0.0.0.0/0
3 120 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
其中的第三条规则,是默认的docker网络的规则。它会将所有源地址在172.17.0.0/16网段,且不是从docker0接口发出的流量(即从容器中出来的流量),动态伪装为从系统网卡发出。MASQUERADE行动跟传统SNAT行动相比,好处是它能从网卡动态获取地址
如果外部容器想要访问docker容器,需要在执行docker run
时,添加-p
参数配置。例如:
$ docker run -it -p 3308:3306 --rm --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:latest
通过上面这条指令运行mysql,就可以通过宿主机网络的3308
端口访问mysql了。
更多配置:
-p IP:host_port:container_port # 绑定宿主机网络的ip和port
-p -p IP::container_port # 只宿主机网络ip,任何端口都可以访问
-p host_port:container_port # 只绑定宿主机网络的端口。此时,通过宿主的localhost和与外部网络连接的IP地址,均可以访问到容器
配置其他
docker的网络还可以有更多地配置。比如,可以通过--link
简单地和其他容器相连接,也可以通过自定义网络,配置DNS Server
来进行容器之间的互相通信,在这,通过手动配置iptables控制容器的访问也是可以的。这里,可以参考下面这篇文章:
高级网络功能(Docker支持的网络定制配置:http://www.cnblogs.com/wade-luffy/p/6594843.html
mysql主从服务配置的应用
现在很多数据库的访问往往会用到主从配置,这样可以减缓数据库并行的压力,提升数据库的服务能力。主数据服务器用来执行对数据库的修改工作,从服务器执行对数据的读取工作。网上关于利用docker配置mysql的文章也很多,例如:
从零开始,通过docker实现mysql主从复制,图文并茂,保证可以实现!:https://blog.csdn.net/pingdouble/article/details/78961673
docker mysql 主从配置:http://lib.csdn.net/article/docker/1041
其中的配置内容如下:
1. 修改mysql配置,重新构建镜像
创建如下目录结构:
mysql
|__master
| |__my.cnf
| |__Dockerfile
|__slave
|__my.cnf
|__Dockerfile
my.cnf直接从mysql镜像/etc/mysql
目录下复制过来修改即可,具体方法是:进入镜像,通过cat
命令输出文件内容,复制文件内容。Dockerfile文件则需要自己编写:
其中,master的my.cnf和Dockerfile如下:
my.cnf
!includedir /etc/mysql/conf.d/
[mysqld]
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
datadir=/var/lib/mysql
#log-error=/var/log/mysql/error.log
# By default we only accept connections from localhost
# 可注释,这样远程机可以访问
#bind-address = 127.0.0.1
#---------------------需要修改的部分---------------------------------------#
# 开启log-bin日志
log-bin=/var/log/mysql/mysql-bin.index
# 服务器唯一id,默认为1,一般取IP最后一段
server-id=1
#---------------------修改部分结束---------------------------------------#
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
Dockerfile
FROM mysql:latest
EXPOSE 3306
ADD my.cnf /etc/mysql/
CMD ["mysqld"]
其中,master的my.cnf和Dockerfile如下:
my.cnf
!includedir /etc/mysql/conf.d/
[mysqld]
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
datadir=/var/lib/mysql
#log-error=/var/log/mysql/error.log
# By default we only accept connections from localhost
# 可注释,这样远程机可以访问
#bind-address = 127.0.0.1
#---------------------需要修改的部分---------------------------------------#
# 开启log-bin日志
log-bin=/var/log/mysql/mysql-bin.index
# 服务器唯一id,默认为1,一般取IP最后一段
server-id=2
#---------------------修改部分结束---------------------------------------#
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
Dockerfile
FROM mysql:latest
EXPOSE 3306
ADD my.cnf /etc/mysql/
CMD ["mysqld"]
构建新的mysql镜像:
$ docker run build -t master/mysql:latest . # master目录下运行
$ docker run build -t slave/mysql:latest . # slave目录下运行
2. 启动主服务器和从服务器
$ docker run -it -p 3307:3306 --rm --name dbmaster -e MYSQL_ROOT_PASSWORD=master -d master/mysql
$ docker run -it -p 3308:3306 --rm --name dbslave -e MYSQL_ROOT_PASSWORD=slave -d master/mysql
3. 主服务器配置
$ docker run -it --rm --net host mysql:latest "sh" # 假定你本地安装了mysql:latest镜像
# mysql -h127.0.0.1 -P3307 -uroot -pmaster
mysql> GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by 'master';
mysql> show master status;
记录下file
和Position的值。
4. 从服务器配置
$ docker run -it --rm --net host mysql:latest "sh"
# mysql -h127.0.0.1 -P3308 -uroot -pslave
mysql> change master to
-> master_host='172.18.52.10', # 宿主机IP地址(port 3307),主服务器IP地址(port 3306)
-> master_user='backup',
-> master_password='master',
-> master_log_file='mysql-bin.000003', # 即为上一步获取的file的值
-> master_log_pos=431, # 即为上一步获取的Position的值
-> master_port=3307; # 根据前面的master_host设置
mysql> start slave;
mysql> show master status;
mysql> show slave status\G;
如果show slave status\G
如下两个值显示与下面的值相符,则成功:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
如果出现了问题
,可以通过以下方式恢复:
# 在master中
mysql> show master status;
# 在slave中,像设置时的操作一样,需要先stop和reset slave
mysql > stop slave;
mysql > reset slave;
mysql > change master to
>.......
>master_port=3308;
mysql > start slave;
mysql> show master status;
mysql> show slave status\G;
检查方法同上。
####遇到的一些问题
1. 为什么要设置server_id
对于mysql主从服务,设置server_id用于标示mysql server。对于从服务器,同步的数据中是包含server_id,用于标识该语句最初是从哪个server(对于一从多主的情况)写入的;对于主服务器来说,每个从服务器的同步过程,都相当于它运行的一个线程,server_id用于标识向哪个从服务器同步,同时,当某个slave运行了stop slave; start slave
时,它会根据标识恢复线程。
2. master_host的设置
很多教程博客并没有很清楚地解释这里的设置。其实,只要能够使得从服务器访问到主服务器的host都可以。对于docker来说,除非你为主服务器的容器配置了静态IP地址,否则不要设置为容器的IP地址。容器的每一次重启,都会重新分配IP,一旦你这样设置了,每一次启动mysql服务,都需要reset slave
,这样无疑是自找麻烦。
需要注意的是,最新的docker中允许用户自定义网络,也就说,可以极为方便地给docker 分配静态ip。所以,通过静态ip配置主从服务器也并非很麻烦。
另外,虽然localhost可以访问到宿主机的对应端口,但是,它也是docker中的一个网络:host
。一旦你自定义了网络,就会产生网络隔离。所以,不要试图通过127.0.0.1
去访问主服务器,除非两个服务器都分布在host
网络中。
综上所述,可以使用以下几种方式设置master_host和master_prot:
1) 宿主机IP方式
master_host='172.18.90.55' #请替换为您的宿主机IP
master_host=3307 # 请替换为您的主mysql服务器的映射端口,我这里是3307
2) 同一个网络中,容器名字作为host
master_host='dbmaster' #请替换为您的主mysql服务器名称
master_host=3306 # mysql暴露端口固定,3306
2) 静态分配容器IP,直接以容器IP作为host
#------------------------------------------------------------------#
# docker-compose.yml
version: "3"
services:
dbmaster:
image: dbmaster:latest
container_name: dbmaster
ports:
- "3308:3306"
volumes:
- $HOME/Work/data/dbmaster:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: master
logging:
driver: "json-file"
options:
max-size: "1000k"
max-file: "20"
networks:
app:
ipv4_address: 172.16.238.10
dbslave:
image: registry.cn-shenzhen.aliyuncs.com/selfmysql/slave:latest
container_name: dbslave
ports:
- "3309:3306"
depends_on:
- dbmaster
volumes:
- $HOME/Work/data/dbslave:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: slave
logging:
driver: "json-file"
options:
max-size: "1000k"
max-file: "20"
networks:
app:
ipv4_address: 172.16.238.11
networks:
app:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
-
subnet: 172.16.238.0/24
-
subnet: 2001:3984:3989::/64
#-------------------------------------------------------------------------#
# 配置
master_host='172.16.238.10
master_port=3306
不过,最为建议通过第二种方式实现。