自建 Docker 镜像加速服务

温馨提醒

一、准备工具

  • 环境准备

    1
    2
    3
    4
    5
    6
    7
    
    安装 Docker 和 docker-compose;
    
    购买一台国外的云服务器,用来部署 Docker 仓库代理服务;
    
    准备一个域名,申请一个免费的 SSL 证书;
    
    安装 Nginx,反向代理到 Docker 仓库代理服务上
  • 创建密码

    1
    2
    3
    
    mkdir /data/registry-proxy/auth -p
    cd /data/registry-proxy
    docker run --entrypoint htpasswd httpd:2 -Bbn 用户名 密码 > auth/htpasswd

二、创建 docker-compose 文件

vim /data/registry-proxy/docker-compose.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
version: "3"
services:
  # registry-UI
  registry-ui:
    container_name: registry-ui
    image: dqzboy/docker-registry-ui:latest
    environment:
      - DOCKER_REGISTRY_URL=http://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
      
  # docker hub
  dockerhub:
    container_name: docker-hub
    image: registry:2
    restart: always
    volumes:
      - ./registry/data:/var/lib/registry
      - ./registry-hub.yml:/etc/docker/registry/config.yml
      - ./auth/htpasswd:/auth/htpasswd		# 可选配置
    ports:
      - 51000:5000
    networks:
      - registry-net

  # gcr.io
  gcr:
    container_name: gcr
    image: registry:2
    restart: always
    environment:
      - OTEL_TRACES_EXPORTER=none
    volumes:
      - ./registry/data:/var/lib/registry
      - ./registry-gcr.yml:/etc/docker/registry/config.yml
      - ./auth/htpasswd:/auth/htpasswd
    ports:
      - 53000:5000
    networks:
      - registry-net
      
  # k8s.gcr.io
  k8sgcr:
    container_name: k8s-gcr
    image: registry:2
    restart: always
    environment:
      - OTEL_TRACES_EXPORTER=none
    volumes:
      - ./registry/data:/var/lib/registry
      - ./registry-k8sgcr.yml:/etc/docker/registry/config.yml
      - ./auth/htpasswd:/auth/htpasswd
    ports:
      - 54000:5000
    networks:
      - registry-net
      
  # registry.k8s.io
  k8s:
    container_name: k8s
    image: registry:2
    restart: always
    environment:
      - OTEL_TRACES_EXPORTER=none
    volumes:
      - ./registry/data:/var/lib/registry
      - ./registry-k8s.yml:/etc/docker/registry/config.yml
      - ./auth/htpasswd:/auth/htpasswd
    ports:
      - 55000:5000
    networks:
      - registry-net
      
  # quay.io
  quay:
    container_name: quay
    image: registry:2
    restart: always
    environment:
      - OTEL_TRACES_EXPORTER=none
    volumes:
      - ./registry/data:/var/lib/registry
      - ./registry-quay.yml:/etc/docker/registry/config.yml
      - ./auth/htpasswd:/auth/htpasswd
    ports:
      - 56000:5000
    networks:
      - registry-net

networks:
  registry-net:

三、创建其他 yaml 文件

  • 创建 dockerhub 配置文件

    vim /data/registry-proxy/registry-hub.yml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    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']
    
    health:
      storagedriver:
        enabled: true
        interval: 10s
        threshold: 3
    
    proxy:
      remoteurl: https://registry-1.docker.io
      username:
      password:
      ttl:
  • 创建 gcr 配置文件

    vim /data/registry-proxy/registry-gcr.yml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    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']
    
    health:
      storagedriver:
        enabled: true
        interval: 10s
        threshold: 3
    
    proxy:
      remoteurl: https://gcr.io
      username:
      password:
      ttl: 168h
  • 创建 k8sgcr 配置文件

    vim /data/registry-proxy/registry-k8sgcr.yml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    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']
    
    health:
      storagedriver:
        enabled: true
        interval: 10s
        threshold: 3
    
    proxy:
      remoteurl: https://k8s.gcr.io
      username:
      password:
      ttl: 168h
  • 创建 k8s 配置文件

    vim /data/registry-proxy/registry-k8s.yml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    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']
    
    health:
      storagedriver:
        enabled: true
        interval: 10s
        threshold: 3
    
    proxy:
      remoteurl: https://registry.k8s.io
      username:
      password:
      ttl: 168h
  • 创建 quay 配置文件

    vim /data/registry-proxy/registry-quay.yml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    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']
    
    health:
      storagedriver:
        enabled: true
        interval: 10s
        threshold: 3
    
    proxy:
      remoteurl: https://quay.io
      username:
      password:
      ttl: 168h

四、启动容器

1
docker-compose up -d

五、配置 Nginx

vim /etc/nginx/conf.d/registry.conf

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# registry-ui
server {
    listen       80;
    listen       443 ssl;
    server_name  ui.xxx.com;
    
    ssl_certificate /etc/nginx/ssl/xxx.com.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.com.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.xxx.com;

    ssl_certificate /etc/nginx/ssl/xxx.com.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.com.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;
    }

# Google Container Registry (gcr.io)
server {
    listen       80;
    listen       443 ssl;
    server_name  gcr.xxx.com;

    ssl_certificate /etc/nginx/ssl/xxx.com.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.com.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:53000;
        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;
    }
    
# Kubernetes Container Registry (k8s.gcr.io)
server {
    listen       80;
    listen       443 ssl;
    server_name  k8s-gcr.xxx.com;

    ssl_certificate /etc/nginx/ssl/xxx.com.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.com.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:54000;
        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;
    }
    
# Kubernetes's container image registry (registry.k8s.io)
server {
    listen       80;
    listen       443 ssl;
    server_name  k8s.xxx.com;

    ssl_certificate /etc/nginx/ssl/xxx.com.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.com.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:55000;
        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;
    }
    
# Quay Container Registry (quay.io)
server {
    listen       80;
    listen       443 ssl;
    server_name  quay.xxx.com;

    ssl_certificate /etc/nginx/ssl/xxx.com.pem;
    ssl_certificate_key /etc/nginx/ssl/xxx.com.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:56000;
        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;
    }
}

六、配置客户端

vim /etc/docker/damon.json

1
2
3
4
5
6
7
{
    "registry-mirrors": [ "https://hub.xxx.com" ],
    "log-opts": {
      "max-size": "100m",
      "max-file": "5"
    }
}