Harbor镜像仓库搭建实战:部署、HTTPS配置与日常运维指南
前两天组里有同事跑过来问我“你说我们自己构建的镜像到底扔哪比较靠谱”我说你是只想拉公共镜像还是想把自己打包的镜像也统一管起来。他说后者还想让不同的小组各管各的项目、各分各的权限。那答案基本就固定了——Harbor。容器镜像仓库这个东西平时不起眼真到要落地的时候你会发现直接裸跑一个 registry 或者靠公共镜像站根本不顶事。Harbor 是开源社区里最成熟、覆盖能力最全的镜像仓库方案适合个人学习、小团队自用也适合企业内部搞统一镜像源。这篇就把我从部署到日常使用、再到被各种证书和磁盘问题折腾的完整过程写出来给打算自建仓库的人一个可以直接照着做的参考。1. 为什么中大型团队最终都会选择自建 Harbor1.1 公共镜像仓库的短板确实存在先说最基础的问题团队小、镜像少的时候大家习惯直接从公共镜像站拉 nginx、redis 这些基础镜像然后打成自己的应用镜像往自己机器上一存就完事。这个阶段没人觉得需要什么仓库。但一旦超过三五个人或者开始有 CI/CD 流水线问题就来了。公共镜像仓库的匿名拉取是有并发和流量限制的同一个学校或办公网络里几十台构建机反复拉同一个基础镜像很容易触发限流。更麻烦的是私有镜像公司内部的服务、带配置文件的中间件镜像总不能明文扔到公共平台上。就算你愿意公共仓库也做不到“分项目、分角色”这种细致的权限控制。另一个容易被忽略的点是镜像生命周期管理。开发环境里镜像越积越多旧版本没人清理最后磁盘爆掉或者有人拉错 tag这种问题我见过太多次。自建仓库不是单纯地把镜像塞进硬盘而是要把登录、权限、复制、扫描、清理这一整套配套能力补上。1.2 Harbor 解决了哪些具体问题Harbor 本质上是一套面向容器镜像的完整服务而不是一个裸 registry。它给 registry 外面套了四层能力第一层是多租户和权限。Harbor 里有“项目”这个概念每个项目下可以分配不同用户角色分为项目管理员、开发者、访客还可以创建机器人账号给 CI/CD 用。这个设计非常贴近真实团队协作不像裸 registry 只有“有没有 token”两种状态。第二层是安全能力。集成漏洞扫描推送完镜像后能自动跑一遍常见漏洞库标记出高危项。还支持内容信任、签名验签虽然很多人用不上但对合规要求严格的环境是刚需。第三层是运维能力。垃圾回收、镜像复制、配额管理、Webhook 通知这些都是日常维护里最常碰到的需求。尤其是镜像复制多机房场景下可以直接靠 Harbor 自身的复制规则把镜像同步到远端仓库省掉一堆手工 docker pull/docker push 的脚本。第四层是认证对接。支持数据库内置用户、LDAP、OIDC企业里可以直接用统一认证登录不用给每个人单独开账号。打个不太严谨的比方裸 registry 像是一个没有门卫的库房谁都能进东西堆满了也没人管Harbor 则是给库房配了门禁、台账、保安和保洁。1.3 这套方案适合谁、不适合谁适合的情况很明确你要在团队里长期维护一批镜像要区分内外部使用权限要对接 CI/CD要跨机房同步或者你的网络环境比较封闭、需要离线安装一套内部仓库。个人学习也适合一台 4G 内存的虚拟机就能愉快地跑起来。不适合的情况也应当坦白说。如果团队只用两三个固定基础镜像既不构建私有镜像也不需要权限区分那自建 Harbor 反而增加维护成本。这种场景写几个 Dockerfile 存到 Git 里就够用了没必要多养一套带数据库和多个容器的服务。2. 部署前必须想清楚的四件事版本、环境、域名与存储2.1 选离线包还是在线包Harbor 官方提供两种安装介质在线安装包和离线安装包。名字有点容易混淆这里解释一下。在线安装包是个很小的脚本包运行 install.sh 的时候会动态从公共镜像源拉取 Harbor 所需的各个组件镜像离线安装包则是一个几百 MB 的 tar.gz里面已经把 nginx、registry、harbor-core、harbor-db 这些组件镜像全都打包好了安装时直接本地加载不依赖外网。我强烈建议不管你是不是在隔离网络第一次安装都用离线包。理由很简单在线安装时一旦某个组件镜像拉取超时或限流整个安装过程就挂在半路排查起来特别烦躁。离线包虽然下载大一点但胜在确定性高、可重复安装而且你后续如果要往完全隔离的内网环境部署离线包是唯一能顺利完成的方案。2.2 版本与依赖矩阵Harbor 当前主流版本是 2.x 系列。选版本的时候不要图新要看你的 Docker 和 Docker Compose 能不能满足要求。我记得官方要求在 2.x 版本里Docker 至少要到 20.10 以上Compose 最好用 v2 插件形式也就是docker compose这种子命令而不是老的docker-compose独立二进制。这里有一个非常常见的坑服务器上之前装过 docker-compose 1.x 的老版本比如 1.29而 Harbor 安装脚本内部用的是docker compose插件。如果你的 PATH 里只有docker-composeinstall.sh 会直接报错提示找不着 compose 命令。先跑一个版本检查能省下后面半小时的折腾时间。docker version --format {{.Server.Version}} docker compose version如果系统里没有 compose 插件可以用系统的包管理器装比如 Debian 系一般是docker-compose-plugin这个包名。装好之后确认docker compose version能正常输出再继续。2.3 hostname 到底填 IP 还是域名这是部署前最值得花时间想的一个问题。harbor.yml 里的 hostname 字段填 IP 和填域名在使用体验上差别很大。填 IP 是最省事的比如hostname: 172.21.10.5装完浏览器直接访问http://172.21.10.5docker login 也可以直接docker login 172.21.10.5。缺点是后续给 Harbor 配 HTTPS 的时候证书里必须带上这个 IP 的 SAN有些企业证书又不允许签 IP。而且一旦服务器换 IP所有客户端配置、脚本里的地址全要改。填域名是比较正规的做法比如hostname: harbor.internal或者规范一点的git.harbor.internal。但前提是你们环境里有 DNS 能解析这个域名或者在每台需要拉镜像的机器上都要配 hosts。这个域名最好是提前规划好的因为安装完再改 hostname 不是改个配置文件那么简单——你还要重新 prepare、重新生成或者更换证书、重新推送配置等于小半个重装流程。我个人经验是只要不是纯临时环境一律用域名。哪怕先用 IP 装上试水也建议尽早规划一个将来长期使用的域名等证书和 DNS 到位后再切换。2.4 存储与备份的提前规划Harbor 的数据分两大部分registry 里真正保存的镜像层数据以及 PostgreSQL 数据库里的项目、用户、标签等元数据。默认配置里数据目录是/data我这里更建议一开始就单独指定一个独立分区或者挂载点比如/data/harbor。为什么要单独分出来因为镜像多了之后这个目录的增长速度可能会超出你的预料。如果根目录磁盘只有几十 GB跑一个月 CI 基本就满了。更关键的是后面做备份、扩容、迁移的时候一个独立挂载点的数据目录会灵活很多直接做快照或者 rsync 都方便。存储这块Harbor 本身支持本地文件系统、S3 一类对象存储。但小规模场景直接用本地磁盘就好上来就接对象存储反而把架构搞复杂。先本地跑等镜像量真的大了再迁移也不迟。3. 离线安装包从零到可用的具体步骤3.1 部署前的运行环境准备我以一台全新的 Linux 服务器为例操作系统不需要特殊发行版Debian 系或 RHEL 系都行。先把 Docker 装好确保服务在运行状态然后确认 compose 插件可用。systemctl start docker systemctl status docker docker compose version接着创建 Harbor 专用的数据目录。这里顺便提醒一句后续 install.sh 里启动的容器会以 root 身份往这个目录里写数据所以没必要把目录所有权改成某个普通用户。如果你有洁癖想用普通用户管理整个 Harbor 目录也可以但需要保证目录权限能让容器进程写入否则 registry 容器起来以后会疯狂报“permission denied”。mkdir -p /data/harbor然后去官方 Releases 页面下载离线安装包。把压缩包解压后你会看到里面有一个很重要的配置文件模板harbor.yml.tmpl。我们的做法是把它复制成harbor.yml然后修改这个文件。tar xzvf harbor-offline-installer-v2.x.x.tgz cd harbor cp harbor.yml.tmpl harbor.yml vim harbor.yml3.2 harbor.yml 关键字段逐项说明harbor.yml 是 YAML 格式缩进千万不能用 Tab。我见过不止一次因为某个字段缩进多了一个空格prepare 阶段直接报解析错误。下面的代码块是一份能跑通的最小配置我把核心字段都标注了用途。hostname: harbor.internal http: port: 80 # 这一段落先注释掉等准备做 HTTPS 时再解开 # https: # port: 443 # certificate: /data/harbor/cert/harbor.crt # private_key: /data/harbor/cert/harbor.key harbor_admin_password: 这里写一个足够复杂的密码 database: password: 数据库专用密码别跟 admin 密码一样 max_idle_conns: 50 max_open_conns: 100 data_volume: /data/harbor trivy: ignore_unfixed: false skip_update: false offline_scan: false jobservice: max_job_workers: 10几个容易出错的地方单独说一下。harbor_admin_password是网页端 admin 超级管理员账号的密码安装完成后你可能根本不会再用它登录日常操作但它相当于整个仓库的后门密码复杂度一定要高一些。database.password是 Harbor 内部数据库的密码平时使用不会直接用到但是运维备份、排查问题的时候会用到建议单独设置不要和 admin 密码一样。trivy段落里的skip_update特别容易坑人。如果保持默认的falseHarbor 安装启动后扫描器组件会尝试联网更新漏洞库。在完全离线环境下这个更新会一直失败并且日志里反复报警。如果你确定环境里没有外网直接改成skip_update: true后续通过离线方式导入漏洞库或者干脆接受不更新漏洞库的现实。这个字段在没踩过坑之前非常容易被忽略。3.3 prepare 和 install.sh 到底做了什么改好配置文件后依次执行两条命令./prepare ./install.shprepare这个脚本做的事情很关键它会把 harbor.yml 里的配置渲染成各个组件真正使用的配置文件同时会生成 Docker Compose 的编排文件以及 nginx 的站点配置。也就是说如果你改了 harbor.yml必须先重新跑 prepare再重新运行安装脚本改动才会真正生效。很多人改完配置后只重启容器结果发现配置根本没变就是因为漏掉了 prepare 这一步。install.sh默认会启动 Harbor 的核心组件包括 nginx、harbor-portal、harbor-core、harbor-registry、harbor-db、harbor-jobservice、harbor-log、redis 这些。如果要额外启用漏洞扫描安装命令要带上--with-trivy。比较新的版本里 Clair 已经被 Trivy 取代直接加 trivy 即可。./install.sh --with-trivy执行过程中会看到本地镜像被 load 进去然后容器一个个起起来。装完后查一下所有容器状态docker compose ps看到所有容器都是 running 状态基本就成功了。这时候浏览器访问你配置的 hostname如果用的域名且 DNS 已配好直接打开如果临时用 IP 装的就访问 IP 地址。第一次打开会看到初始化页面用admin和 harbor.yml 里设置的密码登录。3.4 安装过程中的常见失败我实际安装中遇到最多的失败有三种。第一种是端口被占用。默认 http 端口是 80如果机器上已经跑着 nginx 或者别的 Web 服务install.sh 起 nginx 容器时会报端口冲突。可以先ss -lntp | grep :80 查一下占用情况或者把 harbor.yml 里的 http.port 改成比如 8080。第二种是 prepare 阶段报 YAML 解析错误。这种错误一般会指向具体的行号和列号就照着提示去查缩进。建议用支持 YAML 高亮校验的编辑器改配置文件避免肉眼找缩进。第三种是 compose 版本太旧导致 install.sh 直接退出。我在前面提过harbor 的安装脚本对 compose 的版本要求比较严格如果提示类似unsupported Compose file version或者--with-trivy 无法识别先确认你执行的是docker compose version而不是老的独立版本。还有一个小经验install.sh 失败后重新执行之前最好先docker compose down -v把之前生成的容器和数据清干净。不清的话第二次安装很可能因为旧容器残留导致配置错乱尤其是数据库初始化这种环节残留数据会造成“账号密码明明填对了却登录不上”的诡异问题。4. 日常使用中绕不开的项目、权限与推送拉取4.1 登录界面和 admin 密码的第一次改造Harbor 安装完成后第一个该做的事情不是急着推镜像而是把 admin 的密码策略想清楚。默认账号 admin 是超级管理员它可以创建项目、管理用户、修改系统配置。日常使用中我不建议把这个账号交给所有人共用否则出了问题审计都做不了。Harbor 的界面虽然是英文为主但布局很直观。左侧导航有“项目”“日志”“系统管理”几个大块。登录进去之后先到“系统管理”里的“用户”页面创建一批真正的用户然后再到各个项目里分配角色。一个团队内部比较合理的账号规划是每人一个独立账号管理员和普通开发分开。如果你用的是 LDAP 或 OIDC可以跳过这个步骤直接在认证模式里对接已有的统一认证用户登录时会自动映射到 Harbor 内部身份。4.2 命令行登录与镜像推送命令行是整个镜像仓库使用频率最高的入口。假设你已经有一个本地镜像nginx:stable想推送到 Harbor 的ops项目下操作逻辑是先在本地打一个带仓库地址的 tag然后登录推送。docker tag nginx:stable harbor.internal/ops/nginx:1.25.3 docker login harbor.internal -u alice -p 你的密码 docker push harbor.internal/ops/nginx:1.25.3这里的命名规则是仓库地址/项目名/镜像名:tag。很多第一次用的人会把ops当成命名空间或者忘记在前面加项目名。如果 push 时提示unauthorized先确认你登录的账号被加进了对应项目并且角色至少是开发者或者项目管理员。如果提示denied而账号权限没问题检查一下项目名称拼写Harbor 对项目名区分大小写。4.3 HTTP 环境下 Docker 客户端的特殊配置如果你安装 Harbor 时没有配 HTTPS只开了 80 端口这时候 Docker 客户端默认是不肯用 HTTP 协议的docker login 会报http: server gave HTTP response to HTTPS client。这不是 Harbor 的问题是 Docker 的安全策略。解决办法是在每台需要拉取镜像的机器上把 Harbor 地址加入 Docker 的insecure-registries。编辑/etc/docker/daemon.json{ insecure-registries: [harbor.internal] }改完执行systemctl restart docker再重新登录。这里有个细节insecure-registries里填的地址要和 push/pull 时使用的地址完全一致。你用docker login harbor.internal就写harbor.internal用docker login 172.21.10.5就写 IP。填错一个字Docker 还是会认为这个地址不在白名单里继续用 HTTPS 去握手。HTTP 模式适合临时试用。一旦真要给团队长期使用或者要跨网络同步我强烈建议尽快切到 HTTPS否则证书问题会在后续的复制、扫描、外部系统对接中反复出现。4.4 项目、用户、角色与机器人账号在 Harbor 里“项目”是最核心的资源隔离单元。一个项目对应一组镜像也对应一组权限策略。创建项目时有两个选项要理解清楚项目的访问级别“公开”和“私有”。公开项目的优点是团队成员不需要登录也能拉取镜像适合放基础镜像、公共构件。私有项目则要求必须登录且拥有该项目的拉取权限。默认情况下建议新项目先建为私有等确定要开放再改成公开。公开项目在界面上可以随时切换但要注意一旦公开就意味着所有能访问这个 Harbor 地址的人都可能拉取。角色分配上Harbor 里常用的是三种角色项目管理员、开发者、访客。开发者能推送镜像到项目内也能拉取访客只能拉取项目管理员额外能做配置、标签管理和成员管理。给 CI/CD 流水线用的时候不要拿开发者的个人账号去跑流水线。Harbor 支持机器人账号这种账号命名以robot$开头可以单独指定权限范围比如只允许推送某个项目。好处是流水线里用的密钥即使泄露了也只会影响一个机器人账号而不是某个人的全部权限。创建机器人的入口在项目的“机器人账号”标签页下。创建后系统会给你一个完整凭证通常长成robot$ops-pipeline加一长串密钥。注意密钥只显示一次关掉页面就看不到了务必第一时间存到你的密钥管理工具里。5. 自签 HTTPS 证书的完整配置与信任链处理5.1 为什么这一步省不掉很多人觉得“反正内网用HTTP 也没关系”。这话前期成立但只要你开始使用 Harbor 的复制功能、对接外部漏洞扫描器、或者通过 K8s 拉取镜像上层组件默认几百个心眼它不信任 HTTP 地址。更重要的是不同机器上配置insecure-registries是一个持续性的维护成本每新增一台构建机都要记得改 daemon.json漏一次就卡一次。所以我的建议是在 Harbor 正式投入使用之前就把 HTTPS 配好。内网环境基本不可能申请到商业 CA 证书所以自签 CA 是最现实的方案。整个链路不复杂自己当 CA 签发一个服务端证书把 CA 证书装到所有需要访问 Harbor 的客户端上。5.2 生成 CA 与服务端证书的过程我用 openssl 一步步来。第一步先生成自己的 CA 私钥跟根证书。这一步相当于自己办了个“证书颁发机构”。openssl genrsa -out ca.key 4096 openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \ -subj /CNHarbor Self-Signed CA -out ca.crt接着生成 Harbor 服务端私钥和证书签名请求。这里有一个关键点证书里必须包含你访问 Harbor 时使用的域名或 IP也就是 SAN 字段。如果漏掉 SAN浏览器和 Docker 都会提示证书不匹配。openssl genrsa -out harbor.key 2048 openssl req -new -key harbor.key \ -subj /CNharbor.internal -out harbor.csr然后准备一个 openssl.cnf用来定义 SAN 扩展[ req ] distinguished_name dn req_extensions v3_req [ dn ] [ v3_req ] subjectAltName alt_names [ alt_names ] DNS.1 harbor.internal DNS.2 git.harbor.internal IP.1 172.21.10.5最后用 CA 签发出最终的服务端证书openssl x509 -req -in harbor.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -out harbor.crt -days 825 -sha256 -extfile openssl.cnf -extensions v3_req把生成的harbor.crt和harbor.key放到一个让 Harbor 能读取的目录比如/data/harbor/cert/然后在 harbor.yml 里解开 https 段落https: port: 443 certificate: /data/harbor/cert/harbor.crt private_key: /data/harbor/cert/harbor.key重新跑一遍./prepare ./install.sh注意此时 80 端口的 HTTP 仍然会保留Harbor 的 nginx 默认同时监听 http 和 https 两个端口这不会冲突。5.3 客户端信任自签 CA 的正确姿势服务端证书签好只完成了一半。客户端机器如果不信任你自签的 CADocker 登录时照样会报x509: certificate signed by unknown authority。Linux 客户端把它加入系统 CA 信任链的方式取决于发行版。Debian 系cp ca.crt /usr/local/share/ca-certificates/harbor-ca.crt update-ca-certificates systemctl restart dockerRHEL 系cp ca.crt /etc/pki/ca-trust/source/anchors/ update-ca-trust extract systemctl restart dockermacOS 上可以双击 ca.crt 导入钥匙串然后在证书信任策略里改为“始终信任”。Windows 则是双击导入到“受信任的根证书颁发机构”。命令行登录前先确认一下系统里已经信任了 CA不然即使 docker login 第一次侥幸成功后续做镜像复制或者拉取时也会遇到一堆证书校验失败。这里还有一个很多人忽略的坑Harbor 容器内部有自己的系统信任库。当你在 Harbor 里创建一条指向另一个使用自签证书的仓库的复制规则时Harbor 自己也会校验对方证书。解决方式通常是把自签 CA 文件通过 volume 挂载进 Harbor 的 core 容器或者把 CA 加到 Harbor 所在宿主机的系统信任链后重启相关容器。这个操作不同版本略有差异但排查方向是一致的先看harbor-core容器的日志如果出现x509: certificate signed by unknown authority那基本都是双向信任没配齐。5.4 证书文件权限的注意点openssl 生成的私钥文件默认权限是 600一般不会有问题。但如果你把证书放在一个宿主机的自定义目录然后通过 volume 挂载给 Harbor 使用要确保容器内进程有权限读取。一个简单可靠的做法是chmod 644 harbor.crt、chmod 600 harbor.key。如果部署后发现登录 443 端口提示connection reset优先检查 nginx 容器挂载的证书路径和权限而不是急着怀疑 Harbor 本身的问题。6. 扫描、复制、垃圾回收与容量管理这些功能才是自建仓库的底气6.1 跨机房镜像复制Harbor 的复制功能可以简单理解成“仓库对仓库的同步”。常见的做法是在中心和分部分别部署一套 Harbor然后建立规则让中心仓库的某个项目自动推送到分部的 Harbor 上。这样分部本地有一份完整镜像拉取时不需要跨公网。新建复制规则的位置在“系统管理”-“复制管理”。填写远端仓库地址时注意协议如果远端是 HTTP界面里可以勾选“跳过证书校验”但生产环境我不建议这么做还是配好 HTTPS。复制规则的触发模式有三种事件驱动、定时、手动。事件驱动意味着只要源项目里出现新的镜像就立即触发同步定时适合网络不稳定、错峰同步的场景手动是指人工点击“复制”按钮执行。如果你网络带宽有限建议用定时模式限定在业务低峰期执行避免复制任务占满带宽影响线上镜像拉取。这个功能我实际使用下来最大的体会是千万别拿镜像同步当备份。复制只是把镜像数据推了一份到远端Harbor 的数据库元数据、用户配置、复制规则本身并不会同步过去。真要做容灾备份还是得靠对数据目录和数据库做快照。6.2 漏洞扫描与离线环境处理安装时带上了--with-trivyHarbor 里就有 Trivy 扫描器。默认配置下镜像在推送到项目后会被自动触发扫描任务扫描结果会按严重程度标记出漏洞列表。在线环境下Trivy 组件会主动拉取块漏洞库。离线环境下容易出现“扫描器状态不可用”或“漏洞数据过期”的告警。如果网络条件确实受限有两个方向一个是在 harbor.yml 里把trivy.skip_update设为true避免反复尝试联网另一个是在能联网的机器上预先把漏洞库下载好放到离线环境中给 Trivy 用。这个操作没那么常用但真碰上了可以少走弯路。扫描功能在开发和运维流程里的价值在于它能把“镜像安全”从一个模糊的担忧变成一张清晰的清单。哪怕你初期不强制团队处理所有扫描告警也应该让它先跑起来积累数据这样后面做安全评审时才有依据。6.3 垃圾回收与磁盘配额启用 Harbor 之后通常会遇到一个让人困惑的现象删除了一些镜像 tag但磁盘空间一点没少。这是因为删除 tag 只是删除了元数据层面的引用registry 里的镜像层 blob 文件还保留在磁盘上。回收这些没被引用的 blob 需要手动或定时执行“垃圾回收”。在 Harbor 界面进入“系统管理”-“垃圾回收”可以立即运行一次 GC。GC 期间registry 会进入只读模式推送和拉取操作里读不受影响但 push 会被临时挂起。所以生产环境要选低峰期执行或者建立定时任务定期在凌晨跑。比 GC 更重要的是提前用配额管理控制项目大小。在项目详情页的“配置”里可以设置存储配额。比如给开发项目限制 200GB超过之后推送会报错。这个机制能避免某个项目异常增长把整个磁盘撑爆。磁盘满了之后即使能 GC 也可能因为空间不足无法正常执行这是非常被动的状态远不如一开始就配好配额。6.4 备份与升级的实操心得备份 Harbor 有两条线镜像数据在data_volume目录下元数据在 PostgreSQL 数据库里。大部分情况下直接对data_volume做快照或者 rsync 可以把镜像数据完整带走但数据库更严谨的做法是进入harbor-db容器执行pg_dump导出。docker exec harbor-db pg_dump -U postgres --clean --if-exists harbor_backup.sql升级这块我栽过跟头在离线环境直接拿新版离线包解压复制旧的 harbor.yml 进去就跑./install.sh结果因为跨了两个大版本数据库结构不兼容启动后页面直接打不开。后来养成了习惯升级前先看官方升级说明里有没有“从哪个版本可以直接升到当前版本”的说明如果有特殊路径要求必须先升到中间版本就老老实实做两级升级。每次升级前先备份数据目录和数据库升级后立刻验证登录、推送、拉取、复制一条龙确认无误再开始日常使用。升级过程中最不需要担心的反而是配置文件。harbor.yml 基本保证了前后版本兼容多数情况下复制旧配置文件到新版本目录里就能用。最后再分享一个我自己的习惯给 Harbor 这台服务器留一定的 CPU 和内存余量不要卡着最低要求跑。镜像多的时候GC 和漏洞扫描任务会瞬间拉起不少并发任务资源不够很容易把数据库容器拖到重启。与其后面反复处理各种偶发超时不如前面多给一点资源。Harbor 装了以后基本上是个长期常驻的基础设施前期多花半小时把 HTTPS、磁盘配额、备份脚本这些基础工作做好后面三年你都省心。