暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

利用Docker技术实现多域名负载均衡

横戈安全团队 2021-07-26
936

本文目录:

0x01 概述
0x02 实验环境
0x03 实验开始
    3.1 创建docker网络模拟内网环境
    3.2 配置单域名的负载均衡
        部署默认的Nginx应用
        配置负载均衡服务器
        单域名负载均衡效果
    3.3 配置多域名的负载均衡
        部署第二个web应用
            第一台服务器web1
            第二台服务器web2
            第三台服务器web3
        配置负载均衡服务器
        多域名负载均衡效果
    3.4 负载均衡策略
0x04 实验总结



0x01 概述

  负载均衡,不管是红队蓝队、甲方乙方、踩点或者后渗透,多多少少都会遇到这个概念或者场景。而在大企业中,使用负载均衡可以说已经是常态。
  本文主要利用Docker来模拟简单的多域名(多web应用)负载均衡。

0x02 实验环境

需求:为企业的两个web系统做负载均衡,一个是默认Nginx,一个是www.foxyu.cn

  • Nginx:使用ip访问:107.155.15.110
    web目录:/usr/share/nginx/html

  • www.foxyu.cn:使用域名访问
    web目录:/var/www/html

容器:
  第一台服务器web1:172.20.0.2,部署在内网中,不对外网开放。
  第一台服务器web2:172.20.0.3,部署在内网中,不对外网开放。
  第一台服务器web3:172.20.0.4,部署在内网中,不对外网开放。
  负载均衡服务器nginx:172.20.0.5,外网ip:107.155.15.110,部署在边界,只对外网开放80(Nginx应用)和81(foxyu域名应用)两个端口。

网络结构如下:


0x03 实验开始

物理机需要Docker环境。
我们直接使用Nginx官方镜像:docker pull nginx

3.1 创建docker网络模拟内网环境

1.首先创建一个新的docker网络:

docker network create -d bridge foxyu-net

参数说明:
  -d:参数指定 Docker 网络类型,有 bridge、overlay。

2.创建容器并连接到创建的docker(foxyu-net)网络中:

docker run -dit --name web1 --network foxyu-net nginx
docker run -dit --name web2 --network foxyu-net nginx
docker run -dit --name web3 --network foxyu-net nginx
docker run -dit --name nginx --network foxyu-net -p 80:80 -p 81:81 nginx

其中只需要在负载均衡服务器:nginx(部署在边界)上面映射两个端口,相当于对外只开放两个端口,每个端口对应一个web应用。
其他三个web服务器不映射端口,模拟真实环境中的内网服务器。即外网无法直接访问。


可以通过容器名进行互相通信。也可以使用docker inspect 容器名
查看容器ip:

各容器IP如下:

  • web1:172.20.0.2

  • web2:172.20.0.3

  • web3:172.20.0.4

  • nginx:172.20.0.5

3.2 配置单域名的负载均衡

简单理解负载均衡:
  假设有5台服务器,如果有5个访问请求,没有负载均衡时,可能5个请求都访问机器A,这样可能引致访问速度慢,A机器崩溃等问题,而有了负载均衡,就会将5个任务按照策略进行分发,可能5台机器每台负责处理一个任务就OK了。
  Nginx的负载均衡,就是在Nginx代理服务器上配置upstream模块,通过调度算法实现各个服务器的合理的分压。

部署默认的Nginx应用

  负载均衡服务器由于只是做代理转发,因此不用挂载,其他web1、web2、web3都是web服务器,实际环境中,这三台应该部署同一个web应用,才能做负载均衡。
  先配置默认Nginx应用的负载均衡,这里为了等下可以观察到实际效果,我们分别在三个web服务器的Nginx默认页面上写入不同的内容:

docker exec -it web1 bash -c "echo 'Web server1,default nginx page.' > /usr/share/nginx/html/index.html"
docker exec -it web2 bash -c "echo 'Web server2,default nginx page.' > /usr/share/nginx/html/index.html"
docker exec -it web3 bash -c "echo 'Web server3,default nginx page.' > /usr/share/nginx/html/index.html"

查看是否写入成功:

配置负载均衡服务器

现在默认的Nginx应用就已经在三台web服务器上面部署完成,都是采用默认的80端口。接下来配置负载均衡。
进入容器负载均衡服务器:nginx

