鉴于目前国内无法下载docker image 的情况,收集了一些方案,并经过试用,整理如下:
镜像法
手工修改配置
特点:简单
国内无法下载docker image,多加几个源,总有能用的。
-
vim /etc/docker/daemon.json
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://hub.uuuadc.top", "https://dockerhub.jobcher.com", "https://dockerhub.icu", "https://dockerproxy.com", "https://docker.io", "https://huecker.io", "https://dockerhub.timeweb.cloud" ], "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "10" } } -
restart
systemctl daemon-reload && systemctl restart docker
用自动化脚本
特点:智能
使用下列脚本,自动挑选最快的镜像并生成配置。
- 脚本如下:
#!/bin/bash
# shellcheck shell=bash
# shellcheck disable=SC2086
PATH=${PATH}:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
Blue="\033[1;34m"
Green="\033[1;32m"
Red="\033[1;31m"
Yellow="\033[1;33m"
NC="\033[0m"
INFO="[${Green}INFO${NC}]"
ERROR="[${Red}ERROR${NC}]"
WARN="[${Yellow}WARN${NC}]"
function INFO() {
echo -e "${INFO} ${1}"
}
function ERROR() {
echo -e "${ERROR} ${1}"
}
function WARN() {
echo -e "${WARN} ${1}"
}
function docker_pull() {
#[ -z "${config_dir}" ] && get_config_path
local config_dir=${2:-"/etc/xiaoya"}
mkdir -p "${config_dir}"
local mirrors=("docker.io" "docker.fxxk.dedyn.io" "docker.m.daocloud.io" "docker.adysec.com" "registry-docker-hub-latest-9vqc.onrender.com" "docker.chenby.cn" "dockerproxy.com" "hub.uuuadc.top" "docker.jsdelivr.fyi" "docker.registry.cyou" "dockerhub.anzu.vip")
if [ -s "${config_dir}/docker_mirrors.txt" ]; then
mirrors=()
while IFS= read -r line; do
mirrors+=("$line")
done < "${config_dir}/docker_mirrors.txt"
else
for mirror in "${mirrors[@]}"; do
printf "%s\n" "$mirror" >> "${config_dir}/docker_mirrors.txt"
done
fi
if command -v timeout > /dev/null 2>&1;then
for mirror in "${mirrors[@]}"; do
INFO "正在测试${mirror}代理点的连接性……"
if timeout 30 docker pull "${mirror}/library/hello-world:latest"; then
INFO "${mirror}代理点连通性测试正常!正在为您下载镜像……"
for i in {1..2}; do
if timeout 300 docker pull "${mirror}/${1}"; then
INFO "${1} 镜像拉取成功!"
sed -i "/${mirror}/d" "${config_dir}/docker_mirrors.txt"
sed -i "1i ${mirror}" "${config_dir}/docker_mirrors.txt"
break;
else
WARN "${1} 镜像拉取失败,正在进行重试..."
fi
done
if [[ "${mirror}" == "docker.io" ]];then
docker rmi "library/hello-world:latest"
[ -n "$(docker images -q "${1}")" ] && return 0
else
docker rmi "${mirror}/library/hello-world:latest"
[ -n "$(docker images -q "${mirror}/${1}")" ] && break
fi
fi
done
else
timeout=20
for mirror in "${mirrors[@]}"; do
INFO "正在测试${mirror}代理点的连接性……"
docker pull "${mirror}/library/hello-world:latest" || true &
pid=$!
count=0
while kill -0 $pid 2>/dev/null; do
sleep 5
count=$((count+5))
if [ $count -ge $timeout ]; then
echo "Command timed out"
kill $pid
break
fi
done
if [ $? -eq 0 ]; then
INFO "${mirror}代理点连通性测试正常!正在为您下载镜像……"
timeout=200
for i in {1..2}; do
docker pull "${mirror}/${1}" || true &
pid=$!
count=0
while kill -0 $pid 2>/dev/null; do
sleep 5
count=$((count+5))
if [ $count -ge $timeout ]; then
echo "Command timed out"
kill $pid
break
fi
done
done
if [[ "${mirror}" == "docker.io" ]];then
docker rmi "library/hello-world:latest"
if [ -n "$(docker images -q "${1}")" ]; then
INFO "${1} 镜像拉取成功!"
sed -i "/${mirror}/d" "${config_dir}/docker_mirrors.txt"
sed -i "1i ${mirror}" "${config_dir}/docker_mirrors.txt"
return 0
else
WARN "${1} 镜像拉取失败,正在进行重试..."
fi
else
docker rmi "${mirror}/library/hello-world:latest"
if [ -n "$(docker images -q "${mirror}/${1}")" ]; then
INFO "${1} 镜像拉取成功!"
sed -i "/${mirror}/d" "${config_dir}/docker_mirrors.txt"
sed -i "1i ${mirror}" "${config_dir}/docker_mirrors.txt"
break
else
WARN "${1} 镜像拉取失败,正在进行重试..."
fi
fi
fi
done
fi
if [ -n "$(docker images -q "${mirror}/${1}")" ]; then
docker tag "${mirror}/${1}" "${1}"
docker rmi "${mirror}/${1}"
return 0
else
ERROR "已尝试所有镜像代理拉取失败,程序退出,请检查网络后再试!"
exit 1
fi
}
if [ -n "$1" ];then
docker_pull $1 $2
else
while :; do
read -erp "请输入您要拉取镜像的完整名字(示例:ailg/alist:latest):" pull_img
[ -n "${pull_img}" ] && break
done
docker_pull "${pull_img}"
fi
代理法
利用现成的代理
特点:能不能用随缘
找个现成的代理,关键在于能不能找到好用的、稳定的代理服务器,然后按照以下步骤修改配置。
mkdir /etc/systemd/system/docker.service.d
vim http-proxy.conf
# 填写如下内容
[Service]
Environment="HTTP_PROXY=http://代理服务器ip:port"
Environment="HTTPS_PROXY=http://代理服务器ip:port" # 实际上,大多数https代理还是用http服务器
systemctl daemon-reload
systemctl restart docker
自建服务器搭建
特点:不差钱
找个海外的服务器,跑个Nginx,自己配置一个域名和证书,就可以搭建一个自己的镜像服务了。
-
docker-compose.yml
services: nginx: image: nginx:latest container_name: nginx network_mode: host volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./certs:/certs:ro - ./html:/var/www/html - /var/log/nginx:/var/log/nginx restart: always # 用acme申请证书 # https://github.com/acmesh-official/acme.sh/wiki/Run-acme.sh-in-docker#3-run-acmesh-as-a-docker-daemon acme: image: neilpang/acme.sh:3.0.7 restart: always container_name: acme.sh command: ["daemon"] volumes: - ./html:/webroot - ./acme.sh:/acme.sh - ./certs:/ssl -
./nginx/conf.d/80.conf
server { listen 80; server_tokens off; access_log /var/log/nginx/access_80.log; error_log /var/log/nginx/error_80.log; location /.well-known/acme-challenge { default_type "text/plain"; root /var/www/html; } } -
./nginx/conf.d/docker.conf
server { listen 443 ssl; server_name hub.razeen.me; http2 on; ssl_certificate /certs/cert.pem; ssl_certificate_key /certs/key.pem; access_log /var/log/nginx/access_hub.log; error_log /var/log/nginx/error_hub.log; ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m; # about 40000 sessions ssl_session_tickets off; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; ssl_prefer_server_ciphers off; # OCSP stapling # ssl_stapling on; # ssl_stapling_verify on; # verify chain of trust of OCSP response using Root CA and Intermediate certs # ssl_trusted_certificate /certs/ca.pem; location / { proxy_pass https://registry-1.docker.io; # Docker Hub 的官方镜像仓库 proxy_set_header Host registry-1.docker.io; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; proxy_set_header Authorization $http_authorization; proxy_pass_header Authorization; # 对 upstream 状态码检查,实现 error_page 错误重定向 proxy_intercept_errors on; # error_page 指令默认只检查了第一次后端返回的状态码,开启后可以跟随多次重定向。 recursive_error_pages on; # 根据状态码执行对应操作,以下为301、302、307状态码都会触发 error_page 301 302 307 = @handle_redirect; } location @handle_redirect { resolver 1.1.1.1; set $saved_redirect_location '$upstream_http_location'; proxy_pass $saved_redirect_location; } }
借助大善人之手
特点:赛博大善人,名不虚传
上一个方法要一个海外的服务器,得花钱。要省钱可以用免费的 Cloudflare Workers 来代理。需要准备一个域名并托管到 Cloudflare。在 Workers 和 Pages > 创建 > 创建 Workers,然后添加以下代码:
- worker.js
import HTML from './docker.html'; export default { async fetch(request) { const url = new URL(request.url); const path = url.pathname; const originalHost = request.headers.get("host"); const registryHost = "registry-1.docker.io"; if (path.startsWith("/v2/")) { const headers = new Headers(request.headers); headers.set("host", registryHost); const registryUrl = `https://${registryHost}${path}`; const registryRequest = new Request(registryUrl, { method: request.method, headers: headers, body: request.body, redirect: "follow", }); const registryResponse = await fetch(registryRequest); console.log(registryResponse.status); const responseHeaders = new Headers(registryResponse.headers); responseHeaders.set("access-control-allow-origin", originalHost); responseHeaders.set("access-control-allow-headers", "Authorization"); return new Response(registryResponse.body, { status: registryResponse.status, statusText: registryResponse.statusText, headers: responseHeaders, }); } else { return new Response(HTML.replace(/{{host}}/g, originalHost), { status: 200, headers: { "content-type": "text/html" } }); } } } - docker.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>镜像使用说明</title> <style> body { font-family: 'Roboto', sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; } .header { background: linear-gradient(135deg, #667eea, #764ba2); color: #fff; padding: 20px 0; text-align: center; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .container { max-width: 800px; margin: 40px auto; padding: 20px; background-color: #fff; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border-radius: 10px; } .content { margin-bottom: 20px; } .footer { text-align: center; padding: 20px 0; background-color: #333; color: #fff; } pre { background-color: #272822; color: #f8f8f2; padding: 15px; border-radius: 5px; overflow-x: auto; } code { font-family: 'Source Code Pro', monospace; } a { color: #4CAF50; text-decoration: none; } a:hover { text-decoration: underline; } @media (max-width: 600px) { .container { margin: 20px; padding: 15px; } .header { padding: 15px 0; } } </style> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&family=Source+Code+Pro:wght@400;700&display=swap" rel="stylesheet"> </head> <body> <div class="header"> <h1>镜像使用说明</h1> </div> <div class="container"> <div class="content"> <p>为了加速镜像拉取,你可以使用以下命令设置 registry mirror:</p> <pre><code>sudo tee /etc/docker/daemon.json <<EOF { "registry-mirrors": ["https://{{host}}"] } EOF</code></pre> <p>为了避免 Worker 用量耗尽,你可以手动 pull 镜像然后 re-tag 之后 push 至本地镜像仓库:</p> <pre><code>docker pull {{host}}/library/alpine:latest # 拉取 library 镜像 docker pull {{host}}/coredns/coredns:latest # 拉取 coredns 镜像</code></pre> </div> </div> <div class="footer"> <p>Powered by Cloudflare Workers</p> </div> </body> </html>

