套件庫
所有套件與映像的唯一來源 · 路線圖項目 32 · 負責團隊:SRE
每一次建置都要解析相依套件,每一次部署都要拉映像,每一台主機都要安裝 OS 套件。目前前兩者都經過地端一台 Nexus OSS —— 開發機無法連外,所有套件都透過它取得 —— 而在雲端建置的映像散落在好幾個專案各自的 registry 裡,主機則經由連外 proxy 抓 Ubuntu 套件。本頁描述目標:以 Google Artifact Registry 作為 Go、Python、npm、Maven、Docker 與 Ubuntu Apt 的唯一套件庫,經私有路徑、以身分而非金鑰存取,並採用不會刪掉執行中版本的保留策略。它也是項目 25 鋪好的路所發布的地方 —— 25.1 與 25.3 所說的「發布至 registry」,指的就是這裡。
工作規劃為 CI/CD 與 GitOps 里程碑上的 32.1–32.7。里程碑日期為初稿,之後會調整。
為什麼
| 問題 | 現況代表什麼 |
|---|---|
| 單點故障 | 只有一台 Nexus OSS,沒有高可用。它一停,全公司的建置與部署都會停。 |
| 修補仰賴社群 | OSS 版沒有原廠支援,CVE 要多久才修無法預期。 |
| 雲端存取不到 | 雲端工作負載沒有路徑連到地端快取,每次都從網際網路重新下載相依套件,各團隊也因此在各自專案裡另建 registry。 |
| 兩套身分系統 | 地端用 Nexus 本地帳號,雲端用 IAM。帳號靠人工管理、權限粒度粗、異動難追蹤,離職人員的帳號容易殘留。 |
| 清理無法「保留最新 N 版」 | OSS 版的清理只能依時間。目前用正規表示式限制範圍,但擋不住刪掉一個仍在執行、只是很少被重新拉取的舊版本。 |
| 主機經 proxy 抓 OS 套件 | 主機裝了什麼、從哪裡來,不受任何套件庫控管。 |
清理問題的規模:2026 年 3 月的試算,502 個映像版本中有 370 個被標為待刪除 —— 每一個都得人工比對是否仍在執行。
目標
每種格式各有兩個 repository —— 一個放自家發布的內容,一個快取上游 —— 並在 Artifact Registry 支援的格式上,於兩者前面加一個 virtual repository,讓用戶端每種格式只需設定一個 URL。
| 格式 | 自家發布(standard) | 上游快取(remote) | 用戶端設定 |
|---|---|---|---|
| Docker | internal-docker | proxy-dockerhub —— Docker Hub | 映像參照、registries.conf |
| npm | internal-npm | proxy-npmjs —— npmjs.org | .npmrc |
| Maven | internal-maven | proxy-maven-central —— Maven Central | settings.xml |
| Python | internal-pypi | proxy-pypi-org —— pypi.org | pip.conf/uv index |
| Go | internal-go | proxy-golang —— proxy.golang.org | GOPROXY,私有模組設 GOPRIVATE |
| Apt | internal-apt | proxy-ubuntu 與 proxy-ubuntu-security —— Ubuntu archive 與 security,24.04 與 26.04 LTS | 主機:sources.list 指向地端 Apt 快取;建置:Artifact Registry 的 Apt transport |
| NuGet | — | — | **例外:**保留一台最小化的 Nexus,只服務 NuGet。Artifact Registry 不支援 NuGet,目前只有一個非核心單位使用。 |
Repository 以 IaC(項目 04)建立並設定權限,不手動操作。映像 repository 設為 immutable tags:tag 一旦推上去,就不能再指向不同的內容。Apt 只鏡像 LTS 版本;主機升到新的 LTS 時再加入。
存取路徑
開發機目前無法連外,這點不會改變。把連外 proxy 開放到 Artifact Registry 的公開網域並不可行:*.pkg.dev 底下是全世界的 Artifact Registry,包括任何人的公開 repository,而 proxy 只看得到網域、看不到後面的路徑,分辨不出哪些是我們的。
地端改以私有路徑存取 Artifact Registry:
- VPN 或 Interconnect 連線接在 Shared VPC host 專案上。
- 透過
restricted.googleapis.com使用 Private Google Access,其位址段由 Cloud Router 宣告給地端。 - 地端 DNS 將
*.pkg.dev與*.googleapis.com解析到 restricted 位址(項目 10)。 - VPC Service Controls 邊界涵蓋 host 專案與 registry 專案,這條路徑上只能存取我們自己的 repository。
CI runner 都是自建的:地端的走同一條路徑,GCP 上的位於邊界內。雲端工作負載在同一個邊界內直接存取。
主機的 Apt 套件經由地端 Apt 快取安裝,快取唯一的上游是 Artifact Registry。如此一來,整批主機修補時,每個套件只跨 WAN 下載一次而不是每台一次;WAN 中斷時,已快取的套件仍可安裝;主機本身也不需要持有 Google 憑證。
上游控管
Artifact Registry 決定套件從哪個上游來;網路擋掉其他所有路徑;CI 檢查實際進來了什麼。
- **remote repository 就是上游允許清單。**每個 remote repository 只有一個上游,而且只在 IaC 中定義 —— 建立或修改 repository 的權限只給 Terraform 身分,新增上游就是一次經過審核的 merge request。
- virtual repository 以 internal 優先,公開套件即使搶註了我們內部套件的名稱,也不會被選中(dependency confusion)。
- 用戶端每種格式只用一個 URL —— Python 不用
--extra-index-url(pip 會在多個 index 間挑最高版本),Go 不用GOPROXY=…,direct,Maven 的 mirror 設為*。 - 全部切換後,連外 proxy 不再能連到公開 registry 與 Ubuntu archive。
- CI 擋下含 git 或 URL 相依的 lockfile,這類相依任何 registry 設定都看不到。
- **GitLab 的 package registry 與 dependency proxy 維持關閉。**Artifact Registry 是唯一的套件庫。
Artifact Registry 做不到的是允許或封鎖個別套件:remote repository 會鏡像整個上游。這個缺口由掃描補上。
安全性掃描
每一層的結果都送進 DefectDojo(項目 21),上版閘門讀取的就是這裡。
| 層次 | 做法 | 抓得到什麼 |
|---|---|---|
| 建置 | 共用 CI 範本中以 Trivy 掃映像與原始碼相依、產生 SBOM,Go 另跑 govulncheck | 推送前就發現有弱點的相依套件與 OS 套件 |
| Registry | 只在 internal-docker 開啟 Artifact Analysis | 繞過 CI 推上來的映像;建置後不久才公布的 CVE |
| 執行中 | 每日重掃叢集上執行中的 digest —— 與保留策略用的是同一份清單 | 早已沒人重新拉取、但仍長期執行的版本 |
| 部署 | 准入前驗證簽章與 attestation(項目 15.4) | 不是由 CI 建置並掃描過的任何東西 |
| 上游 | 只能經由 remote repository 取得套件;lockfile | 惡意或冒名(typo-squatting)的套件悄悄進來 |
保留策略
規則來自上版約定,它已經規定了映像如何加 tag、如何發布:
- **版本 tag 永不清除。**正式版是把 rc 映像以 retag(crane/skopeo)加上版本別名,而不是重新建置,所以正式環境跑的就是版本 tag。
- Commit tag 每個映像保留最新 N 版,而且部署中者絕不清除 —— 只要仍被執行中的工作負載參照,不論多舊都不是清理對象。
- 其他格式的套件保留每一個已發布版本,只有 remote 快取會過期。
清理政策先以 dry-run 執行,並與執行中的 digest 比對。2026 年 3 月的 Docker 試算(502 個版本、370 個待刪)是第一個基準。
遷移
- 概念驗證(32.1)—— 每種格式端到端驗證、量測存取路徑,並確認下方的待確認問題。
- Repository、身分與私有連線納入 IaC(32.2)。
- 歷史套件逐格式複製(32.4),增量複製可重複執行,直到最後一條 pipeline 切換。這段期間 Nexus 照常服務。
- 試點 pipeline 切換(32.5),Nexus 與 Artifact Registry 並行。回退方式是把 registry URL 改回去。
- 全面切換(32.6)—— 所有 pipeline、開發機與主機的 Apt 來源。其中包括退掉部分 pipeline 目前帶有的
mirror-nexusstage —— 它把映像從 Artifact Registry 複製到地端 Nexus,讓地端叢集以 insecure-registry 設定拉取。直到最後一條 pipeline 切換、最後一次增量複製完成後,Nexus 才改為唯讀。 - Nexus 退場(32.7)—— 唯讀至少四週後除役,只留下最小化的 NuGet 實例。
概念驗證要確認的問題
- Go remote repository —— Artifact Registry 對 proxy.golang.org 的快取與私有模組的支援程度,確認後才定案 Go 這一列。
- 私有路徑的頻寬 —— 映像拉取與整批主機修補經混合連線的流量,對照目前的
mirror-nexus路徑。 - Artifact Analysis —— 映像以外的涵蓋範圍、費用,以及能否匯入 DefectDojo。
- Virtual repository 與組織政策 —— 各格式的支援度,以及組織政策能否在 IAM 之外再限制 remote 上游。
- Region —— 預設 asia-east1,就近存取。
- 歷史複製的範圍 —— 涵蓋哪些 Nexus repository、往回多久。
與其他項目的關係
| 項目 | 關係 |
|---|---|
| 25 · 應用程式容器化 | 25.1 的 base image 與 25.3 各服務的映像都發布到這裡;25.1 等待 32.2。 |
| 15 · CI/CD 管線最佳化 | 15.4 為映像簽章並在部署前驗證;它等待 32.6,簽章與映像一起存放在這裡。 |
| 20 · 端到端建置稽核 | 建置事件指向的產出物,就是這個 registry 裡的一個 digest。 |
| 21 · 弱點管理 | 上述每一層掃描都回報到 DefectDojo。 |
| 12 · 動態密鑰引擎 | 本設計遵循的「不留靜態憑證」原則。 |
| 10 · DNS/07 · 網路 IaC | 地端 DNS 解析 restricted 位址;防火牆與 proxy 規則。 |
| 04 · 宣告式基礎設施 | Repository、身分與私有路徑都由 Terraform 管理。 |