dockerd 代理
在执行 docker pull
时,是由守护进程 dockerd
来执行。 因此,代理需要配在 dockerd
的环境中。 而这个环境,则是受 systemd
所管控,因此实际是 systemd
的配置。
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo touch /etc/systemd/system/docker.service.d/proxy.conf
在这个 proxy.conf
文件(可以是任意 *.conf
的形式)中,添加以下内容:
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080/"
Environment="HTTPS_PROXY=http://proxy.example.com:8080/"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"
Container 代理
在容器运行阶段,如果需要代理上网,则需要配置 ~/.docker/config.json
。 以下配置,只在 Docker 17.07 及以上版本生效。
{
"proxies":
{
"default":
{
"httpProxy": "http://proxy.example.com:8080",
"httpsProxy": "http://proxy.example.com:8080",
"noProxy": "localhost,127.0.0.1,.example.com"
}
}
}
这个是用户级的配置,除了 proxies
,docker login
等相关信息也会在其中。 而且还可以配置信息展示的格式、插件参数等。
此外,容器的网络代理,也可以直接在其运行时通过 -e
注入 http_proxy
等环境变量。 这两种方法分别适合不同场景。 config.json
非常方便,默认在所有配置修改后启动的容器生效,适合个人开发环境。 在 CI/CD 的自动构建环境、或者实际上线运行的环境中,这种方法就不太合适,用 -e
注入这种显式配置会更好,减轻对构建、部署环境的依赖。 当然,在这些环境中,最好用良好的设计避免配置代理上网。
docker build
docker build 命令虽然是在 docker 所在的宿主机上执行的,看上去像是直接使用了宿主机的网络环境,但实际上 docker build 也是启动了一个 container 进行构建,所以在构建过程中的所有命令都是在 container 中执行的,http_proxy 和 https_proxy 的配置也应该是在 container 中进行的。
并且,由于 container 默认是桥接 bridge
网络,宿主机和 container 是平级的,被放在了一个虚拟的网段里。访问宿主机上的代理服务器,对于 container 来说实际上是访问另一台机器上的服务器,127.0.0.1 指向的是 container 本身。除非使用 --network host
否则是无法使用的
在 docker 默认的桥接 bridge
网络中,宿主机的 IP 一般是 172.17.0.1(Linux),或者 192.168.65.1(MacOS),可以将 http_proxy 中的 IP 换成 172.17.0.1/192.168.65.1,来实现通过宿主的代理服务器访问网络
1、可以使用 ENV
来配置 container
中的环境变量。
ENV http_proxy "http://172.17.0.1:7890"
ENV https_proxy "http://172.17.0.1:7890"
2、通过 build-arg
, 在构建时,需要注入 http_proxy
等参数。
docker build . \
--build-arg "http_proxy=http://172.17.0.1:7890" \
--build-arg "https_proxy=http://172.17.0.1:7890" \
--build-arg "no_proxy=localhost,127.0.0.1,.example.com" \
-t your/image:tag
确认 docker 默认网卡的配置
通常情况下Linux的Docker默认网卡名为 docker0
,默认IP及其网段信息一般情况下是 172.17.0.1/16
,在运行 build 命令时临时容器将会在这张网卡的网段下,所以需要明确这张网卡的配置信息,以方便后续配置本地 HTTP 代理的地址,以及如果你跟我一样开启了防火墙的情况下开放端口使用。
首先可以运行以下命令查看网卡信息
ip a show docker0
你会得到类似如下的输出
xianyu@book:/home/xianyu $ ip a show docker0
14: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever`
如果你不打算修改默认配置的话就可以看下一节了,但如果你觉得默认网段有问题(不少企业网络会使用 172 的网段作为内网的地址段,会有比较大的概率冲突),那么就可以修改默认的网段。
修改默认网段
修改默认网段的方法非常简单,只需向 /etc/docker/daemon.json
中添加如下配置
{
"bip":"10.233.0.1/24"
}
并重启 docker 即可
`systemctl restart docker`
同样的,重启后通过以下命令验证网段是否修改成功
`xianyu@book:/home/xianyu $ ip a show docker0
14: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 10.233.0.1/24 brd 10.233.0.255 scope global docker0
valid_lft forever preferred_lft forever`
BASH
开放防火墙端口
由于目前 IPv6 的逐渐普及,计算机不开放防火墙会有极大的安全风险,所以在我的本地环境中是启用防火墙的
在上一节中我们提到了默认网卡的网段问题,此时我们可以知道默认网卡的网段为 10.233.0.0/24
本机作为网关在这个网段中的地址为 10.233.0.1
我们希望这个网段中的容器可以访问本机的HTTP代理服务,即我们需要添加一条ufw规则以允许来自 10.233.0.0/24
的请求访问 10.233.0.1:8080
,具体的 ufw 命令如下
ufw allow from 10.233.0.0/24 to 10.233.0.1 port 8080
编辑 Dockerfile
做好上述准备我们就可以开始配置容器的 HTTP 代理了
本次实际案例为编译一个包含自定义插件的 Caddy2 容器,依照官方文档原始的 Dockerfile 长这样:
`FROM caddy:builder AS builder
RUN xcaddy build \
--with github.com/caddy-dns/cloudflare
FROM caddy
COPY --from=builder /usr/bin/caddy /usr/bin/caddy`
DOCKERFILE
可以看到在 RUN
当中我们需要从 Github 拉取我们需要的代码,但实际上由于网络环境问题很难正常拉取到,此时我们可以在这里加入 HTTP 代理的变量使其拉取时走本机的代理
`FROM caddy:builder AS builder
ENV http_proxy=http://10.233.0.1:8080
ENV https_proxy=http://10.233.0.1:8080
RUN xcaddy build \
--with github.com/caddy-dns/cloudflare
FROM caddy
COPY --from=builder /usr/bin/caddy /usr/bin/caddy`
DOCKERFILE
经过上述处理即可愉快的手搓容器了。
重启生效
代理配置完成后,reboot
重启当然可以生效,但不重启也行。
docker build
代理是在执行前设置的,所以修改后,下次执行立即生效。 Container 代理的修改也是立即生效的,但是只针对以后启动的 Container,对已经启动的 Container 无效。
dockerd
代理的修改比较特殊,它实际上是改 systemd
的配置,因此需要重载 systemd
并重启 dockerd
才能生效。
sudo systemctl daemon-reload
sudo systemctl restart docker