AI编程生活评测

Docker使用本地代理为服务器拉取镜像,附一键配置脚本

编程笔记 / 2026-04-24 / 6 min

背景

在国内服务器上拉取 Docker 镜像,常见方案是配置国内镜像加速源,但镜像源经常同步不及时、限速、甚至关停。

最靠谱的方式其实是——通过代理直连 Docker Hub 官方源。本文提供一个一键切换脚本,覆盖两种典型场景:

  • 本地 Docker:开发机上装了 Docker 和代理,直接让 Docker 走本地代理
  • 远程服务器 Docker:服务器上装了 Docker 但没有代理,通过 SSH 隧道将本地开发机的代理转发到服务器上使用

原理

Docker 拉取镜像的网络请求由 dockerd 进程发出,而非 docker CLI,因此不能简单设置 shell 环境变量。正确的做法是通过 systemd 的 drop-in 文件为 Docker 服务注入 HTTP_PROXY / HTTPS_PROXY 环境变量。

开启代理需要同时做两件事:

  1. 清空 daemon.json 中的镜像源配置 —— 如果保留了 registry-mirrors,Docker 会优先走镜像源,代理配了也不生效
  2. 创建 systemd drop-in 配置 —— 在 /etc/systemd/system/docker.service.d/http-proxy.conf 中注入代理地址

关闭代理则是反向操作:还原 daemon.json、删除 drop-in 文件、重启服务。

切换脚本

将开启和关闭合并为一个脚本 docker_proxy.sh,通过参数控制:

sudo ./docker_proxy.sh on      # 开启代理
sudo ./docker_proxy.sh off     # 关闭代理
sudo ./docker_proxy.sh status  # 查看状态

安全机制

脚本针对误操作和边界情况做了防护:

场景 处理方式
错误参数或无参数 打印用法提示,不做任何操作
重复执行 on 提示代理已开启,询问是否强制重新配置;不会覆盖原始备份
重复执行 off 提示代理已关闭,直接退出
未执行过 on 就执行 off 检测到备份文件不存在,报错退出,避免配置损坏
所有写操作前 需输入 y 确认(因为会重启 Docker)

完整脚本

#!/bin/bash
# Docker 代理切换脚本
# 用法: sudo ./docker_proxy.sh on|off|status

PROXY_CONF="/etc/systemd/system/docker.service.d/http-proxy.conf"
DAEMON_JSON="/etc/docker/daemon.json"
DAEMON_BAK="/etc/docker/daemon.json.bak"
PROXY_ADDR="http://127.0.0.1:10808"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

usage() {
    echo "用法: sudo $0 {on|off|status}"
    echo "  on     开启代理,直连 Docker Hub 官方源"
    echo "  off    关闭代理,恢复镜像源配置"
    echo "  status 查看当前代理状态"
    exit 1
}

is_proxy_on() {
    [ -f "$PROXY_CONF" ]
}

confirm() {
    echo -e "${YELLOW}$1${NC}"
    read -r -p "确认执行?[y/N] " response
    [[ "$response" =~ ^[yY]$ ]]
}

proxy_on() {
    if is_proxy_on; then
        echo -e "${YELLOW}代理已处于开启状态。${NC}"
        if ! confirm "是否强制重新配置?Docker 服务将重启。"; then
            echo "已取消。"
            exit 0
        fi
    else
        if ! confirm "即将清空镜像源配置并开启代理,Docker 服务将重启。"; then
            echo "已取消。"
            exit 0
        fi
    fi

    # 仅在备份不存在时才备份,防止重复 on 覆盖原始配置
    if [ ! -f "$DAEMON_BAK" ]; then
        cp "$DAEMON_JSON" "$DAEMON_BAK"
        echo -e "${GREEN}已备份 daemon.json → daemon.json.bak${NC}"
    else
        echo "备份文件已存在,跳过备份。"
    fi

    # 清空镜像源,走官方
    tee "$DAEMON_JSON" > /dev/null << 'EOF'
{}
EOF

    # 添加代理配置
    mkdir -p /etc/systemd/system/docker.service.d
    tee "$PROXY_CONF" > /dev/null << EOF
[Service]
Environment="HTTP_PROXY=$PROXY_ADDR"
Environment="HTTPS_PROXY=$PROXY_ADDR"
Environment="NO_PROXY=localhost,127.0.0.1"
EOF

    systemctl daemon-reload
    systemctl restart docker
    echo -e "${GREEN}Docker 已切换为代理直连官方源。${NC}"
}

