作者:E4b9a6, 创建:2024-05-14, 字数:4976, 已阅:1009, 最后更新:2024-07-15
在国内的服务器上使用 Docker 会遇到网络失败的问题,例如经典的3个场景都会出现错误:
下面讲针对以上三个场景涉及到代理的部分进行设置
首先假设有一个不受限制的本地HTTP网络代理:http://127.0.0.1:8080
由于不同的 Docker 版本针对代理的策略不一样,如下面的方法无效,请自行检查版本差异
我的Docker版本信息如下:
$ sudo docker version
Client: Docker Engine - Community
Version: 27.0.3
API version: 1.46
Go version: go1.21.11
Git commit: 7d4bcd8
Built: Sat Jun 29 00:02:50 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 27.0.3
API version: 1.46 (minimum version 1.24)
Go version: go1.21.11
Git commit: 662f78c
Built: Sat Jun 29 00:02:50 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.18
GitCommit: ae71819c4f5e67bb4d5ae76a6b735f29cc25774e
runc:
Version: 1.7.18
GitCommit: v1.1.13-0-g58aa920
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Docker在拉取镜像时,还是借助宿主机的网络,所以设置源和设置环境变量中的网络代理变量均是有效的
在2024年6月后,国内不少Docker源都失效了,如果能找到可用的国内源,更换源这个方法还是很好用的
更换源,编辑:/etc/docker/daemon.json
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
重启docker应用新的源
sudo systemctl restart docker
如果拉取不成功,可以借助 journalctl
查看错误
journalctl -xue docker.service
临时设置系统环境变量 HTTP_PROXY
和 HTTPS_PROXY
对于Docker同样是有效的
例如设置如下:
export HTTP_PROXY=http://127.0.0.1:8080
export HTTPS_PROXY=http://127.0.0.1:8080
使用 curl
验证是否获得了网络代理:
curl cip.cc
然后拉取镜像
sudo -E docker pull hello-world
-E
用于让sudo用户继承当前普通用户的非安全环境变量(HTTP_PROXY和HTTPS_PROXY)
这个代理设置仅对当前会话生效,在退出后将不再生效
另外 sudo
由于安全问题并不一定会全部继承环境变量,使用 -E
并不是一定会继承 HTTP_PROXY
和 HTTPS_PROXY
请确保 /etc/sudoers
有如下配置:
Defaults env_keep += "HTTP_PROXY HTTPS_PROXY"
如果希望拉取时的代理设置永久生效,可以通过修改 daemon.json
来实现
编辑:/etc/docker/daemon.json
{
"proxies": {
"http-proxy": "http://127.0.0.1:8080",
"https-proxy": "http://127.0.0.1:8080",
"no-proxy": "*.test.example.com,.example.org"
},
"ipv6": false
}
走网络代理的时要注意禁用系统 ipv6
,否则容易出现在 ipv4
环境下访问 ipv6
导致的网络错误
重启docker应用网络代理设置:
sudo systemctl restart docker
但请注意,这个方法也同样影响容器内的网络,容器内的 http 请求也会走网络代理
除了修改 daemon.json
实现网络代理永久生效外,也可以通过修改docker运行时的环境变量来实现
编辑:/etc/systemd/system/multi-user.target.wants/docker.service
...
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:8080"
Environment="HTTPS_PROXY=http://127.0.0.1:8080"
...
在service节点中添加环境变量,这样每一次拉取都会走网络代理
docker.service的文件位置在不同系统中不同,可以通过
find
来进行查找该文件
重启docker以使环境变量生效
sudo systemctl daemon-reload
sudo systemctl restart docker
但请注意,这个方法也同样影响容器内的网络,容器内的 http 请求也会走网络代理
无论是修改 daemon.json
还是修改 docker.service
,其本质是影响了Docker的Daemon进程环境变量
而与拉取不同,在构建时,每个Dockerfile的RUN指令都在一个全新的容器中执行,这些容器不会继承Docker Daemon进程的环境变量
如果在构建步骤中,有一些指令如 curl/wget
需要使用代理,则需要修改编辑Dockerfile文件,添加 http_proxy
和 https_proxy
变量:
...
ARG http_proxy
ARG https_proxy
ENV http_proxy=${http_proxy}
ENV https_proxy=${https_proxy}
...
这里采用在构建时传入 http_proxy
和 https_proxy
变量会更加灵活
如刚才所说,构建阶段是完全网络隔离的,所以 127.0.0.1
是无法指向宿主机的,需要填入真实的宿主机IP
先使用 ip -a
获取到宿主机的真实IP,如:
$ ip -a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether c8:7f:54:a9:98:d1 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.2/24 brd 192.168.15.255 scope global enp4s0
valid_lft forever preferred_lft forever
...
106 docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:34:65:16:f5 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
192.168.1.2
和 172.17.0.1
两个地址都可以被容器访问到,那么构建参考如下:
sudo docker build \
--build-arg http_proxy=http://192.168.1.2:1080 \
--build-arg https_proxy=http://192.168.1.2:1080 \
-t your-image .
Docker在运行时,容器要使用网络代理,则需要设置容器的全局网络代理变量,类似于在Linux Shell中设置http_proxy
和 http_proxy
容器在运行时,通过-e
参数设置环境变量:
sudo docker run \
-e http_proxy=http://192.168.1.2:1080 \
-e https_proxy=http://192.168.1.2:1080 \
your-image
与前文一致,容器内的环境是独立的,所以要将代理指向宿主机而不是 127.0.0.1
如果容器内存在环境变量 http_proxy
和 /etc/docker/daemon.json
中存在网络环境变量 prixies
容器将优先容器内的环境变量 http_proxy