场景一: 没有使用反向代理 配置nginx.conf,添加/修改 log 相关配置如下:
http {
......
log_format main 'Parameter remote_addr : $remote_addr\n'
'Parameter http_x_forwarded_for: $http_x_forwarded_for\n'
'Parameter http_x_real_ip : $http_x_real_ip';
access_log /var/log/nginx/access.log main;
......
}
启动nginx服务,并通过浏览器访问,查看访问日志结果如下: 其中http_x_forwarded_for 的值是“空”,因为server端没有reverse proxy,所以该变量就不存在,该变量仅仅在proxy中才有效. 而http_x_real_ip的值同样为"空“, 也和http_x_forwarded_for是一样的原因,但是remote_addr的值就是client端的IP,remote_addr的值不能进行修改,由系统控制,直接访问就可以引用,如果启用的是nginx容器,那么结果也是一样,对于没有配置反向代理的情况,基于host的Nginx和基于container的nginx,对于上述的验证结果是一致的
[root@instance-6p8qz002 log]# tail -n0 -f access.log
Parameter remote_addr : 119.123.134.165
Parameter http_x_forwarded_for: -
Parameter http_x_real_ip : -
.
场景二:只有一个reverse proxy 在此测试场景中,使用docker 启动一个nginx 容器作为 service provider(映射host主机的8080端口到容器的80端口). 而在host主机上运行的nginx配置反向代理功能,同时在host上创建一个虚拟IP:192.168.0.110,这样在配置反向代理的时候就可以使用 192.168.0.110 来代替localhost 具体步骤如下:
[root@instance-6p8qz002 ~]# ifconfig eth0:0 192.168.0.110 netmask 255.255.255.0 up
[root@instance-6p8qz002 ~]# ping -c 2 192.168.0.110
PING 192.168.0.110 (192.168.0.110) 56(84) bytes of data.
64 bytes from 192.168.0.110: icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from 192.168.0.110: icmp_seq=2 ttl=64 time=0.066 ms
--- 192.168.0.110 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.048/0.057/0.066/0.009 ms
[root@instance-6p8qz002 ~]#
......
location / {
proxy_pass http://192.168.0.110:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
......
#启动host上的nginx服务
[root@instance-6p8qz002 ~]# systemctl start nginx.service
[root@instance-6p8qz002 ~]#
http {
......
log_format main 'Parameter remote_addr : $remote_addr\n'
'Parameter http_x_forwarded_for: $http_x_forwarded_for\n'
'Parameter http_x_real_ip : $http_x_real_ip';
access_log /var/log/nginx/access.log main;
......
}
#启动nginx 容器
[root@instance-6p8qz002 my_project]# docker run -d --rm -p 8080:8080 -v /root/my_project/nginx/:/etc/nginx -v /tmp/nginx/log:/var/log/nginx/ --name my_nginx nginx
56a543b71e7c157d9dc736f8c1d3481d31e21db03575d51eadd6ebe980de282d
[root@instance-6p8qz002 my_project]#
[root@instance-6p8qz002 log]# tail -n0 -f access.log
Parameter remote_addr: 192.168.0.110
Parameter http_x_forwarded_for: 119.123.134.165
Parameter http_x_real_ip: 119.123.134.165
根据我们前面的理解,remote_addr的值应该是:client的public IP才对,也就是119.123.134.165, 因为我们这里只有这一个reverse proxy. 那为什么实际是 : 192.168.0.110 呢? 因为在docker map host端口到container的端口的时候,其实是一个http请求的转发,所以host_ip:port ---- container: port 之间的关系,就相当于client--server 的直连关系。 http_x_forwarded_for,http_x_real_ip 的值和前面的理论值是一致的,这里不做过多解释; .
场景三:多个reverse proxy的讨论 这里采用三个reverse proxy来作代表多个proxy的情况,其部署环境如下:
关键的配置过程如下: A. 在本地的centos中,对nginx做如下的配置:
#监听端口采用默认的80端口;
......
#remotee_host 对应的IP写在/etc/hosts中
location / {
proxy_pass http://remote_host:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
......
[root@localhost conf.d]# systemctl restart nginx.service
[root@localhost conf.d]#
B. 在remote_host中,做如下的配置:
server {
listen 8080 default_server;
......
location / {
proxy_pass http://localhost:8088/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...
}
......
[root@instance-6p8qz002 nginx]# systemctl restart nginx.service
[root@instance-6p8qz002 nginx]#
C. 在容器A(172.26.16.8) 中配置 nginx反向代理,转发请求到容器B(172.26.16.4)中. 并启动容器A. 这里要注意以下的几点: 1). 在nginx容器中,upstream不能使用ip地址,必须使用name,为了能够实现name到地址的解析,所以把host主机的/etc/hosts mapping为container A中相应文件, 如下的配置中,主机的/etc/hosts中有:"172.26.16.4 container_b" 之间的映射关系 2). 要使用自定义IP,必须要使用自定义的docker 网络
......
server {
listen 8080;
......
location / {
proxy_pass http://container_b:8080/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
......
}
......
#启动容器A的步骤如下,命令如下:
[root@instance-6p8qz002 nginx_b]# docker network create -d bridge --subnet=172.26.0.0/16 --ip-range=172.26.16.0/24 mynetwork
[root@instance-6p8qz002 nginx_b]# docker run -d --rm --network="mynetwork" --ip 172.26.16.8 -p 8088:8080 -v /root/my_project/nginx_a/:/etc/nginx -v /etc/hosts:/etc/hosts --name nginx_a nginx
D. 通过容器B提供http服务,这里没有反向代理的配置,其监听端口为8080,不做host到容器B的端口映射. 虽然这里没有反向代理的配置,但是需要配置log记录,同时需要把容器中的log目录 mapping 到host主机的特定目录 ;
#配置监听端口为8080. 配置参数忽略
access_log /var/log/nginx/access.log main; #配置log.
......
log_format main 'Parameter remote_addr : $remote_addr\n'
'Parameter http_x_forwarded_for: $http_x_forwarded_for\n'
'Parameter http_x_real_ip : $http_x_real_ip';
......
#启动容器B
[root@instance-6p8qz002 my_project]# docker run -d --rm --network="mynetwork" --ip 172.26.16.4 -v /root/my_project/nginx/:/etc/nginx -v /tmp/nginx/log:/var/log/nginx/ --name nginx_b nginx
在这个过程中用到的端口如下: 1.centos 主机192.168.0.110的80端口,提供用户访问接口; 2.remote_host的8080端口,用于接收centos转发过来的请求; 3.remote_host的8088端口,用于接收remote_host的8080端口转发过来的请求; 4.启动容器A(172.26.16.8)时,要mapping port 8088:8080,也就是指定-p 参数; 5.容器A的8080端口转发到容器B(172.26.16.4)的8080端口, 容器; 验证结果: 首先在remote_host上用命令: tail -n0 -f /tmp/nginx/log/access.log, 然后使用浏览器访问192.168.0.110, tail的结果如下:
[root@instance-6p8qz002 nginx]# tail -n0 -f /tmp/nginx/log/access.log
Parameter remote_addr: 172.26.16.8
Parameter http_x_forwarded_for: 192.168.0.101, 119.123.132.73, 172.26.16.0
Parameter http_x_real_ip: 192.168.0.101
对于结果的分析如下: remote_addr: log 是在172.26.16.4上产生的,其前一级为容器A(172.26.16.8), 所以remote_addr的地址是 172.26.16.8 http_x_real_ip: 就是浏览器设备对应的地址,在本实验中,就是本机的IP地址:192.168.0.101 ,与理论值一致; http_x_forwarded_for: 第一次反向代理是发生在访问192.168.0.110时候,被代理的客户端为192.168.0.101; 第二次反向代理是remote_host上发生的,被代理的请求来自Public的IP:119.123.132.73 第三次反向代理是容器A(172.26.16.8)上配置的,其直接请求docker 中的网桥转发的,但是为什么会是 172.26.16.0 呢?小弟不才,不是很明白这里的原因,希望读者你能够帮忙解答一二 .