背景
docker 仓库存储大量的镜像,占用的空间很大,放到群晖上存储再合适不过了
之前写过基于 docker compose 使用 Harbor 搭建 Docker 私有仓库并管理,但是群晖里只有 docker 的管理,没有 docker compose 的直接支持
现在来个简单的仓库管理
方法
- 安装 docker 套件
- 下载 registry 和 joxit/docker-registry-ui 镜像
- 分别启动这 2 个容器,注意配置
registry 配置
- 配置挂载目录
- 配置环境变量,因为默认的 registry 镜像不支持跨域请求和没有开启删除镜像的功能,我曾尝试在镜像里修改配置文件,然后在导出镜像,但是失败了,新导出的镜像启动后无法提供服务
- 环境配置如下
REGISTRY_STORAGE_DELETE_ENABLED:true
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers:[‘Origin,Accept,Content-Type,Authorization’]
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods:[‘GET,POST,PUT,DELETE’,’HEAD’]
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin:[‘*’]
REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers:[‘Docker-Content-Digest’]
后续配置
路由器开启端口映射即可
镜像的删除
首先要说的是,这里有个坑, 官方提供的删除镜像仓库中镜像的接口,仅仅是把 manifest 删除了,真正的镜像文件还存在!官方并没有提供删除镜像层的接口!这也就是说,当我们调用删除镜像的接口之后,仅仅是查看镜像的列表时看不到原镜像了,然而原有镜像仍然在磁盘中,占用着宝贵的文件存储空间
这里使用官方提供的 GC 工具来清除无用文件
删除方式 1
- 在 web 界面上删除,或者调用 api 删除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 获取待删镜像的digest
获取镜像digest的API为:
GET /v2/<tag>/manifests/<version>
例如: /v2/joy/blog.joylau.cn/manifests/1.0
其中,name是仓库名,reference是标签,此时需要注意,调用时需要加上header内容:
Accept: application/vnd.docker.distribution.manifest.v2+json
其中Docker-Content-Digest的值就是镜像的digest
3、调用官方的HTTP API V2删除镜像
删除镜像的API为:
DELETE /v2/<name>/manifests/<sha256>
例如: /v2/joy/blog.joylau.cn/manifests/sha256:6c2daa1642b94dabdfaa32a9d3943cb92036c55117961fa9fcc4cc29348e5d39
其中,name是仓库名称,reference是包含“sha256:”的digest。
|
- 进入容器里调用GC清理镜像文件
1
| bin/registry garbage-collect /etc/docker/registry/config.yml
|
注意: gc不是事务操作,当gc过程中刚好有push操作时,则可能会误删数据,建议设置read-only模式之后再进行gc,然后再改回来
- 重启 docker registry
注意,如果不重启会导致push相同镜像时产生layer already exists错误。
删除方式 2
使用第三方开源工具: https://github.com/burnettk/delete-docker-registry-image
该工具也提供了dry-run的方式,只输出待删除的信息不执行删除操作。在命令后加上——dry-run即可
跟gc方式一样,删除镜像之后要重启docker registry,不然还是会出现相同镜像push不成功的问题。
docker-registry-ui 对于有认证的 docker 私服的配置 [2020-04-09 更新]
对于没有认证的 docker 私服,使用方式上面已经有配置了
对于有认证的 docker 私服,却有点变化
需要改变:
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods:[‘GET,POST,PUT,DELETE’,’HEAD’]
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin:[‘‘]
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials: [true]
另外,对于有认证的 docker 私服,删除镜像还有有问题的:
具体情况见: https://github.com/Joxit/docker-registry-ui/issues/104
简单来说是 docker 私服的锅,并不是 Joxit/docker-registry-ui 的问题,因为在浏览器再监测是否允许跨域请求发出的 options 请求被返回了 401 状态,导致后续请求无法发出
而实际上应该返回 20x 的请求
作者给出方法是: 将 docker 私服和 docker-registry-ui 放到同一个域下
那我这边还是以 群晖的 docker 来配置 nginx 来实现这样的功能
nginx 配置如下:
- /etc/nginx/nginx.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
| user nginx; worker_processes 1;
error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid;
events { worker_connections 1024; }
http { include /etc/nginx/mime.types; default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on; #tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf; }
|
- /etc/nginx/conf.d/default.conf: 这个文件我们添加反向代理,使得 docker 私服和 docker-registry-ui 在同一个域下
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
| server { listen 80; server_name localhost;
#charset koi8-r; #access_log /var/log/nginx/host.access.log main;
location / { root /usr/share/nginx/html; index index.html index.htm; }
#location / { # #rewrite ^/b/(.*)$ /$1 break; # 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_pass http://nas.joylau.cn:5007/; # 转发地址,注意要有/ #} location /v2 { 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_pass http://xxxx:xxx/v2; # 转发地址 }
location /ui { rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/ui前缀, 否则会出现404 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_pass http://xxxx:xxx/; # 转发地址,注意要有/ }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; }
# proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #}
# deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
|
访问方式:
- docker-registry-ui 的访问直接使用 nginx 的地址, 后面加上
/ui/
, 这样就会代理到之前的 docker-registry-ui 的服务
- docker registry 的地址直接填 nginx 提供服务的
主机 + 端口号
即可, 后面不需要加其他东西
这样方式在 docker-registry-ui 连接 docker 私服时会弹框输入用户名密码, 也能完美解决删除镜像的问题
Docker 私服配置 SSL 证书
- 去证书申请网站上下载证书, 我的是阿里云的, 下载下来的压缩包里有 2 个文件 .key 和 .pem
- 将这 2 个文件上传到 NAS 上, 配置 registry 挂载这 2 个文件, 并配置如下 2 个环境变量, 重启 registry 容器即可
1 2
| -e REGISTRY_HTTP_TLS_CERTIFICATE=/server.crt -e REGISTRY_HTTP_TLS_KEY=/server.key
|
REGISTRY_HTTP_TLS_CERTIFICATE 这个变量指定的文件可以在挂载的时候将 .pem 直接更名为 .crt 文件