跳到正文
查个机

终端代理

docker 代理怎么设

首发 查于 第 1 版阅读约 7 分钟

要点

拉镜像是 dockerd 在联网,要给 daemon 设代理;容器里的程序联网,要另给容器传 HTTP_PROXY。两处互不相干,终端里设的代理变量对它们都不起作用。

问:三处代理各管什么?

短答:拉镜像归 daemon,容器里的程序归容器,构建时 RUN 的命令归构建容器。

场景 谁在联网 在哪设 何时生效
docker pull、拉基础镜像 dockerd Linux:systemd 配置或 daemon.json;Docker Desktop:设置页 重启 daemon 后
容器里的 apt、pip、curl 容器内的进程 ~/.docker/config.json 的 proxies,或启动容器时加 --env 参数 新建的容器
docker build 时 RUN 的命令 构建容器 config.json 的 proxies 会自动变成构建参数,或用 –build-arg 下一次构建

dockerd[进程]Docker 的后台服务,镜像是它去仓库拉的。① 它不读你终端里的环境变量;② Linux 上它跑在宿主机,127.0.0.1 就是宿主机本身。参见:容器代理。

容器代理[配置项]写进容器环境变量的 HTTP_PROXY 一类设置。① 只对新建的容器生效;② 地址要写容器能连到的宿主机地址。

问:Linux 上怎么给 daemon 设代理?

短答:在 docker.service 旁边加一个 systemd 配置片段,写上三行环境变量,重载后重启。

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://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker

也可以写进 /etc/docker/daemon.json,官方文档把这种写法放在前面,并说明 daemon.json 里的设置优先于环境变量:

{
  "proxies": {
    "http-proxy": "http://127.0.0.1:7890",
    "https-proxy": "http://127.0.0.1:7890",
    "no-proxy": "localhost,127.0.0.1"
  }
}

改完同样执行 sudo systemctl restart docker。rootless 模式的配置片段放在 ~/.config/systemd/user/docker.service.d/ 下,命令改用 systemctl –user,不加 sudo。7890 请改为你客户端里显示的端口;systemd 配置里的地址若含百分号这类特殊字符,要写成两个 %% 转义。

问:Docker Desktop 在哪设?

短答:在设置页的 Resources → Proxies 里设,daemon.json 里的 proxies 对它无效。

  1. 打开 Docker Desktop 的 Settings → Resources → Proxies。
  2. 代理客户端已经开了系统代理的,选 System proxy 沿用;否则选 Manual configuration,在 Web Server (HTTP) 和 Secure Web Server (HTTPS) 两栏填客户端的地址和端口,下方可写不走代理的地址。
  3. 新版本把这里分成 Docker Desktop proxy 和 Containers proxy 两块,docker pull 走的是后一块;后一块没配时,拉镜像才退回用前一块。
  4. 按 Apply 保存,Docker Desktop 会自己重启引擎。

问:容器里的程序怎么走代理?

短答:在 ~/.docker/config.json 里写 proxies,之后新建的容器和构建都会自动带上这几个变量。

{
  "proxies": {
    "default": {
      "httpProxy": "http://172.17.0.1:7890",
      "httpsProxy": "http://172.17.0.1:7890",
      "noProxy": "localhost,127.0.0.1"
    }
  }
}

这里的地址不能写 127.0.0.1。Linux 上默认网桥 docker0 的宿主机地址通常是 172.17.0.1(用 ip addr show docker0 确认);Docker Desktop 上写 host.docker.internal。代理客户端还要打开允许局域网连接,否则只听本机回环,容器连不进来。保存后不用重启,对之后新建的容器生效。Docker 文档提醒,这些变量以明文存在容器配置里,代理地址带账号密码时要留意。

问:怎么确认已经走代理?

短答:daemon 看 docker info,容器里用 curl 取一次出口 IP。

docker info | grep -i proxy
docker pull hello-world
docker run \
  --rm curlimages/curl -s https://chageejichang.co/api/chukou

docker info 里出现 HTTP Proxy、HTTPS Proxy 两行,说明 daemon 读到了设置;hello-world 能拉下来,说明拉镜像那条路通了。末一条在容器里访问本站的出口接口,返回的 IP 和 ASN 就是容器经代理后的出口;本站接口打不开时,把地址改为第三方的 https://ipinfo.io/json。容器里返回的出口和宿主机上用 curl 取到的不一致,说明容器没走代理,或者走了另一条分流规则。

问:Linux 和 Docker Desktop(Windows、macOS)有什么不同?

短答:设 daemon 代理的位置、容器连宿主机的地址、重启的方式都不同。

项 Linux(Docker Engine) Docker Desktop(Windows、macOS)
daemon 代理 systemd 配置片段或 daemon.json 设置页 Resources → Proxies
容器里连宿主机 docker0 网桥地址,常见 172.17.0.1 host.docker.internal
重启 daemon sudo systemctl restart docker 设置页按 Apply 自动重启
config.json 位置 ~/.docker/config.json Windows 为 %USERPROFILE%\.docker\config.json,macOS 同 Linux

问:不用了怎么撤销?

短答:删掉配置片段或 daemon.json 里的 proxies,重启 daemon;再从 config.json 里删掉 proxies。

sudo rm /etc/systemd/system/docker.service.d/http-proxy.conf
sudo systemctl daemon-reload
sudo systemctl restart docker
docker info | grep -i proxy

末一条不再有输出即已清除。Docker Desktop 在 Proxies 页改回 No proxy 或 System proxy 后按 Apply。git 拉 GitHub 被重置的情况见 Recv failure: Connection was reset,git 自己的代理设法见 git set proxy;容器里解析域名出错时,先按 DNS 检测 一页查解析器。

常见问题

给 daemon 设了代理,容器里 apt-get 还是连不上,为什么?

daemon 的代理只管它自己拉镜像,不会传进容器。容器要联网,得用 ~/.docker/config.json 的 proxies 或 docker run 的 --env 另外传;地址还不能写 127.0.0.1,因为那在容器里指的是容器自己。

docker build 里 RUN pip install 超时,代理加在哪?

加在构建参数上。config.json 里配了 proxies 的,构建时会自动作为构建参数传进去;没配就用 docker build --build-arg HTTPS_PROXY=… 临时传。别写进 Dockerfile 的 ENV,那会留在镜像里。

镜像加速地址和代理能一起用吗?

能。加速地址改的是从哪里拉,代理改的是怎么连过去。国内的加速地址可以放进 NO_PROXY 让它直连,境外仓库再走代理,两者互不冲突。

本页第 (1)
  • :首发

网站地图 · 机场推荐