HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 代理技术全栈手册

    • 代理技术全栈手册 - HiHuo
    • 原理篇

      • 第01章 代理是什么:正向 / 反向 / 透明 / 隧道的统一模型
      • 第02章 代理与网络层级:L3 / L4 / L5 / L7 在哪里截断流量
      • 第03章 一个请求穿过代理的一生:连接生命周期全景
    • 协议篇

      • 第04章 HTTP 代理协议:绝对 URI、CONNECT 隧道、转发头与连接池
      • 第05章 HTTPS 与 TLS 代理:终止 / 透传 / MITM / SNI / mTLS
      • 第06章 SOCKS 协议:SOCKS4/4a/5 与 UDP ASSOCIATE 报文级解析
      • 第07章 HTTP/2、gRPC 与 HTTP/3(QUIC) 代理的挑战
      • 第08章 代理自动配置:PAC / WPAD / 系统代理 / NO_PROXY
    • 层级与转发篇

      • 第09章 L4 代理:TCP/UDP 转发与连接级负载均衡
      • 第10章 L7 代理:协议感知与基于内容的路由
      • 第11章 透明代理:iptables REDIRECT/DNAT、TPROXY 与 eBPF 劫持
      • 第12章 数据搬运的艺术:splice / sendfile / 零拷贝 / io_uring
    • 组件横评篇

      • 第13章 Nginx / OpenResty:反向代理、upstream 与 Lua 可编程
      • 第14章 HAProxy:L4/L7、ACL、健康检查与 stick table
      • 第15章 Envoy:xDS 动态配置与 filter chain,为何是云原生数据面
      • 第16章 Traefik / Caddy:自动服务发现与自动 HTTPS
      • 第17章 Squid 与正向/缓存代理:企业出网、缓存与审计
      • 第18章 mitmproxy:抓包、改包、脚本化调试
      • 第19章 内网穿透与隧道:frp / gost / SSH 隧道 / ngrok
      • 第20章 科学上网生态的技术原理(技术中立)
    • 多语言手写篇

      • 第21章 Go:100 行手写 HTTP/CONNECT + SOCKS5 代理
      • 第22章 Rust:基于 tokio 的高性能 TCP 代理
      • 第23章 Python:asyncio 实现,适合调试与脚本
      • 第24章 C:epoll 裸写与零拷贝,及语言选型对比
    • 容器与K8s篇

      • 第25章 Docker 里的代理:HTTP_PROXY、build/pull 与 daemon 配置
      • 第26章 Sidecar 与流量劫持:Istio init-container 的 iptables 原理
      • 第27章 Ingress 与南北流量:Ingress-nginx 与 Gateway API
      • 第28章 Egress 与出网治理:出口网关、registry mirror、审计
      • 第29章 Service Mesh 数据面:Envoy Sidecar 全链路
    • 进阶篇

      • 第30章 可编程代理:Lua / Wasm / eBPF / xDS,代理的"软件定义"
      • 第31章 性能调优:并发模型、连接池、超时与重试、压测
      • 第32章 排错决策树:502 / 504 / 握手失败 / 环路 / 泄漏
      • 第33章 代理安全:开放代理、SSRF、凭证泄漏与攻击面
    • 底层机制篇

      • 第34章 代理的背压与流控:一个代理最难的部分
      • 第35章 socket 与 TCP 状态机:半关闭、超时、连接生命周期
      • 第36章 HTTP/2 帧、流控与 HPACK:h2 代理的内部机制
      • 第37章 负载均衡算法推导与韧性状态机
      • 第38章 Capstone:把玩具代理改造成生产级骨架
    • 综合实战篇

      • 第39章 企业多跳转发链:拓扑、协议矩阵与贯穿性难题
      • 第40章 端到端实战:把 6 类流量全代理通
      • 第41章 更刁钻的流量:gRPC、长轮询、WebRTC、大文件、双向流
      • 第42章 可落地完整参考实现:一套能跑的多协议转发栈
    • 附录

      • 附录 A:代理协议报文速查(HTTP / SOCKS / PAC / PROXY protocol)
      • 附录 B:组件选型决策树
      • 附录 C:抓包与命令速查

第25章 Docker 里的代理:HTTP_PROXY、build/pull 与 daemon 配置

学习目标

  • 分清 Docker 代理的三个独立层面:daemon 拉镜像 / build 构建 / run 运行——搞混是头号坑
  • 正确配置各层面的代理,验证 docker pull/build/容器内出网
  • 避开容器里 NO_PROXY 的集群坑与 localhost 指向坑
  • 理解 registry mirror 本质是镜像仓库的反向代理/缓存

前置知识

  • 第08章 代理自动配置(环境变量/NO_PROXY)、第01章 正向代理
  • 容器手册 · 容器网络原理

原理

三个独立层面:这是最大坑源

"配了 Docker 代理还是不生效"——几乎都是因为没分清这三个互相独立的层面:

① Docker daemon 走代理   → 影响 docker pull/push(dockerd 自己去拉镜像)
② docker build 走代理    → 影响构建时容器内的 apt/npm/pip 等下载
③ 容器运行时走代理       → 影响 docker run 起来的应用出网

它们配置位置完全不同、互不影响。"docker pull 不走代理"要配①,"build 时 apt 装不上"要配②,"容器里应用连不上外网"要配③。先定位是哪个层面,再对症下药。

层面①:daemon 代理(拉镜像)

docker pull 是 dockerd 守护进程发起的,不读你 shell 的环境变量。要给 systemd 管理的 dockerd 配代理,用 systemd drop-in:

