跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • Docker compose 搭建的测试环境下,没办法拿到真实的 Client IP 吗?
未分類
2021 年 1 月 16 日

Docker compose 搭建的测试环境下,没办法拿到真实的 Client IP 吗?

Docker compose 搭建的测试环境下,没办法拿到真实的 Client IP 吗?

資深大佬 : kenshin912 0

有一台阿里云的服务器,我用 docker compose 起了一套测试环境,需要获取用户真实 IP,Google 了挺久一直没解决,所以跑 V2EX 来问问大佬们。

Web Server 是 Openresty,后端是 PHP

docker-compose 文件部分如下:

version: '3.8'  services:     openresty:         image: ${OPENRESTY_IMAGE}         container_name: openresty         build:             context: ./service/openresty         ports:             - "80:80"             - "443:443"         volumes:             - ${SOURCE_DIR}:/home/wwwroot/:rw             - ${OPENRESTY_SSL_DIR}:/etc/nginx/ssl:rw             - ${OPENRESTY_CONF_DIR}:/etc/nginx/conf.d/:rw             - ${OPENRESTY_CONF_FILE}:/usr/local/openresty/nginx/conf/nginx.conf:ro             - ${OPENRESTY_LUA_DIR}:/usr/local/openresty/nginx/lua/:rw             - ${OPENRESTY_LOG_DIR}:/home/wwwlogs/openresty/:rw         restart: always         networks:             - frontend         depends_on:             - php   php:         image: ${PHP_IMAGE}         container_name: php         build:             context: ./service/php         volumes:             - ${SOURCE_DIR}:/home/wwwroot/:rw             - ${PHP_LOG_DIR}:/var/log/php             - ${DATA_DIR}/composer:/tmp/composer             #- ${PHP_CONF_FILE}:/usr/local/etc/php/php.ini             #- ${PHP_FPM_CONF_FILE}:/usr/local/etc/php-fpm.d/www.conf             #- ${SUPERVISOR_CONF_FILE}:/etc/supervisord.conf             #- ${SUPERVISOR_CONF_DIR}:/etc/supervisor/conf.d         restart: always         networks:             - frontend             - backend         depends_on:             - mysql 

遇到的情况就是,不管是 Openresty 的 log , 还是程序打印出来的 $_SERVER[‘REMOTE_ADDR’] 都是 docker 网关的地址,拿不到真实的用户 IP,就很尴尬…

有没有大佬能提点一下,谢谢啦

