共计 7118 个字符,预计需要花费 18 分钟才能阅读完成。
背景
众所周知,从国内拉取 docker 镜像时常会遇到网络不畅无法拉取的问题。
下文会介绍几种镜像加速的方案。
实践
前提:需要有一台能够正常链接外网访问镜像仓库的服务器。
一、基于 Registry 部署加速服务
Docker Registry 是一个Dodcker 官方发行,用于存储和分发 Docker 镜像的服务。它直接提供了 镜像加速
的功能。
只需要启动一个简单的容器,配合 Nginx 即可实现镜像加速。本文仅以 docker.io 为例,若还需要代理其他仓库域名,流程完全一致。
PS. Docker 强制要求HTTPS
参考链接:
github.com/dqzboy/Docker-Proxy?tab=readme-ov-file
www.rclogs.com/2024/06/docker-registry-build#%E4%B8%89%E3%80%81%…
github.com/brighill/registry-mirror
部署 Registry
# 创建工作目录
mkdir /usr/local/registry && cd /usr/local/registry
# 创建配置文件
# vim docker-compose.yml
version: '3'
services:
## docker hub
dockerhub:
container_name: reg-docker-hub
image: registry:latest
restart: always
environment:
REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
volumes:
- ./data:/var/lib/registry
ports:
- 50001:5000
networks:
- registry-net
networks:
registry-net:
# 启动
docker-compose up -d
Nginx 反向代理
# 增加子配置文件
# vim /etc/nginx/conf/conf.d/***.opshub.cn.conf
upstream reg-docker-hub {
server 8.*.*.*:50001;
}
server {
listen 80;
server_name ***.opshub.cn;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name ***.opshub.cn;
ssl_certificate /root/.acme.sh/*.opshub.cn_ecc/fullchain.cer;
ssl_certificate_key /root/.acme.sh/*.opshub.cn_ecc/*.opshub.cn.key;
ssl_session_timeout 5m;
ssl_protocols TLSV1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_prefer_server_ciphers on;
# 为了防止被滥用,配置仅允许Get请求,即拉取镜像
location / {
limit_except GET {
deny all;
}
proxy_set_header Host $http_host;
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 https;
proxy_redirect http:// https://;
proxy_pass http://reg-docker-hub;
}
}
# 重载nginx
ngint -t
nginx -s reload
客户端拉取镜像
先开启 Docker 的 debug模式:
# vim /etc/docker/daemon.json
{
"debug": true
}
# systemctl restart docker
当客户端不配置代理时,表现如下:connect: connection timed out
查看日志可以看到详细输出:
# journalctl -u docker.service
Jan 14 17:27:20 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:20.513216547+08:00" level=debug msg="Calling HEAD /_ping"
Jan 14 17:27:20 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:20.513908792+08:00" level=debug msg="Calling POST /v1.44/images/create?fromImage=nginx&tag=latest"
Jan 14 17:27:20 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:20.524786710+08:00" level=debug msg="Trying to pull nginx from https://registry-1.docker.io"
Jan 14 17:27:20 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:20.524808476+08:00" level=debug msg="Trying to pull nginx from https://registry-1.docker.io"
Jan 14 17:27:23 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:23.584454048+08:00" level=warning msg="Error getting v2 registry: Get \"https://registry-1.docker.io/v2/\": dial tcp 208.43.170.231:
Jan 14 17:27:23 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:23.584490264+08:00" level=info msg="Attempting next endpoint for pull after error: Get \"https://registry-1.docker.io/v2/\": dial tc
Jan 14 17:27:23 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:23.586497175+08:00" level=error msg="Handler for POST /v1.44/images/create returned error: Get \"https://registry-1.docker.io/v2/\":
Jan 14 17:27:30 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:27:30.006232489+08:00" level=debug msg="Calling GET /v1.41/containers/json?limit=0"
Jan 14 17:28:00 kae-haiwaiyun-testnode dockerd[19181]: time="2025-01-14T17:28:00.005719245+08:00" level=debug msg="Calling GET /v1.41/containers/json?limit=0"
可以通过两种方式实现加速下载:
1、显式指定加速域名
下表是常用的镜像仓库域名
源站 | 替换为 | 平台 |
---|---|---|
docker.io | hub.your_domain_name | docker hub |
gcr.io | gcr.your_domain_name | Google Container Registry |
ghcr.io | ghcr.your_domain_name | GitHub Container Registry |
k8s.gcr.io | k8s-gcr.your_domain_name | Kubernetes Container Registry |
registry.k8s.io | k8s.your_domain_name | Kubernetes’s container image registry |
quay.io | quay.your_domain_name | Quay Container Registry |
mcr.microsoft.com | mcr.your_domain_name | Microsoft Container Registry |
docker.elastic.co | elastic.your_domain_name | Elastic Stack |
nvcr.io | nvcr.your_domain_name | NVIDIA Container Registry |
# docker pull ***.opshub.cn/library/nginx
Using default tag: latest
latest: Pulling from library/nginx
af302e5c37e9: Pull complete
207b812743af: Pull complete
841e383b441e: Pull complete
0256c04a8d84: Pull complete
38e992d287c5: Pull complete
9e9aab598f58: Pull complete
4de87b37f4ad: Pull complete
Digest: sha256:0e65e7b19ac0abab5c911b175ca20040c98200337337cbb366af24ab597927ea
Status: Downloaded newer image for ***.opshub.cn/library/nginx:latest
***.opshub.cn/library/nginx:latest
执行 journalctl -u docker.service | grep pull
,可以看到此时直接由代理域名执行了镜像数据下载。
2、修改 docker 配置启用加速域名
daemon.json
支持配置仓库域名。域名可以使用列表方式写入多个,docker 会尝试由上至下遍历仓库,直到能够查询到镜像为止。
# 修改配置
# vim /etc/docker/daemon.json
{
"registry-mirrors": [
"https://***.opshub.cn"
],
"debug": true
}
# 重启 docker
systemctl restart docker
# 校验配置是否生效
# docker info|grep -A 1 Registry
Registry Mirrors:
https://***.opshub.cn/
当配置生效后,无需显式指定镜像域名,可以直接 pull 镜像。
# 先删除已经下载完毕的nginx镜像
docker rmi 9bea9f2796e2
# 下载镜像
# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
af302e5c37e9: Pull complete
207b812743af: Pull complete
841e383b441e: Pull complete
0256c04a8d84: Pull complete
38e992d287c5: Pull complete
9e9aab598f58: Pull complete
4de87b37f4ad: Pull complete
Digest: sha256:0e65e7b19ac0abab5c911b175ca20040c98200337337cbb366af24ab597927ea
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
从输出可以看到,以后一行中域名仍然是 docker.io,而不是代理域名。
执行 journalctl -u docker.service |grep "Fetching manifest from remote"
查看日志:可以看到从 docker.io 获取了清单
执行 journalctl -u docker.service | grep pull
查看日志:可以看到从 代理域名 下载了镜像
原因如下:
- 镜像源的作用
registry-mirrors
配置的作用是加速从docker.io
拉取镜像,而不是完全替换docker.io
。因此:- Docker 仍然会与
docker.io
通信,获取镜像的元数据。 - 实际的镜像层数据(blobs)会通过配置的镜像源(如
***.opshub.cn
)下载。
- Docker 仍然会与
- 日志中的关键信息
-
Trying to pull nginx from https://***.opshub.cn/`:Docker 尝试通过
***.opshub.cn` 拉取镜像。 -
Pulling ref from V2 registry: nginx:latest
:Docker 从docker.io
获取镜像的元数据。 -
pulling blob "sha256:..."
:Docker 通过***.opshub.cn
下载实际的镜像层数据。
-
- 为什么仍然显示
docker.io
即使配置了镜像源,Docker 仍然会显示从docker.io
拉取镜像,因为:- 镜像的元数据(如 manifest 和 layer 信息)仍然从
docker.io
获取。 - 镜像层数据(blobs)通过镜像源下载,但 Docker 的输出默认显示的是元数据的来源。
- 镜像的元数据(如 manifest 和 layer 信息)仍然从
二、使用 socks & http 代理
可参考文章:使用 socks5 代理网络流量 进行代理配置。
在客户端中,修改 docker 配置文件:
# vim /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=socks5://192.168.2.10:2080"
Environment="HTTPS_PROXY=socks5://192.168.2.10:2080"
# 重启服务
systemctl daemon-reload
systemctl restart docker
使用这种方式,会将 docker 所有流量均转发到代理服务器。影响面大。
如果 docker 是作为 kubernetes 的运行时,不建议这样做,会引发集群网络异常。
好处是客户端在pull镜像时,无需进行任何域名配置。
总结
文中的3种方式各有优劣,自行根据场景选择方案。
AI总结如下:
问题:
分析三种docker镜像代理方式的优劣:
1、通过部署 Registry 服务端,在客户端显式指定镜像加速域名
2、通过部署 Registry 服务端,在客户端的 /etc/docker/daemon.json 下配置代理域名
3、通过部署 socks代理,在客户端的 /etc/systemd/system/docker.service.d/http-proxy.conf 配置socks代理
回答:
我来详细分析这三种docker镜像代理方式的优缺点:
1. 通过显式指定镜像加速域名
优点:
- 配置简单,只需在pull/push时指定域名
- 灵活性高,可以针对不同镜像源使用不同的加速域名
- 不影响其他Docker操作
- 便于临时使用或测试
缺点:
- 需要每次手动指定域名,使用不便
- 容易遗漏,特别是在自动化脚本中
- 团队协作时需要所有人都记住并使用正确的域名
2. 通过daemon.json配置代理域名
优点:
- 配置一次即可全局生效
- 对用户透明,无需改变使用习惯
- 便于统一管理和维护
- 适合团队使用
- 自动化友好
缺点:
- 需要重启docker服务才能生效
- 配置相对复杂,需要注意json格式
- 可能影响所有的镜像拉取操作
- 故障排查相对困难
3. 通过socks代理配置
优点:
- 支持更广泛的网络代理场景
- 可以同时作用于其他网络服务
- 对网络层面有更细粒度的控制
- 可以处理更复杂的网络环境
缺点:
- 配置最为复杂
- 需要额外维护代理服务器
- 可能影响系统整体网络性能
- 安全风险较大,需要额外的安全措施
- 故障排查最困难
使用建议:
1. 对于个人开发环境:
- 建议使用方式1或2,简单直接
2. 对于企业生产环境:
- 如果主要解决镜像加速问题,推荐使用方式2
- 如果有复杂的网络需求,考虑使用方式3
3. 对于临时使用:
- 推荐使用方式1,无需修改系统配置
4. 对于大规模部署:
- 建议使用方式2,便于统一管理和自动化部署
最佳实践:
1. 优先考虑使用daemon.json配置(方式2),这是最标准的做法
2. 如果遇到特殊情况需要使用其他镜像源,可以临时使用方式1
3. 只有在确实需要处理复杂网络环境时,才考虑使用方式3
需要注意的是,无论选择哪种方式,都应该:
- 做好配置文档
- 进行充分测试
- 建立监控机制
- 准备回退方案
- 定期检查和更新配置