Skip to content

使用本机代理在服务器上拉取Docker镜像

现在国内服务器拉取Docker Hub镜像越来越麻烦,直连经常超时,很多公共镜像源也不稳定。更尴尬的是,服务器上通常没有代理环境,为了偶尔拉一个镜像专门在服务器部署代理又有点重。

如果本地电脑已经有可用代理,就可以通过SSH远程端口映射,把本地代理端口临时映射到服务器上。服务器访问自己的127.0.0.1:7890,实际流量会通过SSH转发到本地电脑的代理端口。

前提条件

  • 本地电脑可以正常使用代理,本文以HTTP代理127.0.0.1:7890为例。
  • 本地电脑可以SSH登录服务器。
  • 服务器已经安装Docker。
  • 如果使用方式二,服务器还需要安装skopeo

本文命令默认使用root用户执行,如果使用普通用户,请在服务器命令前加sudo

SSH远程端口映射

这一步在本地电脑执行,不是在服务器执行。

sh
ssh -N -R 127.0.0.1:7890:127.0.0.1:7890 root@服务器IP

这个命令里的-R是远程端口映射,参数顺序可以理解为:

txt
ssh -R 服务器监听地址:服务器端口:本地代理地址:本地代理端口 用户@服务器

对应到上面的命令:

  • 第一个127.0.0.1:7890服务器上的监听地址和端口,也就是服务器里要使用的代理入口。
  • 第二个127.0.0.1:7890本地电脑上的代理地址和端口,也就是本地真实可用的代理。
  • root@服务器IP是SSH登录的服务器账号和地址。
  • -N表示只建立SSH连接和端口映射,不在服务器上执行命令。

默认绑定127.0.0.1,只允许服务器本机访问这个映射端口,不会把代理端口暴露到公网。

如果服务器的7890端口已经被占用,可以把服务器端口换成其他端口,例如:

sh
ssh -N -R 127.0.0.1:17890:127.0.0.1:7890 root@服务器IP

这时后续在服务器里使用的代理地址就改成:

txt
http://127.0.0.1:17890

测试代理是否可用

保持上面的SSH窗口不要关闭,然后在服务器执行:

sh
curl -I -x http://127.0.0.1:7890 https://registry-1.docker.io/v2/

如果返回401 Unauthorized也没问题,说明已经连到了Docker Registry,只是Docker Hub需要鉴权流程。这里主要看是否还会超时或者连接失败。

方式一:配置Docker代理拉取

Docker本身支持给daemon配置代理,配置后直接使用docker pull即可。

写入Docker代理配置

在服务器执行:

sh
mkdir -p /etc/systemd/system/docker.service.d

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,::1"
EOF

如果前面SSH映射使用的是17890,这里也要改成:

ini
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:17890"
Environment="HTTPS_PROXY=http://127.0.0.1:17890"
Environment="NO_PROXY=localhost,127.0.0.1,::1"

重启Docker

sh
systemctl daemon-reload
systemctl restart docker

查看配置是否生效:

sh
systemctl show --property=Environment docker

然后正常拉取镜像:

sh
docker pull docker.io/library/nginx:latest

方式一的问题

这种方式简单直接,但是有几个明显缺点:

  • 需要重启Docker服务,可能影响正在运行的容器。
  • 配置是持久的,下次docker pull仍然会默认走代理。
  • 如果你平时还想使用镜像源或者直连拉取,就需要来回改配置和重启Docker,不太适合只想临时拉一个镜像的场景。

如果要恢复,可以删除这个配置并再次重启Docker:

sh
rm -f /etc/systemd/system/docker.service.d/http-proxy.conf
systemctl daemon-reload
systemctl restart docker

方式二:使用skopeo临时拉取

我更推荐这种方式。skopeo可以把远程仓库里的镜像复制到本机Docker daemon中,而且代理只对当前命令生效,不需要修改Docker配置,也不需要重启Docker。

安装skopeo

Debian / Ubuntu:

sh
apt update && apt install -y skopeo

Rocky Linux / AlmaLinux / Fedora / RHEL 8+:

sh
dnf install -y skopeo

CentOS 7等使用yum的系统:

sh
yum install -y skopeo

如果旧系统的软件源里没有skopeo,可以先启用系统可用的软件源或EPEL,再重新安装:

sh
yum install -y epel-release
yum install -y skopeo

确认安装成功:

sh
skopeo --version

拉取镜像到Docker

在服务器执行:

sh
HTTP_PROXY=http://127.0.0.1:7890 \
HTTPS_PROXY=http://127.0.0.1:7890 \
skopeo copy docker://docker.io/library/nginx:latest docker-daemon:nginx:latest

这条命令的含义:

  • HTTP_PROXYHTTPS_PROXY只对这一次skopeo copy生效。
  • docker://docker.io/library/nginx:latest是远程镜像地址。
  • docker-daemon:nginx:latest表示把镜像写入本机Docker daemon,镜像名为nginx:latest

如果使用普通用户,并且访问Docker需要sudo权限,可以使用:

sh
sudo env HTTP_PROXY=http://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 \
skopeo copy docker://docker.io/library/nginx:latest docker-daemon:nginx:latest

如果SSH映射使用的是17890端口,把代理地址替换为:

sh
HTTP_PROXY=http://127.0.0.1:17890 \
HTTPS_PROXY=http://127.0.0.1:17890 \
skopeo copy docker://docker.io/library/nginx:latest docker-daemon:nginx:latest

拉取完成后查看Docker镜像:

sh
docker images nginx

能看到nginx:latest就说明镜像已经进入Docker本地镜像列表,可以直接docker run或者在docker compose里使用。

两种方式怎么选

  • 只是临时拉取一两个镜像:推荐方式二,使用skopeo copy,不改Docker配置,也不重启服务。
  • 服务器短时间内要大量拉取镜像:可以考虑方式一,配置Docker daemon代理后统一使用docker pull
  • 服务器上已经有重要容器在跑:优先方式二,避免重启Docker带来的影响。

上次更新于: