集群架构学习整理 - Nginx四层负载均衡配置(九)

九、Nginx四层负载均衡配置

场景1:实现MySQL数据库负载均衡实践

1)环境
lb4-01 192.168.238.15
lb4-02 192.168.238.16
2)安装nginx+keepalived
3)生产场景1:实现MySQL数据库负载均衡
四层代理:192.168.238.15   172.16.1.15
DB节点:172.16.1.51  172.16.1.52
步骤:
1.克隆192.168.238.15
2.检查负载的节点正常172.16.1.51  172.16.1.52
3.配置lb4-01 192.168.238.15
4.测试

[root@lb4-01 ~]# vim /etc/nginx/nginx.conf +12
注意要在http标签外面加上如下几行
stream {
    include /etc/nginx/stream_conf.d/*.conf;
}

[root@lb4-01 nginx]# mkdir /etc/nginx/stream_conf.d/

[root@lb4-01 nginx]# cd /etc/nginx/stream_conf.d/
[root@lb4-01 stream_conf.d]# cat 01_lb4-mysql.conf 
upstream mysql {
        server 172.16.1.51:3306;
        server 172.16.1.52:3306;
}

server {
        listen 3306;
        proxy_pass mysql;
}
        
nginx -t
systemctl restart nginx

注意:此场景用于代理各类tcp应用,比如,k8s集群,数据库集群,中间件应用服务器集群。
注意:
1.nginx.conf里不允许多个stream标签。
2.stream标签配置为主配置文件nginx.conf main区段。
3.可以在主配置的stream标签里嵌入include /etc/nginx/stream_conf.d/*.conf;
4.nginx.conf 里的 include /etc/nginx/conf.d/*.conf; 这个要注释掉,不然跟stream 80冲突,要不然stream里的80通过192.168.238.15:80监听

#安装Navicat for MySQL或使用Phpmyadmin进行测试

场景2:实现nginx4层+Nginx多七层代理+多Web节点

大并发:      www:192.168.238.15----->192.168.238.5/192.168.238.6----->172.16.1.7/172.16.1.8
不需要高并发:blog:192.168.238.5/192.168.238.6----->172.16.1.7/172.16.1.8

四层代理:192.168.238.15   172.16.1.15
四层代理:192.168.238.16   172.16.1.16
L7层代理:172.16.1.5  172.16.1.5
L7层代理:172.16.1.6  172.16.1.6
Web节点:172.16.1.7  172.16.1.8

==1)四层负载均衡(lb4-01) 192.168.238.15:
完整配置如下:
[root@lb4-01 stream_conf.d]# cat /etc/nginx/stream_conf.d/06_web.conf 
upstream proxy_7 {
	server 192.168.238.5:80;
	server 192.168.238.6:80;
}
server {
	listen 80;
	proxy_pass proxy_7; #注意,不带HTTP。
	#proxy_protocol on; #开启proxy_protocol协议
}
注意别忘了:
1.stream里的监听80端口不能和7层的监听80冲突。
  因此,注释结尾 #include /etc/nginx/conf.d/*.conf;
2.指定VIP (keepalived配置) 192.168.238.17:80;
nginx -t
systemctl restart nginx
七层负载均衡(lb01,lb02)
#lb01
[root@lb01 conf.d]# cat /etc/nginx/conf.d/05_www.conf
upstream www {
    server 172.16.1.7       weight=1;	#默认80端口
    server 172.16.1.8       weight=1;
}
server {
        listen 80;
        server_name www.yunwei.com;
        location / {
                proxy_pass http://www;
                proxy_set_header Host $http_host;
        }
}

nginx -t
systemctl restart nginx

#lb02
[root@lb02 conf.d]# cat /etc/nginx/conf.d/05_www.conf
upstream www {
    server 172.16.1.7   weight=1;
    server 172.16.1.8   weight=1;
}
server {
        listen 80;
        server_name www.yunwei.com;
        location / {
                proxy_pass http://www;
                proxy_set_header Host $http_host;
        }
}

nginx -t
systemctl restart nginx
部署web01,web02相同
[root@web01 conf.d]# cat /etc/nginx/conf.d/05_www.conf
server {
	listen 80;
	server_name www.yunwei.com;
	root /data/www;
	location / {
		index index.html;
	}
}

nginx -t
systemctl restart nginx

#在7层lb01上测试
[root@lb01 conf.d]# curl -H "host:www.yunwei.com" 172.16.1.7
web01
[root@lb01 conf.d]# curl -H "host:www.yunwei.com" 172.16.1.8
web02
必要测试步骤;测试早前配置的7层代理情况
#在4层lb4-01测试
[root@lb4-01 nginx]# curl -H "host:www.yunwei.com" 192.168.238.5
web01
[root@lb4-01 nginx]# curl -H "host:www.yunwei.com" 192.168.238.5
web02

[root@lb4-01 nginx]# curl -H "host:www.yunwei.com" 192.168.238.6
web01
[root@lb4-01 nginx]# curl -H "host:www.yunwei.com" 192.168.238.6
web02

#测试L4(15)---L7(5,6)--->Web(7,8)
[root@web02 conf.d]# curl -H "host:www.yunwei.com" 192.168.238.15
web01
[root@web02 conf.d]# curl -H "host:www.yunwei.com" 192.168.238.15
web01
[root@web02 conf.d]# curl -H "host:www.yunwei.com" 192.168.238.15
web02
[root@web02 conf.d]# curl -H "host:www.yunwei.com" 192.168.238.15
web02

场景3:实现nginx4层+Nginx多七层代理+多Web节点【获取真实用户IP地址】

四层负载均衡
http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_protocol
开启proxy_protocol协议
proxy_protocol on;

语法
Syntax:	proxy_protocol on | off;
Default:	
proxy_protocol off;
Context:	stream, server
This directive appeared in version 1.9.2.

Enables the PROXY protocol for connections to a proxied server.
http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
https://www.nixops.me/articles/PROXY_protocol_pass_client_ip.html
使用PROXY protocol获取客户IP
获取客户IP是常见的需求,对于大流量的项目都会使用反向代理、负载均衡等,甚至多重代理,导致架构和网络都比较复杂,在这种情况下获取IP就不那么容易了。七层代理可以通过添加头信息来实现,如http协议的X-Forword-For,还比较方便;四层代理基本无法简单的获取到客户端IP地址,像LVS的FULLNAT模式,前端LVS把真实IP写在TCP option里面,后端服务器用内核toa模块获取客户IP;haproxy配合TPROXY也是类似的方式实现,两者都需编译内核非常麻烦,这种情况下就可以考虑使用代理协议

一、代理协议简介
代理协议即 PROXY protocol,是haproxy的作者Willy Tarreau于2010年开发和设计的一个Internet协议,通过为tcp添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等),在网络情况复杂又需要获取客户IP时非常有用。如:

多层NAT网络
TCP代理(四层)或多层tcp代理
https反向代理http(某些情况下由于Keep-alive导致不是每次请求都传递x-forword-for)

代理协议分为v1和v2两个版本,v1人类易读,v2是二进制格式,方便程序处理。Proxy protocol是比较新的协议,但目前已经有很多软件支持,如haproxy、nginx、apache、squid、mysql等等,要使用proxy protocol需要两个角色sender和receiver,sender在与receiver之间建立连接后,会先发送一个带有客户信息的tcp header,因为更改了tcp协议,需receiver也支持proxy protocol,否则不能识别tcp包头,导致无法成功建立连接。
#配置开启proxy_protocol,lb4-01(192.168.238.15)
[root@lb4-01 stream_conf.d]# cat /etc/nginx/stream_conf.d/06_web.conf
upstream proxy_7 {
	server 172.16.1.5:80;
	server 172.16.1.6:80;
}
server {
	listen 80;
	proxy_pass proxy_7; #注意,不带HTTP。
	proxy_protocol on;  #开启proxy_protocol协议==================
}	
nginx -t
systemctl reload nginx

	
#七层负载均衡(lb01,lb02) 192.168.238.5/6
[root@web01 conf.d]# cat /etc/nginx/conf.d/05_www.conf
upstream www {
	server 172.16.1.7:80;
	server 172.16.1.8:80;
}
server {
	listen 80 proxy_protocol;       #添加proxy_protocol
	server_name www.yunwei.com;
	set_real_ip_from 172.16.1.0/24;  #添加七层负载前经过的代理IP地址
	real_ip_header proxy_protocol;   #将proxy_protocol获取的IP赋值给$remote_addr	
	location / {
		proxy_pass http://www;
		proxy_set_header Host $http_host;
		proxy_set_header X-Forwarded-For $proxy_protocol_addr;
		#将proxy_protocol真实客户端的IP地址赋值给X-Forwarded-For变量携带至后端
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		#不加下面两条,可能会报错nginx: [warn] could not build optimal proxy_headers_hash, you should increase either proxy_headers_hash_max_size: 512 or proxy_headers_hash_bucket_size: 64; ignoring proxy_headers_hash_bucket_size
		proxy_headers_hash_max_size 51200;
		proxy_headers_hash_bucket_size 6400;
	}
}
		
#在web01上查看访问结果
[root@web01 nginx]$tail -f /var/log/nginx/access.log
172.16.1.5 - - [26/Dec/2022:16:38:25 +0800] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" "192.168.238.1, 192.168.238.15"
172.16.1.5 - - [26/Dec/2022:16:38:26 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" "192.168.238.1, 192.168.238.15"
172.16.1.5 - - [26/Dec/2022:16:38:27 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" "192.168.238.1, 192.168.238.15"

最后面显示用户真实和代理ip"192.168.238.1, 192.168.238.15"

Nginx多级代理,获取客户端真实请求ip以及每级代理ip

https://blog.csdn.net/simonchi/article/details/53944308

haproxy + nginx + proxy protocol 获得客户真实IP方法

https://www.cnblogs.com/hh2737/p/8951872.html

场景4:测试众多nginx http变量值

[root@web01 conf.d]# cat 05_www.conf 
server {
	listen 80;
	server_name www.yunwei.com;
	root /data/www;
	location / {
		return 200 "web01,老男孩Linux77最优班级\n
		remote_addr: $remote_addr\n
		proxy_add_x_forwarded_for:$proxy_add_x_forwarded_for\n
		proxy_protocol_addr: $proxy_protocol_addr\n
		http_x_forwarded_for:$http_x_forwarded_for\n";
	}
}

从DB01访问:192.168.238.51---192.168.238.15----172.16.1.5----172.16.1.7

[root@db01 ~]# curl -H "host:www.yunwei.com" 192.168.238.15
web01,老男孩Linux77最优班级
remote_addr: 172.16.1.5
proxy_add_x_forwarded_for:192.168.238.51, 172.16.1.5
http_x_forwarded_for:192.168.238.51

更改web01主配置日志测试:
log_format  access '-$proxy_protocol_addr-,--$remote_addr--,---$http_x_forwarded_for---,----$proxy_add_x_forwarded_for----,$remote_user,$time_local,$host,$request,$status,$http_referer,$HTTP_X_UP_CALLING_LINE_ID,$request_time,$http_user_agent  $upstream_addr  $upstream_response_time  $upstream_cache_status';
access_log  /var/log/nginx/access.log  access;

---,--172.16.1.5--,---192.168.238.51, 192.168.238.15---,----192.168.238.51, 192.168.238.15, 172.16.1.5----
-$proxy_protocol_addr-,--$remote_addr--,---$http_x_forwarded_for---,----$proxy_add_x_forwarded_for----

日志结果:

[root@web01 conf.d]# tail /var/log/nginx/access.log
---,--172.16.1.5--,---192.168.238.1---,----192.168.238.1, 172.16.1.5----,-,03/Mar/2023:16:20:49 +0800,www.yunwei.com,GET / HTTP/1.0,304,-,-,0.000,Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54  -  -  -
---,--172.16.1.5--,---192.168.238.1---,----192.168.238.1, 172.16.1.5----,-,03/Mar/2023:16:20:49 +0800,www.yunwei.com,GET / HTTP/1.0,200,-,-,0.000,Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54  -  -  -


nginx多层代理获取客户端的真实ip总结:

1、要有http_realip_module模块支持
2、在nginx.conf文件中
proxy_pass http://www; #添加下面三行
proxy_set_header   Host             $host;
proxy_set_header   X-Real-IP        $remote_addr;
proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

3、在每一层nginx日志中的打印的"$http_x_forwarded_for"就是真实客户端的ip地址。

4、后台服务器获取真实的客户端ip地址:
headers中的X-Forwarded-For选项中逗号前第一个ip就是真实客户端ip
日志中获取真实ip:  $http_x_forwarded_for 就是获取真实ip的变量
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
提示:
1、set_real_ip_from 是指接受从哪个信任前代理处获得真实用户ip
2、real_ip_header 是指从接收到报文的哪个http首部去获取前代理传送的用户ip
3、real_ip_recursive 是否递归地排除直至得到用户ip(默认为off)
首先,real_ip_header 指定一个http首部名称,默认是X-Real-Ip,假设用默认值的话,nginx在接收到报文后,会查看http首部X-Real-Ip。

(1)如果有1个IP,它会去核对,发送方的ip是否在set_real_ip_from指定的信任ip列表中。如果是被信任的,它会去认为这个X-Real-Ip中的IP值是前代理告诉自己的,用户的真实IP值,于是,它会将该值赋值给自身的$remote_addr变量;如果不被信任,那么将不作处理,那么$remote_addr还是发送方的ip地址。

(2)如果X-Real-Ip有多个IP值,比如前一方代理是这么设置的:proxy_set_header X-Real-Ip $proxy_add_x_forwarded_for;
得到的是一串IP,那么此时real_ip_recursive的值就至关重要了。nginx将会从ip列表的右到左,去比较set_real_ip_from 的信任列表中的ip。
如果real_ip_recursive为off,那么,当最右边一个IP,发现是信任IP,即认为下一个IP(右边第二个)就是用户的真正IP;
如果real_ip_recursive为on,那么将从右到左依次比较,知道找到一个不是信任IP为止。
然后同样把IP值复制给$remote_addr。
http_proxy_module相关参数
相关重要参数	参数说明
proxy_pass http://server_pools; 	通过proxy_pass功能把用户的请求转向到反向代理定义的upstream服务器池
proxy_set_header Host $host;	在代理向后端服务器发送的http请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时,可以识别代理的是哪个虚拟主机。这是节点服务器多虚拟主机时的关键配置
proxy_set_header X-Forwarded-For $remote_addr;	在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息,用于后端服务器程序、日志等接收记录真实用户的IP,而不是代理服务器IP。
这是反向代理时,节点服务器获取用户真实IP的必要功能配置
[root@web02 conf.d]# tail -f /var/log/nginx/access.log
172.16.1.5 - - [02/Aug/2021:16:45:59 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-"
172.16.1.5 - - [02/Aug/2021:16:46:00 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-"

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
access_log  /var/log/nginx/access.log  main;
结果:
$remote_addr 172.16.1.5
$http_x_forwarded_for -

3. 经过7层反向代理后的节点服务器记录用户IP企业案例
   [root@lb01 conf.d]# cat 03_www.yunwei.com.conf
   upstream www {
     server 172.16.1.7       weight=1 ; #默认80端口 
     server 172.16.1.8       weight=1; #默认80端口
   }
   server {
   listen 80;
   server_name www.yunwei.com;
   location / {
         proxy_pass http://www;
         proxy_set_header Host $http_host;
         proxy_set_header X-Forwarded-For $remote_addr;

   <==在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息,用于后端服务器程序、日志等接收记录真实用户的IP,而不是代理服务器的IP。
   }
   }
   [root@lb01 conf.d]# nginx -t 
   [root@lb01 conf.d]# systemctl restart nginx
测试:使用DB01或者浏览器测试
[root@db01 ~]# curl -H"host:www.yunwei.com" 172.16.1.5
web01
[root@db01 ~]# curl -H"host:www.yunwei.com" 172.16.1.5
web02
[root@web02 conf.d]# tail -f /var/log/nginx/access.log
172.16.1.5 - - [02/Aug/2021:16:45:59 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-"
172.16.1.5 - - [02/Aug/2021:16:46:00 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "-"
172.16.1.5 - - [02/Aug/2021:16:51:21 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "172.16.1.5"
172.16.1.5 - - [02/Aug/2021:16:51:52 +0800] "GET / HTTP/1.0" 200 6 "-" "curl/7.29.0" "172.16.1.51"
172.16.1.5 - - [02/Aug/2021:16:52:23 +0800] "GET /favicon.ico HTTP/1.0" 404 555 "http://www.yunwei.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "192.168.238.1"
172.16.1.5 - - [02/Aug/2021:16:52:25 +0800] "GET /favicon.ico HTTP/1.0" 404 555 "http://www.yunwei.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "192.168.238.1"
172.16.1.5 - - [02/Aug/2021:16:52:28 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "192.168.238.1"
172.16.1.5 - - [02/Aug/2021:16:52:28 +0800] "GET / HTTP/1.0" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" "192.168.238.1"
看结尾$http_x_forwarded_for列如果出现访问的客户的真实IP就对了
浏览器访问的结果,真实IP是192.168.238.1,如果通过db01访问真实IP就是172.16.1.51
结果:
$remote_addr依然是172.16.1.5,上级代理IP
$http_x_forwarded_for 192.168.238.1



nginx反向代理的若干参数说明:
fastcgi_pass
     http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html
proxy_pass
     http://nginx.org/en/docs/http/ngx_http_proxy_module.html
uwsgi_pass
http://nginx.org/en/docs/http/ngx_http_uwsgi_module.html

扩展:搭建nginx cache服务 作为静态web服务的前端缓存。
https://blog.csdn.net/dengjiexian123/article/details/53386586

标签:

上一篇集群架构学习整理 - Keepalived高可用配置(八)
下一篇集群架构学习整理 - 四层负载均衡(十)

相关文章