关键词:HTTP_PROXY、HTTPS_PROXY、代理、Docker、containerd、cURL、systemd、Linux
一、前言
在 Linux 服务器或 Kubernetes 集群中,我们经常会遇到「命令行走代理成功,但后台服务始终连不通」的诡异现象。最典型的例子就是:
bash
export HTTP_PROXY=http://192.168.1.100:7897
curl -I https://www.google.com # ✅ 秒出 200
docker pull hello-world # ❌ 卡住不动
本文将带你彻底搞懂:
HTTP_PROXY/HTTPS_PROXY到底影响了谁?- 为什么 cURL 能用,Docker 却用不了?
- 怎样让 系统级服务 也乖乖走代理?
二、HTTP_PROXY 是什么?
1. 定义
HTTP_PROXY / HTTPS_PROXY 是 进程级别的环境变量 ,用于告诉 支持它的应用程序:
"你的 HTTP/HTTPS 请求不要直接发,先发到这个代理地址,由它帮你转发。"
2. 作用域
- 仅对「读取该变量」的进程有效
- 谁启动时拿到,谁就用;拿不到就直连
- 不会自动继承给「已运行」的系统服务
三、实验:同一台机器,三种不同结果
| 场景 | 是否走代理 | 原因 |
|---|---|---|
curl www.google.com |
✅ | curl 是当前 shell 子进程,继承了 HTTP_PROXY |
wget www.google.com |
✅ | wget 同样读变量 |
docker pull hello-world |
❌ | dockerd 是 systemd 服务 ,启动时 没有 这些变量 |
kubelet 拉镜像 |
❌ | 同上,也读不到终端里 export 的变量 |
四、底层原理:变量传递链条
text
┌--------------------┐
│ 终端 export │──┐
└--------------------┘ │ 继承
▼
┌--------------------┐
│ curl / wget / 其他 │◀- 子进程,能用代理
└--------------------┘
┌--------------------┐
│ dockerd / kubelet │◀- systemd 启动,**不继承**终端变量
└--------------------┘
结论:
临时
export只能影响「当前 shell 及后续子进程」 ,
对「已开机启动」的系统服务无效!
五、实战:让 Docker 也走代理
1. 写入 systemd
bash
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://192.168.1.100:7897"
Environment="HTTPS_PROXY=http://192.168.1.100:7897"
Environment="NO_PROXY=localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
EOF
2. 重载 & 重启
bash
sudo systemctl daemon-reload
sudo systemctl restart docker
3. 验证
bash
docker info | grep -i proxy
# 输出里能看到刚写的地址
docker pull hello-world
# 秒拉完成
六、Kubernetes 场景扩展
1. 只让 镜像拉取 走代理
-
仅给 containerd 配代理(kubelet 不配,避免它连 apiserver 也绕远路)
-
同样写 systemd:
bashsudo mkdir -p /etc/systemd/system/containerd.service.d # 同上写 http-proxy.conf sudo systemctl restart containerd
2. 给 Pod 内业务 走代理
-
在 Deployment/Helm 的
env里显式写:yamlenv: - name: http_proxy value: "http://192.168.1.100:7897" - name: https_proxy value: "http://192.168.1.100:7897"
七、一张图总结
text
终端 export HTTP_PROXY
│
├─▶ 子进程(curl、wget、python 脚本...) ✅
│
├─▶ 后台服务(dockerd、containerd、kubelet) ❌
│ └─▶ 必须写 systemd 单元文件 ✅
│
└─▶ Pod 内容器 ✅
└─▶ 在 YAML 里显式声明 env ✅
八、常见坑 checklist
| 现象 | 排查点 |
|---|---|
curl 行,Docker 不行 |
是否给 dockerd 写了 systemd 代理 |
| 重启后又失效 | 代理文件是否在 /etc/systemd/system/服务.service.d/ 目录 |
| 空格导致失败 | cat -A 查看文件,确认 7897" 后面没有空格 |
| kubelet 连不上 apiserver | 不要把 kubelet 的代理指向外网;NO_PROXY 里加上集群内网、apiserver 地址 |
九、结语
HTTP_PROXY/HTTPS_PROXY 本身很简单,但**"谁能读到它"**决定了流量走向。
记住一句话:
临时 export 只能玩终端;要让系统服务走代理,就去 systemd 写文件!
把这篇博客收藏起来,下次再遇到「cURL 行,Docker 不行」的怪事,5 分钟就能定位解决。