自建 Docker 镜像加速服务:加速与优化镜像管理

本文转自:浅时光博客

场景描述

在部署 Kubernetes 集群时,面临的一个主要问题是镜像下载。许多镜像存储在 k8s.gcr.io 仓库中,然而由于国内的网络防火墙(GFW)的影响,无法直接访问该网站。尽管一些镜像可以通过阿里云的 k8s.gcr.io 同步解决国内无法下载 GCR 镜像的问题,但是仍有一些镜像无法在阿里云镜像仓库中找到。在这种情况下,我们需要采取一些措施来自行解决这个问题。

自2024年06月07日起,国内已要求所有提供镜像站和镜像加速服务的机构停止其服务。

自动化脚本

  • ✨️ 一键部署 Docker 镜像代理服务的功能,支持基于官方 Docker Registry 的镜像代理
  • ✨️ 支持多个镜像仓库的代理,包括 Docker Hub、GitHub Container Registry ( ghcr.io )、Quay Container Registry ( quay.io ) 和 Kubernetes Container Registry ( k8s.gcr.io )
  • ✨️ 自动检查并安装所需的依赖软件,如 Docker、Nginx 等,并确保系统环境满足运行要求
  • ✨️ 自动清理注册表上传目录中的那些不再被任何镜像或清单引用的文件
  • ✨️ 提供了重启服务、更新服务、更新配置和卸载服务的功能,方便用户进行日常管理和维护
  • ✨️ 支持主流 Linux 发行版操作系统,例如 Centos、Ubuntu、Rocky、Debian、Rhel 等
  • ✨️ 支持主流 ARCH 架构下部署,包括 Linux/amd64、Linux/arm64

项目地址:https://github.com/dqzboy/Docker-Proxy

操作流程

  • 购买一台国外的云服务器并且没有被墙,用来搭建 Docker 镜像仓库代理服务
  • 准备一个域名,然后到腾讯云或者阿里云上申请一个免费的证书;如果有多个代理的地址则要配置多个二级域名,然后购买一个通配符证书(说明:如果你使用cloudflare 进行 DNS 解析,开启 CF 代理就不需要单独购买证书了,CF 会免费提供 HTTPS 服务)
  • 安装 Nginx,配置域名和证书,然后反代我们的 Registry 容器服务
  • 安装部署 Docker 和 docker-compose

部署过程中出现的问题或者疑问,请点击这里 问题总结,查看是否有你遇到的情况!尝试先自己解决。

基础环境安装

添加 YUM 源

yum update
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装 Docker

#可以查看所有仓库中所有docker版本,并选择特定版本安装
yum list docker-ce --showduplicates | sort -r
yum install -y docker-ce

启动 Docker

systemctl enable docker && systemctl start docker

部署镜像仓库代理

创建账号密码 (可选)

注意:
1、配置账号密码:设置密码认证后,我们在进行拉取镜像时就需要先 docker login 登入到我们的自建的代理镜像仓库,然后才可以拉取镜像。

2、执行 htpasswd 命令时,请把 username 和 password 修改为你自己的账号和密码。

mkdir -p /data/registry-proxy &&  cd $_
htpasswd -Bbn username password >  ./htpasswd

添加 docker-compose.yml 文件

如果你要开启 Proxy 认证的话请把 #- ./htpasswd:/auth/htpasswd 注释取消掉

mkdir -p /data/registry-proxy &&  cd $_
vi docker-compose.yaml
services:
  ## docker hub
  dockerhub:
    container_name: reg-docker-hub
    image: dqzboy/registry:latest
    restart: always
    environment:
      - OTEL_TRACES_EXPORTER=none
      # 如果需要配置代理,请把下面的注释去掉,并配置你的代理地址
      #- http_proxy=http://host:port
      #- https_proxy=http://host:port
    volumes:
      - ./registry/data:/var/lib/registry
      - ./docker-hub.yml:/etc/distribution/config.yml
      #- ./htpasswd:/auth/htpasswd
    ports:
      - 51000:5000
    networks:
      - registry-net
  ## UI
  registry-ui:
    container_name: registry-ui
    image: dqzboy/docker-registry-ui:latest
    environment:
      # UI所关联的REGISTRY容器服务地址
      - DOCKER_REGISTRY_URL=http://reg-docker-hub:5000
      # [必须]使用 openssl rand -hex 16 生成唯一值
      - SECRET_KEY_BASE=9f18244a1e1179fa5aa4a06a335d01b2
      # 启用Image TAG 的删除按钮
      - ENABLE_DELETE_IMAGES=true
      - NO_SSL_VERIFICATION=true
    restart: always
    ports:
      - 50000:8080
    networks:
      - registry-net
 
networks:
  registry-net:

添加 config.yml 文件

