在上一part《把AspDotNetCoreMvc程序运行在Docker上-part3:使用独立的存储容器》,我们利用MySql容器和Volume实现了真正意义上的数据存储。整个结构非常简单,就是一个web容器和一个数据库容器,是一个简单的应用。如今都流行支持高并发,集群什么的,最起码要有多个web服务器,于是通常要用到负载均衡的技术,比如HAproxy,Nginx等等。那么这一部分,我们接着用Docker技术实现负载均衡,其实说严格还是用的老技术,只不过包装到了Docker容器中而已。
自定义网络配置
docker内置了默认的网络配置,默认的网络配置是自动创建好的,可用于容器之间的网络访问。在上一part中的我们就用到了这个默认的网络配置,里面的MySql容器就是通过默认网络配置访问的。
通过以下命令可以查看docker默认创建的网络配置
docker network ls
NETWORK ID NAME DRIVER SCOPE
13d5e19c447e bridge bridge local
fb4ce1a7bfcf host host local
ee50b1dc443b none null local
在创建了MySql容器之后,系统分配的网络是bridge,我们可以通过以下命令查看bridge被哪个容器使用
"Containers": {
"d4e5cf975ad5e3ff11620c02f9b626fa4d0042faab83fa9d0ea86801d2cce452": {
"Name": "mysql",
"EndpointID": "5fe1c90310938704323ba4cbb7c156a962ca07cd49845d12ea142dff40021212",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
从Containers节点能看到当前在使用该网络配置的容器以及分配的IP地址,通过这个IP就能访问到该容器。
这么看来默认网络配置似乎够用,但是它有他的局限性。首先这个IP是docker分配的,需要手动去查看用的是哪个IP地址。另外一个重要问题就是,如果有多个容器都使用了同一个网络,没法根据功能进行区分和管理,尤其是后续我们要讲到的负载均衡功能,用自定义的网络配置更加灵活。
创建自定义网络配置
通过以下命令创建frontend和backend两个自定义网络,名字可以改成其他。
docker network create frontend
docker network create backend
frontend将用于我们的网站容器,backend将用于MySql容器。
查看已创建的网络
docker network ls
NETWORK ID NAME DRIVER SCOPE
f18bd38d350f backend bridge local
13d5e19c447e bridge bridge local
1318f2d56587 frontend bridge local
fb4ce1a7bfcf host host local
ee50b1dc443b none null local
有了自定义网络之后,就可以将它分配给容器
为了便于演示,首先通过如下命令删除之前创建的容器
docker rm -f $(docker ps -aq)
创建MySql容器,并指定使用backend网络
docker run -p 3306:3306 -d --name mysql -v productdata:/var/lib/mysql --network=backend -e MYSQL_ROOT_PASSWORD=password -e bind-address=0.0.0.0 mysql:8.0.0
相比上一part,这里只是多了一个—network参数
使用自定义网络的还有一个很有用的功能就是,在docker内部可以通过容器的名称作为网络访问地址,比如我们这里创建了MySql容器,容器名是mysql,那么实际上在docker内部,mysql就可以作为host名称,然后docker内部会将mysql解析为其分配的IP地址。这样的话,我们在docker内部就可以直接用容器名称来配置网络参数,比如数据库的主机地址,接下来我们创建站点容器将使用到。
创建MVC网站容器
还是使用之前我们定义的镜像shenba/aspdotnetcoremvc
这里我们创建三个容器
docker create --name app1 -e DBHOST=mysql -e MESSAGE="1st Server" --network backend shenba/aspdotnetcoremvc
docker create --name app2 -e DBHOST=mysql -e MESSAGE="2nd Server" --network backend shenba/aspdotnetcoremvc
docker create --name app3 -e DBHOST=mysql -e MESSAGE="3rd Server" --network backend shenba/aspdotnetcoremvc
这里的创建命令只是MESSAGE不同,这个MESSAGE是个环境变量,会作为网站内容输出,用于识别目前是在哪个容器中。
这里的network的参数指定方式跟创建MySql容器的不同,这里只是指定需要连接这个网络,这三个容器都需要连接backend网络访问mysql容器。
此外,这里创建的时没有指定宿主机的端口映射。
我们需要进一步将这三个容器连接到frontend网络,然后通过frontend网络访问这三个容器。
连接到frontend网络
docker network connect frontend app1
docker network connect frontend app2
docker network connect frontend app3
启动这三个MVC站点容器
docker start app1 app2 app3
使用HAProxy容器
启动完三个MVC网站容器之后,还不能被宿主机访问到,因为没有公开外网访问的IP和端口,所以它们只能被docker内部的网络访问到。这就是我们通常使用负载均衡的场景,应用服务器都部署在内网,然后外部通过反向代理的方式访问到内部的应用服务器。所以接下来我们需要一个反向代理的服务器,在docker里当然就是一个安装了反向代理服务的容器。
我们使用HAPoxy容器来实现负载均衡,首先在docker所在的服务器(或者说是宿主机,这里用的是centos)创建一个haproxy.cfg配置文件
defaults
timeout connect 5000
timeout client 50000
timeout server 50000
frontend localnodes
bind *:80
mode http
default_backend mvc
backend mvc
mode http
balance roundrobin
server mvc1 app1:80
server mvc2 app2:80
server mvc3 app3:80
简单的说就是将负载均衡服务器的80端口公开,并且将这个端口的请求分配到三个不同的MVC站点中。
接下来在cfg文件所在的目录执行如下命令
docker run -d --name loadbalancer --network frontend -v "$(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg" -p 3000:80 haproxy:1.7.0
参数跟创建其他容器一样,提供了名称(loadbalancer),网络(frontend),端口映射(3000:80),基于镜像(haproxy:1.7.0)
比较特别的是-v参数,这里是将宿主机的haproxy.cfg映射到了容器里的haproxy.cfg文件。
好了到此,实现负载均衡的所有配置已经完成,打开浏览器输入http://192.168.115.136:3000,重复刷新多次那么会看到网站的内容标题会发生变化,比如截图所示
目前的结构图如下