大佬有話說 (21)

  • 資深大佬 : oott123

    你说的“docker 网关”是什么东西?

  • 主 資深大佬 : kenshin912

    @oott123 #1 就是 docker inspect ${Container} 看到的 Gateway

    就这里了
    我这边看到的 Client IP 一直是这个 Gateway 的地址

    “`
    “NetworkID”: “e9d63ecbe9c731c56c4279be95fe1f04501ec9adb0f7b42ffd91bfc5f157664b”,
    “EndpointID”: “491a05c9061f5464ec29f17bd28feda572ab3db5723f3f078a250747a8c1fe57”,
    “Gateway”: “172.19.0.1”,
    “IPAddress”: “172.19.0.3”,
    “IPPrefixLen”: 16,
    “IPv6Gateway”: “”,
    “GlobalIPv6Address”: “”,
    “GlobalIPv6PrefixLen”: 0,
    “MacAddress”: “02:42:ac:13:00:03”,
    “DriverOpts”: null
    “`

  • 資深大佬 : SingeeKing

    如果服务很简单可以直接 –net=host

    如果不太方便,那么几乎没有办法;可以考虑在外层负载均衡 /CDN 将用户的 IP 写入 Headers 然后 openresty 配置信任这个自己写的 Headers

  • 主 資深大佬 : kenshin912

    @SingeeKing #3 感谢
    –net=host 请问是加在哪里呢?
    我之前 Google 到的解决方案中有建议将 openresty 的网络修改为 host 模式,我在 openresty 的 ports 那里定义过但是似乎不起作用,如果定义为 networks_mode: host,则 openresty 无法启动,因为 openresty 的配置文件中定义了 fastcgi_pass php:9000 , openresty 不在 frontend 网络中,找不到 php:9000 …

    网络上还有办法就是安装 traefik,然后手动追加一个 X-Real-IP 到 headers 里面,看了下挺麻烦心态也有点崩,所以只好跑 V2EX 来问问各位大佬们有没有什么办法了 Docker compose 搭建的测试环境下,没办法拿到真实的 Client IP 吗?

  • 資深大佬 : SingeeKing

    @kenshin912 #4 你这种情形就不适合配置 network host 了…… 只能是前置追加了

  • 主 資深大佬 : kenshin912

    @SingeeKing #5 好吧,谢谢大佬,研究一下 traefik 的用法去…

  • 資深大佬 : shynome

    #ports 写法改成下面这样就可以了
    ports:
    – { mode: host, protocol: tcp, target: 80, published: 80 }
    #要注意的是只能有一个这样的服务不然会端口冲突
    deploy: &deploy
    replicas: 1

  • 資深大佬 : shynome

    deploy: &deploy
    replicas: 1
    #可能要加上下面这个才行
    endpoint_mode: dnsrr

  • 資深大佬 : also24

    简单点直接套娃吧,外面套个 proxy_protocol Docker compose 搭建的测试环境下,没办法拿到真实的 Client IP 吗?

    https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/

  • 資深大佬 : Symo

    X-Real-IP 还是个比较常用的办法, 阿里云自己的 SLB 就是用这个 header 来识别 client ip 的, 不然 vps 拿到的全是 slb 的内网 ip

  • 主 資深大佬 : kenshin912

    @shynome 好的,谢谢大佬我去试试看

  • 主 資深大佬 : kenshin912

    @shynome 我没有启动 Swarm,直接 docker compose up -d 启动的,也需要设定副本数量嘛

  • 資深大佬 : shynome

    @kenshin912 那不用设定副本数量

  • 主 資深大佬 : kenshin912

    @shynome #13 大佬,我已经修改了 docker-compose.yaml

    “`
    build:
    context: ./service/openresty
    ports:
    – { mode: host, protocol: tcp, target: 80, published: 80 }
    – { mode: host, protocol: tcp, target: 443, published: 443 }
    “`

    但是没有任何效果
    endpoint_mode: dnsrr 这个我添加后是无法启动的,提示:
    Unsupported config option for services.openresty: ‘endpoint_mode’

  • 資深大佬 : shynome

    @kenshin912 干, docker-compose 起的都是可以直接拿到客户端的地址的, openresty 这里就可以拿到客户端的地址, 转发到 php 这里的话就只能拿到 openresty 的地址, 如果用的是 docker swarm 才会拿不到客户端的地址, 所以你到底用的是啥? 前面还有层代理?

  • 主 資深大佬 : kenshin912

    @shynome #15 我真的用的是 docker compose 起的服务啊
    openresty 的 log 也都只能拿到 172.19.0.1 这种 Gateway 的地址,我一直很纳闷。
    之前我在 Docker Swarm 里面遇到过这种问题,不过当时没来得及解决。
    现在我只是拿 docker-compose 起了个测试环境而已,还是这种问题,我也好郁闷。

    系统环境是 Cent OS 8.2,docker 版本是 Docker version 19.03.13, build 4484c46d9d

  • 資深大佬 : muzuiget

    我觉得根本不是 docker 的问题喔,一般来说 $_SERVER[‘REMOTE_ADDR’] 就是 TCP 层面发起端的 IP 。如果不是你想要的用户 IP,那么数据传递时中间肯定有个节点再起另一个新 TCP 链接到你的 web 服务器上,就像使用代理一样。除非代理以某种方式告知,否则你搞不到原始 IP 的。

    我看你用的是 openresty,也就是 nginx, 在折腾其它方案之前,先看看是不是有 X-Forwarded-For 这个 HTTP header,或者先打印出所有 X- 开头的 headers 看看。

  • 主 資深大佬 : kenshin912

    @muzuiget #17 打印过 $_SERVER , 整个看了一圈确实是来自于 Docker 的 Gateway 。
    不过刚才 15 提醒了我,docker-compose 起的是可以直接拿到客户端 IP 的不应该有问题。
    我登录了一台阿里云 HK 的节点,观察了这台服务器上同样是 docker-compose 起的 openresty,log 里面的 IP 是正常的没有问题。
    结合之前我操作 firewall-cmd –zone=public –remove-masquerade 以后,log 里面的 IP 就正常了,但是 openresty 会找不到 php:9000 来看,应该还是服务器配置或者防火墙有问题。

    所以,你开始的结论应该是正确的,不是 docker 的问题。
    只是我现在还是不知道到底哪里出了问题,只好再去一个个排查一下。

  • 資深大佬 : privil

    基于 iptables,会转发 nat 一次的,所以你拿到的地址都是 docker gateway 的

  • 主 資深大佬 : kenshin912

    @privil 我关闭转发后 openresty 的 log 显示拿到了正确的 Client IP,但是访问站点却抛出了 502,看 error_log 显示 no route to host 172.19.0.2 之类的错误
    但是还是无法解决我的问题,毕竟站点挂了。

  • 主 資深大佬 : kenshin912

    @shynome #15
    @muzuiget #17
    @privil #19

    感谢各位的帮助,问题已经解决。
    参考链接:
    https://stackoverflow.com/questions/47537954/how-to-make-docker-container-see-real-user-ip
    https://stackoverflow.com/a/61263768

    首先将 openresty 所在 network 对应的网卡接口调整到 internal 区域
    执行完这个命令后重启防火墙, 访问 openresty 会报 no route to host 的错误
    接着执行后三条命令即可。

    firewall-cmd –zone=internal –change-interface=br-e9d63ecbe9c7 –permanent
    firewall-cmd –reload
    sysctl net.bridge.bridge-nf-call-iptables=0
    sysctl net.bridge.bridge-nf-call-arptables=0
    sysctl net.bridge.bridge-nf-call-ip6tables=0

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具