作者:Chancel Yang, 创建:2024-05-14, 字数:3628, 已阅:904, 最后更新:2024-07-15
在国内的服务器上使用 Docker 会遇到网络失败的问题,例如经典的3个场景都会出现错误:
下文涉及到代理的部分,将假设有一个本地HTTP的网络代理:http://127.0.0.1:1080
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
临时设置系统环境变量:
export HTTP_PROXY=http://127.0.0.1:1080
export HTTPS_PROXY=http://127.0.0.1:1080
然后拉取镜像
sudo -E docker pull hello-world
-E
用于让sudo用户继承当前普通用户的非安全环境变量(HTTP_PROXY和HTTPS_PROXY)
这个代理设置仅对当前会话生效,在退出后将不再生效
如果希望拉取时的代理设置永久生效,可以通过修改 daemon.json
来实现
编辑:/etc/docker/daemon.json
{
"proxies": {
"http-proxy": "http://127.0.0.1:1080",
"https-proxy": "http://127.0.0.1:1080",
"no-proxy": "*.test.example.com,.example.org"
},
"ipv6": false
}
走网络代理的时要注意禁用系统 ipv6
,否则容易出现在 ipv4
环境下访问 ipv6
导致的网络错误
重启docker应用网络代理设置:
sudo systemctl restart docker
除了修改 daemon.json
实现网络代理永久生效外,也可以通过修改docker运行时的环境变量来实现
编辑:/etc/systemd/system/multi-user.target.wants/docker.service
...
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:1080"
Environment="HTTPS_PROXY=http://127.0.0.1:1080"
...
在service节点中添加环境变量,这样每一次拉取都会走网络代理
docker.service的文件位置在不同系统中不同,可以通过
find
来进行查找该文件
重启docker以使环境变量生效
sudo systemctl daemon-reload
sudo systemctl restart docker
无论是修改 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