docker exec -it nginx /bin/bash

由于容器里面没有vim命令,我们需要先安装vim

apt-get update
apt-get install vim

首先查看我们的内网环境和三台web服务器是否正常运行:

使用内网IP可以请求到web页面,环境部署没问题。

接下来编辑/etc/nginx/nginx.conf
文件,在http{}中新增以下内容:

http {
upstream default_nginx {
server 172.20.0.2:80;
server 172.20.0.3:80;
server 172.20.0.4:80;
}
.....
}


编辑/etc/nginx/conf.d/default.conf
文件,在server{}中新增以下内容:

server {}
......
location / {
......
proxy_pass http://default_nginx;
proxy_connect_timeout 2s;
}
......
}

因为我们这里使用默认的Nginx应用,因此这里的root,也就是web应用目录不需要改动。

执行以下命令检查配置文件,然后重新加载nginx配置文件:

nginx -t
nginx -s reload

重启成功。

单域名负载均衡效果

由于没有多个域名,这里直接使用ip访问模拟一个域名了,使用下面命令查看负载效果:

sh -c "while true;do curl http://107.155.15.110;done;"

实验搭建成功,将我们的请求平均分配给后端的三台web服务器。

3.3 配置多域名的负载均衡

往往一个企业不止一个域名,可能会有多个域名多个web应用,那么在上面配置完单域名的负载均衡后,我们怎么添加多个域名的负载均衡呢?

部署第二个web应用

首先还是需要在三台web服务器上部署第二个web应用,为了查看效果,还是在页面内容中写入不同的内容:

第一台服务器web1

进入容器,安装vim:

docker exec -it web1 /bin/bash
apt-get update
apt-get install vim

后面不再重复说明。

部署第二个web应用,这里参考Apache,部署在/var/www/html
目录下:

mkdir -p /var/www/html
echo "Web server1,domain www.foxyu.cn!"> /var/www/html/index.html

部署完成之后,我们还需要配置一下Nginx。

进入/etc/nginx/conf.d/
目录下,复制一份默认的配置文件,重命名为域名.conf的格式。
如需部署第三个、第四个web应用,只需要在该目录下重新创建一个域名.conf的文件,修改其配置即可。

cp default.conf www.foxyu.cn.conf


编辑www.foxyu.cn.conf
文件,新增以下内容:

server {
listen 81 default;
listen [::]:81 default;
server_name _;
return 403;
}
server {
listen 81;
listen [::]:81;
server_name www.foxyu.cn;


#access_log /var/log/nginx/host.access.log main;
location / {
root /var/www/html;
index index.html index.htm
}
......
}

新增了一个server{},监听81端口,将除了域名访问的所有请求都返回403。
然后修改原来的server{},修改监听端口为81(80为默认的Nginx应用),设置虚拟主机为目标域名。也就是第二个web应用只允许通过域名进行访问
修改location / {},将root也就是网站目录修改为上面创建的/var/www/html
目录。

修改完成后检查配置是否有问题:

nginx -t
nginx -s reload

配置完成。

第二台服务器web2

同样部署第二个web应用:

docker exec  -it web2 /bin/bash
apt-get update
apt-get install vim
mkdir -p /var/www/html
echo "Web server2,domain www.foxyu.cn!"> /var/www/html/index.html

/etc/nginx/conf.d/
目录下新建www.foxyu.cn.conf
文件,同样新增以下内容:

server {
listen 81 default;
listen [::]:81 default;
server_name _;
return 403;
}
server {
listen 81;
listen [::]:81;
server_name www.foxyu.cn;


#access_log /var/log/nginx/host.access.log main;
location / {
root /var/www/html;
index index.html index.htm
}
......
}

检查配置是否有问题并重启Nginx服务:

第三台服务器web3

部署第二个web应用:

docker exec  -it web3 /bin/bash
apt-get update
apt-get install vim
mkdir -p /var/www/html
echo "Web server3,domain www.foxyu.cn!"> /var/www/html/index.html

/etc/nginx/conf.d/
目录下新建www.foxyu.cn.conf
文件,同样新增以下内容:

server {
listen 81 default;
listen [::]:81 default;
server_name _;
return 403;
}
server {
listen 81;
listen [::]:81;
server_name www.foxyu.cn;


#access_log /var/log/nginx/host.access.log main;
location / {
root /var/www/html;
index index.html index.htm
}
......
}

