Skip to content
intermediate

如何通过 ProxyScrape 代理路由 Docker 容器流量

使用环境变量、客户端与守护进程代理配置以及应用级设置,让容器流量、镜像拉取和 Compose 服务经由 ProxyScrape 的 HTTP 或 SOCKS5 端点转发。

Linux SOCKS5 HTTP(S) 其他

概述

Docker 容器与宿主机的 shell 及其代理设置相互隔离,因此在终端中可用的代理不会自动在 docker run 或 docker compose 内生效。有三个实用位置可以插入 ProxyScrape 端点:容器内部以环境变量的形式;在 Docker 客户端或守护进程层面,使镜像拉取和构建走代理;以及在那些忽略环境变量或需要 SOCKS5 的工具的应用配置中。

ProxyScrape 提供住宅、数据中心和移动代理,支持 http 和 socks5,可按用量计费或选择包月固定套餐,因此你可以根据所容器化的工作负载来匹配合适的代理池和计费模式。端点主机、端口和凭据可在你的 ProxyScrape 仪表板中查看。

本教程涵盖上述三个层面,并演示如何确认容器流量确实经由代理发出。

你需要准备

  • Docker Engine 20.10 或更高版本,或 Docker Desktop
  • Docker Compose v2(docker compose)
  • 一个 ProxyScrape 订阅,以及仪表板中的主机、端口、用户名和密码
  • 你的网络能够对外访问代理端口

选择在何处应用代理

层面 适用于 协议 说明
容器环境变量 读取 HTTP_PROXY 的客户端(curl、pip、apt、许多 SDK) http 设置最快;大多数运行时忽略 SOCKS5 URL
Docker 客户端或守护进程配置 docker pull、docker build、docker push http 守护进程级别的改动需要重启服务
应用配置或转发器 有自身代理设置的工具,或仅支持 SOCKS5 的需求 http、socks5 对非标准客户端最可靠

先从环境变量入手,只有当某个工具忽略它们时,才依次往下采用表中的方法。

步骤

1. 将凭据存放在镜像之外

根据你要使用的协议构建代理 URL:

http://<username>:<password>@<host>:<port>
socks5h://<username>:<password>@<host>:<port>

将相关取值保存在一个绝不会进入构建上下文或 Git 仓库的文件中。

mkdir -p ~/.config/proxyscrape
cat > ~/.config/proxyscrape/proxy.env <<'EOF'
PROXY_USER=your-username
PROXY_PASS=your-password
PROXY_HOST=proxy-host-from-dashboard
PROXY_PORT=proxy-port-from-dashboard
EOF
chmod 600 ~/.config/proxyscrape/proxy.env

如果密码中包含 @、:、/ 或 #,在将其放入 URL 之前需要对这些字符进行百分号编码。

2. 从宿主机验证端点

set -a; . ~/.config/proxyscrape/proxy.env; set +a

curl -sS -x "http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" https://api.ipify.org; echo
curl -sS -x "socks5h://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" https://api.ipify.org; echo

请使用 socks5h:// 而非 socks5://,这样主机名解析会在代理端进行,而不是在本地进行。如果两条命令中只有一条成功,则在本设置的其余部分使用该协议。

3. 将代理传递给单个容器

docker run --rm \
  -e HTTP_PROXY="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" \
  -e HTTPS_PROXY="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" \
  -e http_proxy="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" \
  -e https_proxy="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" \
  -e NO_PROXY="localhost,127.0.0.1,::1" \
  curlimages/curl:latest -sS https://api.ipify.org; echo

许多运行时只读取小写形式的变量名,另一些则只读取大写形式,因此两者都要设置。NO_PROXY 可让回环地址和容器内部流量不经过代理。

4. 使用 Docker Compose 管理代理

在 Compose 项目目录中创建一个 .env 文件,以便 Compose 能够插值这些取值,并将其加入 .gitignore。

PROXY_USER=your-username
PROXY_PASS=your-password
PROXY_HOST=proxy-host-from-dashboard
PROXY_PORT=proxy-port-from-dashboard
services:
  worker:
    image: python:3.12-slim
    environment:
      HTTP_PROXY: "http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
      HTTPS_PROXY: "http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
      http_proxy: "http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
      https_proxy: "http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
      NO_PROXY: "localhost,127.0.0.1,::1"
    command:
      - python
      - -c
      - "import urllib.request; print(urllib.request.urlopen('https://api.ipify.org').read().decode())"
docker compose up --build
docker compose logs worker

请注意,放在 env_file 中的取值会被注入容器,但不会用于 ${...} 插值。Compose 会从 shell 环境或项目的 .env 文件中读取这些值。

5. 让镜像拉取和构建走代理

对于单个用户,配置 Docker 客户端,使构建能够继承代理。将其保存为 ~/.docker/config.json:

