1. 为什么值得花时间把 Dependency-Track 跑起来
软件供应链安全这两年从“合规加分项”变成了“上线硬门槛”。你交付一个镜像、一个 Jar 包、一个前端 bundle,里面到底引了多少个第三方组件、这些组件有没有已知漏洞、许可证是否干净,很多时候连开发团队自己都说不清楚。SBOM(软件物料清单)就是用来回答这个问题的,而 Dependency-Track 是目前开源圈里把“SBOM 持续分析”这件事做得最完整的平台之一。
它的定位很明确:你不需要在 CI 里跑一次性的扫描然后看一份静态报告,而是把所有项目、所有版本的 SBOM 持续喂给它,它帮你做版本追踪、漏洞匹配、策略告警。换句话说,它更像一个“组件资产 + 漏洞情报”的长期账本,而不是一次性的体检报告。
这篇内容面向的是准备第一次把 Dependency-Track 部署起来的人。我会把安装这件事拆开讲透:为什么官方推荐用容器方式、API Server 和 Frontend 为什么要拆成两个服务、数据库怎么选、首次启动有哪些坑、初始化管理员密码在哪里、以及怎么验证整套链路真的通了。装完之后你至少能得到一个能登录、能上传 SBOM、能看到漏洞结果的可用实例。整个过程我会按“从业者实际会怎么做”来写,参数和取舍都会给出理由,而不是照抄一份 docker-compose 就完事。
需要先说明一点:Dependency-Track 的版本迭代比较快,镜像标签、环境变量名在不同大版本之间偶有调整。下面涉及具体配置的地方,我会以当前主流稳定版的通用做法为准,并标注哪些地方需要你按自己拉到的版本核对。这是实操里最容易被忽略的一环——网上很多教程是两三年前写的,直接抄会踩坑。
2. 部署前的整体设计与选型思路
2.1 为什么官方架构是 API Server + Frontend 双服务
第一次看 Dependency-Track 的部署文档,很多人会疑惑:为什么不是一个大而全的容器,非要拆成dependency-track-apiserver和dependency-track-frontend两个镜像?这不是给自己找麻烦吗?
拆分的核心原因在于职责分离和升级灵活性。API Server 是真正干活的:它负责接收 SBOM、解析组件、跟漏洞数据源做匹配、执行策略引擎、对外提供 REST API。Frontend 本质上是一个静态资源服务加反向代理,它把浏览器请求转发给 API Server。这样拆开之后,前端可以独立更新(比如换个 UI 版本),后端逻辑升级也不用动前端容器;更重要的是,API Server 可以单独做水平扩展,而前端几乎不消耗什么资源。
从安全角度看,这个拆分也有意义。API Server 持有数据库凭据、需要访问外部漏洞情报源,属于高敏感服务,通常放在内网;Frontend 是唯一对外暴露的入口,攻击面相对小。你在做网络分区的时候,可以只让 Frontend 暴露端口,API Server 和数据库都藏在后面。
提示:如果你只是本地跑个 Demo 玩玩,确实可以用 all-in-one 的思路把两个服务塞进一个 compose 文件里,但生产环境强烈建议保持双服务结构,否则后面做升级和扩容会很别扭。
2.2 数据库选型:H2 还是 PostgreSQL
Dependency-Track 支持两种数据库:内置的 H2(嵌入式,文件型)和外部的 PostgreSQL。这个选择直接决定了你的部署复杂度和长期可用性。
H2 的好处是零配置,容器起来就能用,适合快速验证和单机小规模试用。但它的短板也很明显:并发写入能力弱,数据量一大(比如几万个组件、几十个项目持续上报)就容易出现锁等待;备份和迁移也不如 PostgreSQL 成熟。我见过有人拿 H2 跑了一个季度,项目数上到几十个之后,API 响应明显变慢,最后不得不迁移到 PostgreSQL,而迁移过程本身又是一堆事。
PostgreSQL 是官方推荐的生产级选择。它并发能力强、生态成熟、备份恢复方案完善,而且 Dependency-Track 的很多性能优化(比如索引策略)都是围绕 PostgreSQL 做的。代价就是你需要多维护一个数据库实例,多一份配置。
我的建议很直接:只要你不是“今天装完明天就删”的临时验证,一律上 PostgreSQL。多花的这点配置时间,会在你项目数量涨起来之后加倍还给你。
| 维度 | H2 | PostgreSQL |
|---|---|---|
| 配置复杂度 | 极低,开箱即用 | 中等,需独立实例 |
| 并发写入 | 弱,易锁等待 | 强,适合持续上报 |
| 数据规模上限 | 小规模试用 | 中大型生产 |
| 备份迁移 | 一般 | 成熟完善 |
| 官方推荐场景 | 演示、验证 | 生产环境 |
2.3 部署方式:容器编排还是裸机
Dependency-Track 官方提供 Docker 镜像,也支持直接跑 Jar 包。裸机部署(直接java -jar)的好处是你能完全控制 JVM 参数、日志路径、系统服务管理;坏处是依赖管理、升级、回滚都得自己写脚本。
容器方式(docker-compose 或 Kubernetes)的优势在于环境一致性——你在测试环境验证过的镜像,到生产环境还是同一个镜像,不会出现“我这能跑你那不能跑”的经典问题。而且 Dependency-Track 的官方镜像已经把 JVM 参数、健康检查、启动脚本都调好了,你只需要给环境变量。
对于绝大多数团队,我推荐 docker-compose 起步:比 Kubernetes 轻,比裸机省心,配置文件一目了然,迁移到 K8s 也容易。下面我就以 docker-compose 为主线来讲,同时把关键参数的含义说清楚,方便你迁移到其他编排方式。
3. 核心细节解析与实操前的准备
3.1 资源需求与端口规划
在动手之前,先把资源账算清楚。Dependency-Track 本身不算重,但它对内存比较敏感,尤其是 API Server 在做 SBOM 解析和漏洞匹配的时候。
一个中等规模(几十个项目、持续上报)的部署,我建议的最低配置是:API Server 分配 2 到 4 GB 堆内存,PostgreSQL 分配 1 到 2 GB,Frontend 几乎不占资源,512 MB 足够。磁盘方面,主要消耗在数据库上,SBOM 数据和漏洞匹配结果会持续增长,预留 20 GB 起步比较稳妥,长期跑建议挂独立数据卷并做定期清理策略。
端口规划上,默认情况下 Frontend 监听 8080,API Server 监听 8081。对外只需要暴露 Frontend 的端口,API Server 的端口在容器网络内部访问即可。如果你前面还要挂一层反向代理(Nginx、Traefik 之类),那 Frontend 端口也可以只在内网暴露。
注意:API Server 的 8081 端口如果直接暴露到公网,等于把管理接口裸奔出去了。生产环境务必只暴露 Frontend,或者用反向代理做统一入口和鉴权。
3.2 环境变量的关键项
Dependency-Track 的配置几乎全靠环境变量。下面这几个是安装阶段必须搞明白的,我把它们分成“数据库相关”和“服务相关”两类。
数据库相关:
ALPINE_DATABASE_MODE:取值external表示用外部 PostgreSQL,embedded表示用内置 H2。生产环境填external。ALPINE_DATABASE_URL:JDBC 连接串,格式类似jdbc:postgresql://数据库主机:5432/数据库名。ALPINE_DATABASE_DRIVER:PostgreSQL 填org.postgresql.Driver。ALPINE_DATABASE_USERNAME/ALPINE_DATABASE_PASSWORD:数据库账号密码。
服务相关:
ALPINE_API_URL:Frontend 用来找 API Server 的地址,容器网络里通常填http://apiserver:8081。ALPINE_CORS_ENABLED:跨域开关,前后端分离部署时可能需要打开。ALPINE_INITIAL_ADMIN_PASSWORD:首次启动时初始化管理员密码,不设的话会随机生成并打印在日志里。
这里有个特别容易踩的坑:ALPINE_API_URL填的是 Frontend 容器视角能访问到的地址,不是你在宿主机浏览器里访问的地址。很多人在这里填了http://localhost:8081,结果 Frontend 容器里根本连不上 API Server,页面一直转圈。容器之间要用服务名通信,这是 Docker 网络的基本规则。
3.3 镜像标签的选择
Dependency-Track 的镜像标签有好几种:latest、具体版本号(如4.x.x)、以及带后缀的变体。我的建议是永远不要用latest上生产。latest意味着你每次重新拉取都可能拿到一个新版本,而 Dependency-Track 的大版本升级偶尔会有数据库 schema 变更,自动升级可能带来意外。
正确做法是锁定一个具体版本号,比如dependencytrack/apiserver:4.x.x和dependencytrack/frontend:1.x.x,前后端版本要匹配(官方 release notes 会说明对应关系)。升级的时候手动改标签、看 changelog、备份数据库,再重启。这套流程虽然多几步,但能避免“某天早上服务起不来”的惊魂时刻。
4. 实操过程:从零把服务跑起来
4.1 编写 docker-compose 文件
下面这份 compose 文件是我在实际部署中反复用过的结构,包含 PostgreSQL、API Server、Frontend 三个服务。你可以直接拿去改。
version: "3.8" services: postgres: image: postgres:15-alpine container_name: dt-postgres restart: unless-stopped environment: POSTGRES_DB: dtrack POSTGRES_USER: dtrack POSTGRES_PASSWORD: 换成你自己的强密码 volumes: - dt-pg-data:/var/lib/postgresql/data networks: - dt-net apiserver: image: dependencytrack/apiserver:4.x.x container_name: dt-apiserver restart: unless-stopped depends_on: - postgres environment: ALPINE_DATABASE_MODE: external ALPINE_DATABASE_URL: jdbc:postgresql://postgres:5432/dtrack ALPINE_DATABASE_DRIVER: org.postgresql.Driver ALPINE_DATABASE_USERNAME: dtrack ALPINE_DATABASE_PASSWORD: 换成你自己的强密码 ALPINE_INITIAL_ADMIN_PASSWORD: 换成你的初始管理员密码 volumes: - dt-api-data:/data networks: - dt-net frontend: image: dependencytrack/frontend:1.x.x container_name: dt-frontend restart: unless-stopped depends_on: - apiserver environment: ALPINE_API_URL: http://apiserver:8081 ports: - "8080:8080" networks: - dt-net volumes: dt-pg-data: dt-api-data: networks: dt-net: driver: bridge几个关键点解释一下。depends_on只保证启动顺序,不保证 PostgreSQL 已经 ready,所以 API Server 第一次启动可能会因为连不上数据库而重试几次,这是正常的,restart: unless-stopped会让它自动恢复。dt-api-data这个卷挂到/data,是 API Server 存放一些本地数据的地方,别省。数据库密码和管理员密码一定要换成强密码,别用示例值。
4.2 启动与首次初始化
文件写好之后,在同一个目录下执行:
docker compose up -d然后盯一下日志,尤其是 API Server 的启动过程:
docker compose logs -f apiserver你会看到它先连数据库、然后执行 schema 初始化(第一次启动会建表,可能要一两分钟)、接着加载漏洞数据源。看到类似Starting API server或者监听端口的日志,基本就说明起来了。
如果你没有在环境变量里设ALPINE_INITIAL_ADMIN_PASSWORD,那就要在日志里找初始密码,通常会打印一行包含admin和随机密码的提示。我强烈建议显式设置初始密码,省得去日志里翻,而且日志里的密码如果被别看到也不安全。
提示:首次启动时 API Server 会去同步漏洞数据源,这个过程可能持续几分钟到十几分钟,取决于网络和镜像源。在同步完成前,漏洞匹配结果可能不全,这是正常的,别以为装坏了。
4.3 验证整套链路是否真的通了
服务起来不等于能用。我一般按下面这个顺序验证,每一步都能定位到具体环节。
第一步,确认三个容器都在运行:
docker compose ps三个服务状态都应该是Up。如果 API Server 反复重启,八成是数据库连接问题,去看它的日志。
第二步,直接访问 API Server 的健康检查接口(在宿主机上,如果端口没暴露就用docker exec进去 curl):
docker exec dt-apiserver curl -s http://localhost:8081/api/version能返回版本号 JSON,说明 API Server 本身没问题。
第三步,浏览器打开http://你的主机:8080,应该能看到登录页。用admin和你设置的初始密码登录。如果页面能打开但登录报错,通常是 Frontend 到 API Server 的ALPINE_API_URL配错了,回去检查。
第四步,登录后进Administration里的Analysis或者数据源配置页,确认漏洞数据源的状态。如果显示还在同步,等一会儿再看。
这四步走完,整套链路就算真正通了。任何一步卡住,都能快速定位是数据库、API Server 还是 Frontend 的问题,比盲目重启高效得多。
5. 常见问题与排查技巧实录
5.1 启动阶段的典型故障
安装阶段遇到的问题其实高度集中,我把最常见的几个整理成速查表,方便你对号入座。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| API Server 反复重启 | 数据库连不上 | 检查 JDBC URL、账号密码、数据库是否 ready |
| 页面能开但登录失败 | Frontend 找不到 API | 检查ALPINE_API_URL是否为容器内可达地址 |
| 登录后一直转圈 | API Server 未就绪或 CORS 问题 | 看 API 日志,必要时开ALPINE_CORS_ENABLED |
| 漏洞结果为空 | 数据源还在同步 | 等待同步完成,检查数据源状态 |
| 上传 SBOM 报 500 | 数据库 schema 未初始化完 | 等初始化完成,或检查数据库权限 |
这里重点说两个我踩过的坑。第一个是数据库密码里有特殊字符,比如@、#,直接写进 JDBC URL 或者环境变量会导致解析错误。解决办法是用 URL 编码,或者干脆用不含特殊字符的强密码(长度够就行)。第二个是宿主机上已经有服务占了 8080 端口,导致 Frontend 起不来,docker compose ps会显示端口冲突。改一下映射端口就行,比如"18080:8080"。
5.2 升级与数据保留的注意事项
很多人装完之后就不管了,等到要升级的时候才发现不知道怎么安全地升。这里给几条实操经验。
升级前一定先备份数据库。PostgreSQL 用pg_dump导出一份,命令类似:
docker exec dt-postgres pg_dump -U dtrack dtrack > backup_$(date +%Y%m%d).sql然后改 compose 文件里的镜像标签,docker compose pull拉新镜像,docker compose up -d重启。API Server 启动时会自动执行数据库迁移脚本,这一步不要中断,等它跑完。如果迁移失败,用备份回滚。
前后端版本要匹配,别只升一个。官方 release notes 里会写明哪个前端版本对应哪个后端版本,升级前扫一眼,能省掉很多莫名其妙的兼容问题。
注意:不要在生产环境直接跑
latest然后指望它自动升级。自动升级意味着你失去了对升级时机的控制,而数据库迁移是不可逆的,出问题的时候你连回滚的窗口都没有。
5.3 几个提升长期可用性的小技巧
第一,给 API Server 配一个合理的 JVM 堆大小。默认值在项目多了之后可能不够,可以通过JAVA_OPTS环境变量调整,比如-Xmx4g。但别设得比容器内存上限还大,否则会被 OOM Killer 干掉。
第二,定期清理旧的 SBOM 数据。Dependency-Track 会保留每个上传的 SBOM 版本,时间长了数据库会膨胀。可以在项目设置里配置保留策略,或者定期归档不活跃的项目。
第三,把数据库和 API Server 的数据卷放在可靠的存储上,并纳入你的备份体系。SBOM 数据本身可以重新上传,但漏洞匹配历史、策略配置、用户权限这些是重新配很麻烦的,值得备份。
第四,如果你打算把它接入 CI,先在测试环境把 API Token 的权限范围摸清楚。Dependency-Track 支持细粒度的权限和团队划分,别一上来就用 admin 的 Token 去跑 CI,权限过大且不好审计。
6. 装完之后可以怎么用起来
服务跑起来只是起点。接下来最自然的动作是创建一个项目,然后手动上传一份 SBOM 试试水。SBOM 格式支持 CycloneDX 和 SPDX,CycloneDX 是官方主推的,工具链支持也最广。你可以用常见的构建工具插件生成一份 CycloneDX 格式的 SBOM,然后在项目页面里上传,看它解析出多少组件、匹配出多少漏洞。
这一步的意义在于验证你的 SBOM 生成链路和 Dependency-Track 的解析能力是否对得上。我见过有人生成的 SBOM 里组件信息不全(比如缺 PURL),导致漏洞匹配率很低,还以为是平台的问题,其实是 SBOM 本身质量不行。PURL(Package URL)是漏洞匹配的关键字段,生成 SBOM 的时候一定要确保它被正确填充。
等你确认手动上传没问题了,再去接 CI 自动上报,就是水到渠成的事。到那时候,你手里就有了一套能持续追踪组件风险的基础设施,而不是每次上线前临时抱佛脚跑一次扫描。
我个人在实际部署中的体会是,Dependency-Track 的安装本身并不复杂,真正花时间的是把数据库、网络、版本匹配这些细节理顺。第一次装的时候多花半小时把每个环境变量的含义搞清楚,后面升级和排障会轻松很多。最后再分享一个小技巧:把 compose 文件和一份简短的部署说明一起放进版本控制,注明每个密码类环境变量的来源(比如从哪个密钥管理工具取),下次换人维护的时候能少走很多弯路。