# /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://10.0.0.1:3128"
Environment="HTTPS_PROXY=http://10.0.0.1:3128"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,*.internal"
sudo systemctl daemon-reload && sudo systemctl restart docker
sudo systemctl show --property=Environment docker   # 验证生效

层面②③:build 与 run 代理(~/.docker/config.json)

构建和运行容器内的代理,现代用 ~/.docker/config.json 的 proxies,Docker 会自动注入 HTTP_PROXY 等环境变量到 build/run:

{
  "proxies": {
    "default": {
      "httpProxy":  "http://10.0.0.1:3128",
      "httpsProxy": "http://10.0.0.1:3128",
      "noProxy":    "localhost,127.0.0.1,*.internal,10.0.0.0/8"
    }
  }
}

或显式传:

# build 时(老式 --build-arg,需 Dockerfile 里 ARG 声明)
docker build --build-arg HTTP_PROXY=http://10.0.0.1:3128 -t myimg .
# run 时
docker run -e HTTP_PROXY=http://10.0.0.1:3128 -e NO_PROXY=localhost myimg

localhost 陷阱:容器里的 localhost 不是宿主

容器有独立网络命名空间(容器手册)。容器里的 127.0.0.1 是容器自己,不是宿主机。所以代理跑在宿主机时:

  • ❌ HTTP_PROXY=http://127.0.0.1:3128——容器里这指向容器自己,连不上
  • ✅ 用宿主 IP,或 host.docker.internal(Docker Desktop 自带;Linux 上需 --add-host=host.docker.internal:host-gateway)

NO_PROXY 的容器/集群坑(呼应第08章)

第08章 强调过:设了代理一定要把不该走代理的内网目标加进 NO_PROXY。容器场景尤其要排除:

localhost,127.0.0.1          # 本机
172.17.0.0/16               # Docker 默认网桥网段(容器间)
host.docker.internal         # 宿主
私有 registry 域名/IP        # 拉私有镜像不该走外网代理
.svc,.cluster.local          # K8s 集群内(到了 K8s 更要命,见第26-28章)
169.254.169.254              # 云元数据(绝不能走外部代理)

漏了集群内网段,会导致"容器访问内部服务/registry 全部超时"——一个超高频故障。

registry mirror:镜像仓库的反向代理/缓存

国内拉 Docker Hub 慢,常配 registry mirror——这本质是给镜像仓库做了个反向代理 + 缓存(第10章、第28章):

// /etc/docker/daemon.json
{ "registry-mirrors": ["https://mirror.example.com"] }

docker pull nginx 会先问 mirror,mirror 缓存命中直接给、未命中回源 Docker Hub 并缓存——和 Squid 缓存(第17章)一个道理。这是 第28章 Egress 出网治理 的常用手段。


️ 实现 / 命令

实验一:配 daemon 代理并验证拉镜像

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf >/dev/null <<'EOF'
[Service]
Environment="HTTPS_PROXY=http://10.0.0.1:3128"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,registry.internal"
EOF
sudo systemctl daemon-reload && sudo systemctl restart docker

# 抓代理日志能看到 docker pull 的 CONNECT 请求(第04章)
docker pull alpine        # 经代理拉取

实验二:验证三层面互相独立

# 只配了 daemon 代理时:
docker pull alpine                                   # ✅ 走代理(层面①)
docker run --rm alpine wget -qO- http://example.com  # ❌ 容器内不走代理(层面③没配)
# 要让容器内出网,得另配 config.json proxies 或 -e HTTP_PROXY(层面③)

这个对比一眼说明:三层面独立,配了一个不等于配了全部。

实验三:容器内代理指向宿主(localhost 陷阱)

# 代理在宿主 3128,容器内要用 host-gateway 而非 127.0.0.1
docker run --rm --add-host=host.docker.internal:host-gateway \
  -e HTTP_PROXY=http://host.docker.internal:3128 \
  alpine wget -qO- http://example.com

实验四:registry mirror 加速

sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{ "registry-mirrors": ["https://mirror.example.com"] }
EOF
sudo systemctl restart docker
docker pull nginx          # 经 mirror 拉取(缓存命中则秒回)
docker info | grep -A2 "Registry Mirrors"   # 验证生效

排错

现象根因解决
docker pull 不走代理配错层面(配了 shell env 而非 daemon)配 systemd drop-in(层面①)
build 时 apt/npm 装不上build 没代理config.json proxies 或 --build-arg(层面②)
容器内应用连不上外网run 没代理-e HTTP_PROXY 或 config.json(层面③)
容器内代理 127.0.0.1 连不上localhost 指向容器自己用 host.docker.internal/宿主 IP
拉私有 registry 走了外网代理超时NO_PROXY 没含 registry把 registry 域名/IP 加进 NO_PROXY
访问容器间服务超时NO_PROXY 没含 172.17/16补容器网段
https_proxy=https:// 报错scheme 写错(第08章)改 http://代理

本章小结

  • Docker 代理分三个独立层面:daemon(pull/push)、build(构建内)、run(运行内)——搞混是头号坑。
  • daemon 配 systemd drop-in;build/run 配 ~/.docker/config.json proxies 或 -e/--build-arg。
  • 容器里 localhost 是容器自己,代理指宿主用 host.docker.internal;NO_PROXY 必须含容器/集群网段。
  • registry mirror 是镜像仓库的反向代理+缓存,属 Egress 治理手段。

下一章 第26章 Sidecar 与流量劫持,进入 K8s 核心:Istio 如何用 init-container + iptables 把 Pod 流量零侵入地劫持给 Envoy——这是 第11章透明代理 在 K8s 的终极落地。

Next
第26章 Sidecar 与流量劫持:Istio init-container 的 iptables 原理