检查配置是否有问题并重启Nginx服务:

配置负载均衡服务器

现在第二个web应用也已经在三台web服务器上面部署完成,部署在81端口。接下来配置负载均衡。
进入容器负载均衡服务器:nginx

docker exec -it nginx /bin/bash

编辑/etc/nginx/nginx.conf
文件,在http{}中新增以下内容:

http {
.....
upstream foxyu_web {
server 172.20.0.2:81;
server 172.20.0.3:81;
server 172.20.0.4:81;
}
.....
}

进入/etc/nginx/conf.d/
目录下,同样新增一个www.foxyu.cn.conf
文件:

编辑www.foxyu.cn.conf
文件,在server{}中修改以下内容:

server {
listen 81 default;
listen [::]:81 default;
server_name _;
return 403;
}
server {
listen 81;
listen [::]:81;
server_name www.foxyu.cn;


#access_log /var/log/nginx/host.access.log main;


......
location / {
proxy_pass http://foxyu_web;
proxy_set_header Host $host;
proxy_connect_timeout 2s;
}
......
}

注意:这里由于我们负载均衡upstream{}中配置的是ip+端口形式,而三台web服务器又设置成只允许域名访问。因此这里在location / {}中需要添加一个proxy_set_header Host $host;
字段,再转发到后端三台web服务器的时候才会是以域名访问的形式。
此时后端服务器看到的来源IP都是负载均衡服务器的IP,如有需要得到真实的来源IP,可以再加上:

proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

配置完成后检查配置文件,然后重新加载nginx配置文件:

重启成功。

多域名负载均衡效果

1、测试 IP+端口 进行访问:

sh -c "while true;do curl http://107.155.15.110:81;done;"

可以看到直接以IP+端口的形式访问第二个web应用,返回都是403,也就是我们上面在www.foxyu.cn.conf
文件中配置的第一个server {}的作用。

2、测试 域名+端口 进行访问:

sh -c "while true;do curl http://www.foxyu.cn:81;done;"

成功得到第二个web应用的内容。

这里我们因为没有配置负载均衡策略,因此使用nginx默认的轮询策略进行负载,把每一个请求逐一分配到不同的server,如果分配到的server不可用,则分配到下一个,直到可用。
这个时候我们模拟一个服务器down掉了,停掉web1:

可以看到此时获取到的web页面就只有web2和web3的web页面了:

大大提高了企业网络的灵活性和可用性。

3.4 负载均衡策略

上面我们配置的负载均衡采用默认策略,但是,Nginx其实提供了多种负载均衡策略。

  • 轮询
    这是默认的策略,把每个请求逐一分配到不同的server,如果分配到的server不可用,则分配到下一个,直到可用:

upstream foxyu_web {
server 172.20.0.2:81;
server 172.20.0.3:81;
server 172.20.0.4:81;
}
  • 最少连接
    把请求分配到连接数最少的server

upstream foxyu_web {
least_conn;
server 172.20.0.2:81;
server 172.20.0.3:81;
server 172.20.0.4:81;
}
  • 权重
    weight默认值为1,值越大则代表被访问的几率越大,如下配置,172.20.0.3
    的访问数量是172.20.0.2
    的2倍,172.20.0.4
    的访问数量是172.20.0.2
    的3倍。

upstream foxyu_web {
server 172.20.0.2:81 weight=1;
server 172.20.0.3:81 weight=2;
server 172.20.0.4:81 weight=3;
}
  • ip_hash
    根据访问客户端IP的hash值分配,这样同一客户端的请求都会被分配到同一个server上,如果牵扯到session的问题,用这个是最好的选择

upstream foxyu_web {
ip_hash;
server 172.20.0.2:81;
server 172.20.0.3:81;
server 172.20.0.4:81;
}

0x04 实验总结

  本文通过Docker技术,模拟了一个小型企业实现多域名负载均衡的技术,在这之中了解了Nginx强大的功能,明白了Nginx的反向代理和负载均衡实现原理,还有负载均衡的几种策略。后续可能会再出一期针对Nginx的waf功能的实验,敬请期待!


如文章有错误不理解的地方,请在"公众号留言",欢迎各位师傅一起学习交流。

文章转载自横戈安全团队,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论