{
  "proxies": {
    "default": {
      "httpProxy": "http://<username>:<password>@<host>:<port>",
      "httpsProxy": "http://<username>:<password>@<host>:<port>",
      "noProxy": "localhost,127.0.0.1"
    }
  }
}

Docker 的客户端和守护进程代理配置仅支持 HTTP 代理,因此即使你在容器内使用 SOCKS5,这里也要使用 http:// 端点。

在守护进程本身需要访问镜像仓库的 Linux 宿主机上,改为添加一个 systemd drop-in:

# /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://<username>:<password>@<host>:<port>"
Environment="HTTPS_PROXY=http://<username>:<password>@<host>:<port>"
Environment="NO_PROXY=localhost,127.0.0.1"
sudo systemctl daemon-reload
sudo systemctl restart docker
docker info | grep -i proxy

6. 配置那些忽略环境变量的工具

少数包管理器和运行时需要显式设置。

基于 Debian 的镜像中的 apt:

echo 'Acquire::http::Proxy "http://<username>:<password>@<host>:<port>";' \
  > /etc/apt/apt.conf.d/95proxy

pip:

pip install --proxy "http://<username>:<password>@<host>:<port>" requests

对于仅支持 SOCKS5 的工具,proxychains-ng 提供了一个包装器,强制连接经由代理:

# /etc/proxychains4.conf (excerpt)
strict_chain
proxy_dns
[ProxyList]
socks5 <host> <port> <username> <password>
proxychains4 curl -sS https://api.ipify.org; echo

7. 验证出站流量并留意用量

确认容器所看到的地址,然后将其与未设置任何代理变量时得到的地址进行对比。如果两者一致,说明代理并未被使用。

docker run --rm \
  -e HTTPS_PROXY="http://$PROXY_USER:$PROXY_PASS@$PROXY_HOST:$PROXY_PORT" \
  curlimages/curl:latest -sS https://api.ipify.org; echo

轮换型端点可能在每次请求时返回代理池中不同的出口 IP,这对于抓取和监控类工作负载而言是正常现象。如果你的 ProxyScrape 套餐提供会话或粘性选项,请按仪表板中的说明将会话标识符添加到用户名字段中,并在那里留意用量,因为请求量是计量的。

故障排查

407 Proxy Authentication Required(需要代理身份验证)

用户名或密码有误,或者密码中包含未进行百分号编码的字符。请从 ProxyScrape 仪表板重新复制凭据并重建 URL。

宿主机可用但容器失败

  • 确认容器内同时设置了大写和小写形式的代理变量。
  • 检查容器能否解析代理主机名:docker run --rm curlimages/curl:latest -sS -I http://<host>。
  • 在 Docker Desktop 上,容器通过虚拟机访问互联网,因此请确认代理端口未被宿主机防火墙拦截。
  • 打印这些变量以排除取值为空的情况:docker run --rm --env-file ~/.config/proxyscrape/proxy.env alpine env | grep -i proxy。

连接超时

  • 出口端口可能被企业防火墙或本地 VPN 拦截。请先在宿主机上进行测试。
  • HTTP 和 SOCKS5 端点通常监听不同的端口。请使用与你所配置协议相匹配的端口。

SOCKS5 URL 被忽略

大多数运行时仅实现 HTTP 代理环境变量。请改用应用级设置,例如 --proxy、proxychains-ng 包装器,或库自身的代理参数,而不要依赖 ALL_PROXY。

配置守护进程后 docker pull 仍然失败

运行 docker info | grep -i proxy 以确认守护进程已读取这些变量,并记住 ~/.docker/config.json 仅对当前用户生效。检查你的 noProxy 列表,看是否有条目意外涵盖了镜像仓库主机名。

TLS 或证书错误

HTTPS 目标要求代理支持 CONNECT 方法,curl 和 Docker 客户端会自动使用该方法。如果你配置的是 HTTP 代理 URL,请确认目标端口在你的 ProxyScrape 端点上是允许的。

总结

  • 容器不会继承宿主机的代理设置,因此请通过 HTTP_PROXY、HTTPS_PROXY 及其小写等价形式显式传递凭据。
  • 使用 ~/.docker/config.json 或 systemd drop-in 来路由镜像拉取和构建,并记住 Docker 自身的代理配置仅支持 HTTP。
  • apt、pip 以及仅支持 SOCKS5 的客户端等部分工具需要各自的配置或 proxychains-ng 包装器。
  • 始终从容器内部验证出口 IP,并将凭据保存在已排除在版本控制之外的文件中。
  • ProxyScrape 的住宅、数据中心和移动代理池支持 http 和 socks5,提供按用量计费或包月固定计费,让你能够为每种容器化工作负载选择合适的方案。