registry · 集群私有镜像仓库
registry 是集群自托管的私有 OCI 镜像仓库,运行官方 distribution/registry v3,镜像的 blob 与 manifest 全部落在集群内 MinIO 的 registry bucket(S3 兼容存储)。它附带一个 joxit/docker-registry-ui 作为只读 Web 浏览界面,对外通过 Cloudflare tunnel + traefik 暴露在 registry.yldm.tech / registry.dunaifen.games。
整套部署位于独立的 registry 命名空间,由两个 Deployment 组成:核心 registry(端口 5000 提供 OCI distribution API,5001 暴露 Prometheus 指标)与 registry-ui(端口 8080,反代到集群内 registry)。命名空间挂了独立的 ResourceQuota 与 LimitRange 做资源约束。
部署形态
核心仓库与 UI 各为单副本 Deployment,镜像版本固定写在 manifest 中(不经 argocd-image-updater 改写)。
- Name
- 命名空间
- Description
- registry(独立命名空间,namespace.yaml 显式创建)
- Name
- 工作负载
- Description
- 两个 Deployment:registry(核心仓库)+ registry-ui(Web 界面)
- Name
- registry 镜像
- Description
- registry:3.1.1(distribution v3),replicas 1
- Name
- registry-ui 镜像
- Description
- joxit/docker-registry-ui:2.6.0,replicas 1
- Name
- registry 端口
- Description
- 5000(http,OCI distribution API)、5001(metrics,debug + Prometheus)
- Name
- registry-ui 端口
- Description
- 容器 8080,Service 暴露 80
- Name
- 存储
- Description
- 无 PVC;blob/manifest 全部存到集群内 MinIO 的 S3 bucket
registry(storage driver = s3)
- Name
- 安全上下文
- Description
- registry 以非 root(uid/gid 1000)运行,drop ALL caps、禁止提权、RuntimeDefault seccomp
- Name
- 资源约束
- Description
- 命名空间级 ResourceQuota(pods 5、requests.cpu 500m / mem 512Mi、limits.cpu 3 / mem 2Gi)+ LimitRange 默认值
registry 容器 requests cpu 50m / mem 64Mi,limits cpu 1 / mem 512Mi;readiness 与 liveness 探针都打 /v2/(5000)。registry-ui 容器 requests cpu 10m / mem 32Mi,limits cpu 200m / mem 128Mi,readiness 探针打 /(8080)。manifest 未配置 nodeSelector/workload 标签、HPA/VPA 或 PDB。
配置与依赖
registry 的主配置由 ConfigMap registry-config 提供,以只读卷挂到 /etc/distribution(v3 默认配置路径;v2 时代是 /etc/docker/registry)。关键配置项:
| 配置 | 值 | 说明 |
|---|---|---|
| storage driver | s3 | bucket registry,endpoint http://minio.minio.svc.cluster.local:9000,region us-east-1,forcepathstyle、secure=false |
| storage.redirect.disable | true | 禁用 S3 presigned URL 重定向,registry 自己代理 blob 内容 |
| storage.cache.blobdescriptor | inmemory | blob descriptor 内存缓存 |
| storage.delete.enabled | true | 允许删除 |
| http.addr | :5000 | OCI API 监听端口 |
| http.relativeurls | true | 在 TLS 终止的 ingress 后生成代理无关的上传 Location URL |
| http.debug.addr | :5001 | 指标 + 健康端口,/metrics 开启 prometheus |
| health.storagedriver | enabled,interval 10s,threshold 3 | 存储驱动健康检查 |
S3 凭据不在 ConfigMap 里,而是经 ExternalSecret registry-s3 从 Vault(ClusterSecretStore vault-backend,KV 路径 registry/minio)拉取,同步成 Secret registry-s3,再以三个环境变量注入容器,与 config.yml 的 storage.s3 合并:
- Name
- REGISTRY_STORAGE_S3_ACCESSKEY
- Description
- remoteRef
registry/minio的access-key
- Name
- REGISTRY_STORAGE_S3_SECRETKEY
- Description
- remoteRef
registry/minio的secret-key
- Name
- REGISTRY_HTTP_SECRET
- Description
- remoteRef
registry/minio的http-secret,上传/cookie 状态的 HMAC secret,从 Vault 取以保证跨重启稳定
ExternalSecret 的 refreshInterval 为 1h。核心运行时依赖是集群内 MinIO(applications/storage/minio/)与 Vault(凭据来源)。
registry-ui 通过环境变量配置,自带 nginx 同源反代到集群内 registry,免 CORS:NGINX_PROXY_PASS_URL=http://registry.registry.svc.cluster.local:5000、SINGLE_REGISTRY=true、REGISTRY_TITLE="DNF Private Registry"、DELETE_IMAGES=false、SHOW_CONTENT_DIGEST=true、SHOW_CATALOG_NB_TAGS=true。
访问与监控
registry 核心 Service 为 NodePort(30500 → 5000),便于大体积镜像推送绕过 Cloudflare 代理的 100MB 请求体上限直连节点;另有 ClusterIP Service registry-metrics(5001)供指标抓取。registry-ui 为 ClusterIP(80 → 8080)。
对外入口经 Cloudflare tunnel + traefik(ingressClassName: traefik),且按 Cloudflare 账号做了拆分:
| Host | Cloudflare tunnel | TLS |
|---|---|---|
| registry.yldm.tech | NEW 账号 tunnel 2b822c22... | cert-manager DNS-01 origin 证书(letsencrypt-prod,secret registry-tls) |
| registry.dunaifen.games | OLD 账号 tunnel 79da7b14... | Cloudflare 边缘 TLS,无 origin 证书 |
| registry-ui.yldm.tech | NEW 账号 tunnel 2b822c22... | cert-manager 证书(secret registry-ui-tls) |
| registry-ui.dunaifen.games | OLD 账号 tunnel 79da7b14... | Cloudflare 边缘 TLS |
yldm.tech 与 dunaifen.games 分属不同 Cloudflare 账号,故 host 必须指向各自账号的 tunnel;cert-manager 的 DNS-01 只覆盖 yldm.tech/yldm.ai,所以只为 yldm.tech host 签 origin 证书,dunaifen.games 走 Cloudflare 边缘 TLS。registry 的 ingress 上放开了 body 上限(proxy-body-size: 0)并把读写超时拉到 600s,应对大镜像层。
监控方面:ServiceMonitor registry 通过 registry-metrics Service 的 metrics 端口(5001)按 30s 间隔抓取 /metrics,relabel 出 pod / namespace / service / job 标签。manifest 中未包含 PrometheusRule。
注意事项
几处 manifest 里以注释标注的关键约束:
- redirect 必须禁用:MinIO 只在集群内可达(NetworkPolicy + 内部 DNS),不能把客户端 307 重定向到 presigned S3 URL,否则节点 containerd / 外部客户端会被重定向到
minio.minio.svc:9000而拉取失败,所以 registry 自己代理 blob 内容。 - 大镜像推送走 NodePort:Cloudflare 代理另有 100MB 请求体上限,大推送应直连 NodePort
30500,而非走 ingress。 - ResourceQuota 的
limits.cpu从 2 提到 3:留出滚动更新时第二个 registry pod(1 cpu)与旧 pod、registry-ui 并存的余量,否则默认 surge 会因配额死锁报 FailedCreate。 - registry-ui 不能 drop ALL caps:joxit 入口用 sed 原地模板化 index.html / nginx 配置,需要以 root(默认)写文件,剥掉
DAC_OVERRIDE会导致写权限被拒、CrashLoop,所以 UI 容器只设了禁止提权 + seccomp,未 drop caps。 - v3 配置路径变更:distribution v3 默认配置路径是
/etc/distribution/config.yml(v2 时代是/etc/docker/registry/config.yml),挂载路径已对应调整。
返回 storage 总览