注意:
每个容器挂载对应的 config.yml,这里名称需要与上面 docker-compose.yml 文件定义的挂载的名称保持一致(例如上面挂载的配配置文件名称为 docker-hub.yml );下面只是其中一个示例配置,其他的配置也一样,只需要更改 remoteurl 代理的地址即可!
如果你上面开启了密码认证,那么下面配置中 auth 块的内容需要把注释取消掉!!!

vim docker-hub.yml
version: 0.1
log:
  fields:
    service: registry
storage:
  filesystem:
    rootdirectory: /var/lib/registry
  delete:
    enabled: true
  cache:
    blobdescriptor: inmemory   
    blobdescriptorsize: 10000
  maintenance:
    uploadpurging:
      enabled: true
      age: 168h
      interval: 24h
      dryrun: false
    readonly:
      enabled: false
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
    Access-Control-Allow-Origin: ['*']
    Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
    Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control']
    Access-Control-Max-Age: [1728000]
    Access-Control-Allow-Credentials: [true]
    Access-Control-Expose-Headers: ['Docker-Content-Digest']
 
#auth:
#  htpasswd:
#    realm: basic-realm
#    path: /auth/htpasswd
 
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3
 
proxy:
  remoteurl: https://registry-1.docker.io
  username: 
  password:
  ttl: 168h

启动容器服务

docker compose up -d
 
# 检查启动容器状态
docker ps

配置 Nginx 反代

cd /etc/nginx/conf.d/
vim registry-proxy.conf
## registry-ui
server {
    listen       80;
    listen       443 ssl;
    ## 填写绑定证书的域名
    server_name  ui.your_domain_name;
    ## 证书文件名称(填写你证书存放的路径和名称)
    ssl_certificate your_domain_name.crt;
    ## 私钥文件名称(填写你证书存放的路径和名称)
    ssl_certificate_key your_domain_name.key;
    ssl_session_timeout 1d;
    ssl_session_cache   shared:SSL:50m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_buffer_size 8k;
 
    proxy_connect_timeout 600;
    proxy_send_timeout    600;
    proxy_read_timeout    600;
    send_timeout          600;
 
    location / {
        proxy_pass   http://localhost:50000;
        proxy_set_header  Host $host;
        proxy_set_header  Origin $scheme://$host;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Proto $scheme;
        proxy_set_header  X-Forwarded-Ssl on; # Optional
        proxy_set_header  X-Forwarded-Port $server_port;
        proxy_set_header  X-Forwarded-Host $host;
    }
}
## docker hub
server {
    listen       80;
    listen       443 ssl;
    ## 填写绑定证书的域名
    server_name  hub.your_domain_name;
    ## 证书文件名称(填写你证书存放的路径和名称)
    ssl_certificate your_domain_name.crt;
    ## 私钥文件名称(填写你证书存放的路径和名称)
    ssl_certificate_key your_domain_name.key;
    ssl_session_timeout 1d;
    ssl_session_cache   shared:SSL:50m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_buffer_size 8k;
 
    proxy_connect_timeout 600;
    proxy_send_timeout    600;
    proxy_read_timeout    600;
    send_timeout          600;
 
    location / {
        proxy_pass   http://localhost:51000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        
        proxy_set_header X-Nginx-Proxy true;
        proxy_buffering off;
        proxy_redirect off;
    }
}
# 重载Nginx配置
nginx -t
nginx -s reload

解析域名

  • 将我们在 Nginx 配置的域名,在 DNS 服务商商进行解析,解析到部署镜像代理仓库的服务器上;
  • 通过访问 UI 地址可以查看镜像仓库缓存的镜像;
  • 通过使用对应的代理域名来下载我们之前无法下载的镜像。

使用镜像仓库代理

使用自建的 Registry 地址替换官方的 Registry 地址拉取镜像

## 源:nginx:latest
## 替换
docker pull hub.your_domain_name/library/nginx:latest

访问 UI 页面就可以看到上面我们下载的镜像已经被缓存了

docker-proxy001

修改 Docker 配置

在 Docker 的 daemon.json 配置文件中添加上 docker.io 的代理域名,然后重启 Docker 程序

vim /etc/docker/daemon.json
{
    "registry-mirrors": ["https://hub.your_domain_name"],
    "log-opts": {
      "max-size": "100m",
      "max-file": "5"
    }
}
#重启docker
systemctl restart docker

使用威联通 NAS 的请注意:

1、威联通的 docker 配置文件不叫 daemon.json 而是叫 docker.json
位置在 /share/CACHEDEV1_DATA/.qpkg/container-station/etc/docker.json

2、修改完毕后重启 docker 命令不是 systemctl restart docker 而是使用:/etc/init.d/container-station.sh 来重启 docker

kubeadm 配置镜像代理

如果你用 kubeadm 部署 Kubernetes 集群,可以在 kubeadm 配置文件中设置镜像地址为你的搭建的代理仓库的域名地址…

cat kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: v1.25.1
......
imageRepository: gcr.your_domain_name/google-containers
打赏