proxy_off() {
    if ! is_proxy_on; then
        echo -e "${YELLOW}代理已处于关闭状态,无需操作。${NC}"
        exit 0
    fi

    if [ ! -f "$DAEMON_BAK" ]; then
        echo -e "${RED}错误:备份文件 $DAEMON_BAK 不存在,无法还原。${NC}"
        echo "请手动检查 $DAEMON_JSON 的配置。"
        exit 1
    fi

    if ! confirm "即将关闭代理并恢复镜像源配置,Docker 服务将重启。"; then
        echo "已取消。"
        exit 0
    fi

    cp "$DAEMON_BAK" "$DAEMON_JSON"
    rm -f "$DAEMON_BAK"
    echo -e "${GREEN}已还原 daemon.json${NC}"

    rm -f "$PROXY_CONF"
    echo "已删除代理配置。"

    systemctl daemon-reload
    systemctl restart docker
    echo -e "${GREEN}Docker 已还原为镜像源模式。${NC}"
}

proxy_status() {
    if is_proxy_on; then
        echo -e "${GREEN}当前状态:代理已开启${NC}"
        echo "代理地址:$PROXY_ADDR"
    else
        echo -e "${YELLOW}当前状态:代理未开启(镜像源模式)${NC}"
    fi
}

# 检查 root 权限
if [ "$EUID" -ne 0 ]; then
    echo -e "${RED}请使用 sudo 运行此脚本。${NC}"
    exit 1
fi

case "${1:-}" in
    on)     proxy_on ;;
    off)    proxy_off ;;
    status) proxy_status ;;
    *)      usage ;;
esac

注意:请根据实际代理端口修改脚本顶部的 PROXY_ADDR 变量,默认为 http://127.0.0.1:10808

场景一:本地 Docker 使用本地代理

适用于本地开发机上同时运行了 Docker 和可正常连接 Dokcer Hub 的代理,代理监听在 127.0.0.1:10808,直接配置 Docker 走代理即可。

操作步骤

# 1. 赋予执行权限(仅首次)
chmod +x docker_proxy.sh

# 2. 开启代理
sudo ./docker_proxy.sh on

# 3. 拉取镜像
docker pull vllm/vllm-openai:v0.19.1

# 4. 拉完后关闭代理,恢复镜像源
sudo ./docker_proxy.sh off

随时可以用 status 查看当前状态:

sudo ./docker_proxy.sh status

场景二:远程服务器 Docker 通过 SSH 隧道使用本地代理

适用于远程服务器上运行了 Docker 但没有代理客户端。核心思路是通过 SSH 远程端口转发,将本地开发机的代理”映射”到服务器上,让服务器上的 Docker 也能走代理。

前提条件

本地开发机上有一个 HTTP 代理,监听在 127.0.0.1:10808,且可以通过 SSH 登录远程服务器。

操作步骤

第一步:从本地开发机发起 SSH 连接,带上 -R 参数建立隧道:

# 在本地电脑上执行
ssh -R 10808:127.0.0.1:10808 user@your-server

这条命令会让远程服务器上的 127.0.0.1:10808 转发到本地开发机的 127.0.0.1:10808。连接建立后,服务器访问该地址的流量会通过 SSH 隧道回到本地代理。

SSH -R 转发默认绑定到 127.0.0.1,不需要修改服务器的 sshd 配置。

第二步:保持上面的 SSH 隧道会话不要断开。另外打开一个终端,用普通方式 SSH 登录到远程服务器:

# 在本地另开一个终端
ssh user@your-server

第三步:将脚本上传到服务器并赋予执行权限(仅首次):

# 方式一:从本地用 scp 上传(在本地再开一个终端执行)
scp docker_proxy.sh user@your-server:~/

# 方式二:如果已经在服务器上了,直接创建脚本文件,粘贴上面的脚本内容
vim docker_proxy.sh
# 在服务器上赋予执行权限
chmod +x docker_proxy.sh

第四步:在服务器上执行脚本拉取镜像:

sudo ./docker_proxy.sh on
docker pull vllm/vllm-openai:v0.19.1
sudo ./docker_proxy.sh off

第五步:镜像拉完后,关闭第一步中带 -R 参数的 SSH 隧道会话即可,隧道自动断开。

提示:如果本地开发机代理监听的端口不是 10808,需要同时修改 SSH 命令中的端口号和脚本顶部的 PROXY_ADDR 变量,保持一致。

注意事项

  • 脚本会执行 systemctl restart docker所有正在运行的容器会短暂重启(设置了 restart: alwaysunless-stopped 的容器会自动恢复)。建议在业务低峰期操作。
  • 脚本通过检测 /etc/systemd/system/docker.service.d/http-proxy.conf 是否存在来判断代理状态。避免手动增删该文件,以免状态判断不准确。
点击刷新