同一批代理IP,本机跑的很稳,进了Docker就全超时,最后查到三处

上个月把采集服务容器化,本地 docker-compose 起了三个容器,跑了两周一直很稳。搬到客户机房那天,日志里全是 read timeout,目标站的响应一条都没有。第一反应是手上这批短效IP被封了,重新提了一批,还是原样。折腾到下午才反应过来:可能压根没走代理。在次回头看,容器里挂代理的坑就那么几个,记下来给同样踩过的人。

先别急着换IP,先确认请求走没走代理

最快的办法是在容器里手工发一条:curl -x http://账号:密码@IP:端口 https://httpbin.org/ip。能返回代理的出口IP,说明容器到代理、代理到目标站两条链路都通;这时候程序还超时,就不要再怀疑IP了。

另一个信号是 curl -v 的输出:真正走HTTP代理时,会先看到一行 CONNECT 目标域名:443,没有这行就是直连。直连有时候也能拿到数据,只是出口IP不对,这种"不报错但IP不对"的情况比超时更难发现。我后来在请求日志里加了一行,打印脱敏后的实际出口IP,才发现大概一半请求根本没经过代理。

环境变量:大小写各认一半,还只在当前shell活着

这是第一个坑。宿主机上 export http_proxy=... 之后本地跑脚本没问题,但容器是独立环境,docker run 不挂 -e 就什么都没有。

更麻烦的是不同程序认的变量不一样:Python 的 requests 只认小写 http_proxy/https_proxy;curl 大小写都认;Java 完全不看环境变量,要加 -Dhttp.proxyHost 和 -Dhttp.proxyPort。我当时 supervisor 配置里只写了大写 HTTP_PROXY,Python 进程读不到,两个都写上才正常。

如果是 systemd 拉起的服务,也别指望它继承你登录 shell 里的变量,要在 unit 文件里写 Environment=,改完 systemctl daemon-reload。

docker run -d \
  -e http_proxy=http://user:pass@1.2.3.4:8080 \
  -e https_proxy=http://user:pass@1.2.3.4:8080 \
  -e HTTP_PROXY=http://user:pass@1.2.3.4:8080 \
  -e HTTPS_PROXY=http://user:pass@1.2.3.4:8080 \
  -e NO_PROXY= \
  --dns 223.5.5.5 \
  your-image

NO_PROXY 里那条内网域名,把请求悄悄放行了

配置是从公司模板抄的,NO_PROXY 里带着 .corp.local 和 10.0.0.0/8。目标站在测试环境里刚好解析到 10 段地址,于是被当成内网流量直连出去了,程序表现就是"代理没生效"。

在容器里执行 env | grep -i proxy,把 NO_PROXY 打出来逐条对一遍,比猜快得多。生产容器我最后是把 NO_PROXY 直接置空,只留确实要走内网的那一两个域名。

代理地址写的是域名,容器里根本解析不到

供应商后台给的是 proxy.xxx.com:8080,宿主机能解析,容器里 DNS 只指到 127.0.0.11,解析失败的表现和连接超时一模一样。改成IP直连,或者 docker run 加 --dns 223.5.5.5,问题就没了。

顺带说一句,容器时间不对也会出怪问题:有的服务商按时间戳做签名,容器时区差八小时,鉴权直接失败,日志里看着像账号密码错。这种时候先去容器里 date 一下,能省不少时间。

单条能通、20并发全红,是句柄和连接池

单请求测通了,压到20并发又开始大面积超时。查下来两件事:一是 ulimit -n 默认1024,多进程一开很快打满;二是 requests 默认每次新建连接,短效IP本来就换得勤,连接复用没做,握手开销全砸在超时上。

改成 Session 加 HTTPAdapter(pool_maxsize=50),超时拆成连接5秒、读取15秒,报错信息一下就清楚了。还有个细节,短效IP别一次提200个放着,按并发数和寿命算着提,提多了也是等它过期,白花钱。

最后落下来的配置清单

  • 环境变量双份:docker run 用 -e 把大小写都传进去,别依赖宿主机。
  • 代码里显式写 proxies:不要赌环境变量,requests 直接在调用处传 proxies= 最稳。
  • NO_PROXY 自查:置空或只留必须项,进容器 env | grep -i proxy 看一眼。
  • 代理用IP:别用域名,容器 DNS 单独配,时区一起校正。
  • 连接复用:Session + pool_maxsize,按并发给,别用默认值。
  • 超时分级:连接5秒、读取15秒,日志打印脱敏后的代理地址和出口IP。
  • 淘汰别太急:连续两次失败再换IP,避免一次抖动把好IP扔掉。

我现在用的是星月代理,池子覆盖全国300多个城市,可用率标在90%以上,高匿,短效IP自动轮换,API实时提取、白名单、会话保持都支持,后台能看到每条订单的提取记录和用量。新用户可以先领免费试用IP,拿上面这套清单在容器里跑一遍再决定买哪个套餐——参数表上的数字,和你在容器里实际跑出来的,经常不是一回事。

代理在容器里不生效,先按环境变量、NO_PROXY、DNS、连接池这四层过一遍,八成都能定位到。实在找不到原因,就在容器里手工 curl 一次,把"链路问题"和"IP问题"分开,比反复换服务商有效得多。

容器里代理不生效,大多不是IP的问题:环境变量的传递方式、NO_PROXY误放行、代理域名解析失败、并发上来后连接池不够,这四层按顺序查一遍,比换一批IP快得多。

「Docker容器里代理IP不生效」相关的资源与工具

本文从一次容器化迁移的排查过程出发,说明宿主机正常、容器内请求全部超时的常见原因:环境变量大小写与作用域、NO_PROXY误放行、容器DNS解析、连接池与文件句柄上限,并给出可直接套用的docker run参数和requests配置。

需要「高匿短效IP」「API实时提取」「白名单」「免费试用」的代理资源,可联系星月代理客户经理,按并发规模和任务时长搭配套餐。

联系方式

电话:

QQ:260696622

微信:Pst1226551254

有问题请找我,期待与您的合作