自建 Docker 私有仓库
GitHub Packages 免费提供 500M 空间 1G 外网流量的私有容器仓库。Pro 用户可达 2G 存储 10G 流量。如果没有特殊需要不建议自己折腾了。
这是只是一篇比较水的记录
快速开始
Docker 官方提供了 Registry 镜像,可以快速部署服务。这里使用 Docker Compose 来运行:
version: "3"
services:
registry:
image: registry:2
container_name: registry
restart: always
ports:
- "5000:5000"
volumes:
- ./registry:/var/lib/registry
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:5000
REGISTRY_STORAGE_DELETE_ENABLED: "true"
/var/lib/registry
是容器内用户上传镜像的保存位置,根据需求映射到本地。环境变量 REGISTRY_HTTP_ADDR
控制其监听的地址与端口,注意把端口映射出来。
现在在本机已经可以使用啦,试试看吧:
docker pull hello-world
docker tag hello-world:latest localhost:5000/custom:latest
docker push localhost:5000/custom:latest
Tips: 下面命令可以执行 Docker Registry 的垃圾清理:
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
# registry 是容器的名字
HTTPS
上面的最小实例只能在本机使用,要是在其他机器通过 ip 或域名访问默认会被阻断,因为 Docker 默认不允许使用明文 HTTP 推送。这是客户端的限制,与服务器 Registry 无关。
我们当然可以通过配置修改这个行为,但这不是最佳实践。下面还是配一下 HTTPS 证书。非常简单,只需要加几个环境变量:
version: "3"
services:
registry:
image: registry:2
container_name: registry
restart: always
ports:
- "5000:443"
volumes:
- ./registry:/var/lib/registry
- /www/wwwroot/ssl/docker:/certs
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:443
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/fullchain.pem
REGISTRY_HTTP_TLS_KEY: /certs/key.pem
REGISTRY_STORAGE_DELETE_ENABLED: "true"
注意映射一下包含证书文件的文件夹。
建议使用 acme.sh 来自动化获取与更新免费的 https 证书。
Nginx 反代
Registry 地址带个端口号真是太难看了。而我们的服务器通常也会部署普通的 web 服务,443 端口已经被占用,那么最好的办法就是反向代理一下。
server
{
listen 80;
listen 443 ssl http2;
server_name docker.example.com;
# -------------------- https
ssl_certificate /www/wwwroot/ssl/docker/fullchain.pem;
ssl_certificate_key /www/wwwroot/ssl/docker/key.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /www/wwwroot/ssl/docker/fullchain.pem;
# -------------------- https END
# .well-known 下文件不走反代以免影响 https 证书签发
location ^~ .well-known{
allow all;
}
# 请求搜索引擎屏蔽
location = /robots.txt {
default_type text/html;
add_header Content-Type "text/plain; charset=UTF-8";
return 200 "User-Agent: *\nDisallow: /";
}
# 反代
location / {
proxy_pass http://localhost:5000;
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_cache off;
}
}
上面配置有几个注意点:
-
proxy_cache off;
用于关闭反代缓存。反正 Docker 储存库就在本地,没有缓存的必要,反而在服务端清除一些垃圾后客户端重新 push 可能遇到下面的诡异报错:upload manifest blob unknown: blob unknown to registry
-
proxy_pass
目前用了 http 协议,同样因为 Docker 仓库服务就在本地,没有必要启用 https。
Nginx 配置 https 后 Docker Registry 就可以不配置 https 了。
来试试我们的反代:
docker pull hello-world
docker tag hello-world:latest docker.example.com/custom:latest
docker push docker.example.com/custom:latest