Skip to content

部署容器镜像源

有的时候,需要频繁使用某个镜像,而为了节约本地空间,经常清理缓存。这就导致需要重复从互联网拉取,不仅慢还会造成带宽浪费。

所幸,有一个workaroud: 部署镜像代理,它将镜像存储到HDD中。一旦命中缓存,就能获得瞬间拉取的体验。

安装镜像仓库

参见 dqzboy/Docker-Proxy

推荐配置proxy.ttl: 0s,可以每次拉取都检查更新。

默认源

为默认源(Docker Hub)设置镜像比较简单,只需编辑配置 /etc/docker/daemon.json.

json
{
	"insecure-registries": [
		"localhost:5001",
	],
	"registry-mirrors": [
		"http://localhost:5001"
	]
}

自用清理脚本

垃圾清理
sh
#!/bin/bash

# ================= 配置区域 =================
# NAS SSH 连接信息
NAS_SSH="nas"

# 公共基础路径 (末尾不要带 /)
NAS_BASE_PATH="/mnt/pool_1/Service/Runtime/container_cache"

# 服务配置列表
#    格式: "Docker容器名:NAS子目录名"
#    例如: "reg-docker-hub:dockerhub" 代表容器是 reg-docker-hub,路径是 .../dockerhub/data
TARGETS=(
    "reg-docker-hub:dockerhub"
    "reg-mcr:mcr"
)

# ===========================================

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd $SCRIPT_DIR && echo cd $SCRIPT_DIR

LOG_FILE="/var/log/registry_wipe.log"
log() {
    local message="$1"
    echo "$(date +"%Y-%m-%d %H:%M:%S") - ${message}" | tee -a "${LOG_FILE}"
}

log "=== 开始 TrueNAS 远程清理任务 ==="
# 遍历配置数组
for item in "${TARGETS[@]}"; do
    # 使用 IFS (Internal Field Separator) 解析 "容器:目录" 字符串
    IFS=':' read -r CONTAINER_NAME SUB_DIR <<<"$item"

    # 自动拼接出完整的 NAS 路径
    # 最终路径 = 基础路径 / 子目录 / data / docker
    FULL_NAS_PATH="${NAS_BASE_PATH}/${SUB_DIR}/data/docker/*"

    log "[处理任务] 容器: $CONTAINER_NAME"
    log "目标路径: $FULL_NAS_PATH"

    # ----------------------------------------------------
    #  停止容器
    # ----------------------------------------------------
    if [ "$(docker ps -q -f name=^/${CONTAINER_NAME}$)" ]; then
        docker stop "$CONTAINER_NAME" 2>&1
    else
        log "容器未运行,跳过停止步骤。"
    fi

    # ----------------------------------------------------
    #  SSH 远程删除
    # ----------------------------------------------------
    log "SSH 远程删除 TrueNAS 路径: $FULL_NAS_PATH"
    ssh -o ConnectTimeout=5 "$NAS_SSH" "rm -rf '$FULL_NAS_PATH'" 2>&1

    if [ $? -eq 0 ]; then
        log "删除成功 (NAS Local execution)。"
    else
        log "错误: SSH 删除失败,请检查路径或权限!"
        docker start "$CONTAINER_NAME"
        continue
    fi

    # ----------------------------------------------------
    #  启动容器
    # ----------------------------------------------------
    docker start "$CONTAINER_NAME" 2>&1

    log "$CONTAINER_NAME 重置完成。"
done

docker compose up -d

log "=== 任务结束 ==="

第三方仓库

Docker 的镜像源功能只对默认源有效。要实现从镜像源拉取,有2种方法:显式指定, 透明代理

shell
docker pull localhost:5000/azure-sdk/azure-mcp

对于不能修改镜像源的地方,只能采取比较hack的方法:透明代理。基本原理

  • 自定义DNS:指定被加速的域名的IP为反代的IP
  • 反向代理:默认端口即可访问
  • 添加信任:以上方法通常不被信任

反向代理

这里提供适用于 1Panel 用户的 OpenResty 的配置示例

假设项目的根目录是 /opt/1panel/www/sites/docker-proxy/.

nginx
server {
    listen 80 ;
    listen 5042 ;
    listen 443 ssl ;
    server_name home-cloud-manual.jfyy.xyz home.cloud.manual.jfyy.xyz hcm.jfyy.xyz 192.168.5.18;
    index index.php index.html index.htm default.php default.htm default.html;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    access_log /www/sites/home-cloud-manual.jfyy.xyz/log/access.log main;
    error_log /www/sites/home-cloud-manual.jfyy.xyz/log/error.log;
    location ^~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html;
    }
    root /www/sites/home-cloud-manual.jfyy.xyz/index;
    error_page 497 https://$host$request_uri;
    ssl_certificate /www/sites/home-cloud-manual.jfyy.xyz/ssl/fullchain.pem;
    ssl_certificate_key /www/sites/home-cloud-manual.jfyy.xyz/ssl/privkey.pem;
    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    proxy_set_header X-Forwarded-Proto https;
    http2 on;
}

/opt/1panel/www/sites/docker-proxy/proxy/proxy_params.conf

conf
# Docker Registry 代理通用参数

# 传递客户端原始请求的Host头给后端
proxy_set_header Host            $host;
proxy_set_header X-Real-IP       $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 告知后端客户端是通过HTTPS连接的
proxy_set_header X-Forwarded-Proto "https";

# 启用 WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# 关闭缓冲,对拉取大镜像至关重要
proxy_buffering off;
proxy_request_buffering off;

# 允许上传任意大小的镜像层
client_max_body_size 0;

# 设置较长的超时时间 (15分钟)
proxy_connect_timeout 900s;
proxy_send_timeout    900s;
proxy_read_timeout    900s;

添加信任

添加信任有2种方法:应用层配置,信任 CA 根证书。

应用层配置

编辑/etc/docker/daemon.json

json
{
	"insecure-registries": [
		"mcr.microsoft.com"
	]
}
shell
systemctl restart docker

信任 CA 根证书

shell
Private_cert_Dir="/etc/TLS/my" # 私有证书目录
CA_PATH="${Private_cert_Dir}/ca"
CERTS_PATH="${Private_cert_Dir}/certs"

# 创建 CA 证书
docker run --rm -it -v ${CA_PATH}:/root/.local/share/mkcert alpine/mkcert mkcert -install
# 创建服务端证书
docker run --rm -it -v ${CA_PATH}:/root/.local/share/mkcert:ro -v ${CERTS_PATH}:/certs -w /certs alpine/mkcert mkcert mcr.microsoft.com registry.k8s.io k8s.gcr.io quay.io ghcr.io gcr.iosudo apt-get install -y mkcert
ln -s /etc/TLS/my/ca $(mkcert -CAROOT)      # 链接CA证书到 mkcert 的默认位置
apt-get update && apt-get install -y mkcert # 安装 mkcert
mkcert -install                             # 使系统信任证书

# 卸载 mkcert(可选)
rm -rf "$(mkcert -CAROOT)"
apt-get remove mkcert

自定义DNS

Debian系的hosts/etc/hosts

bash
127.0.0.1 mcr.microsoft.com