自架服務 Atlas 資料庫 schema migration DevOps

Flyway 寫到 V200 還是得靠人腦避免 schema 飄移:Atlas 用 HCL 把資料庫變更變成 Terraform

傳統 schema migration 工具強迫開發者手寫每一步 SQL,回滾失敗、schema 飄移、PR 看不出影響範圍都得自己想辦法。本文解析 Atlas 用宣告式 HCL 描述目標狀態、自動產生 versioned migration、在 CI 階段做破壞性變更掃描的完整工作流,以及它跟 Flyway、Bytebase 的定位差異。

Schema migration 從 Rails Active Record 把 db:migrate 變成內建指令之後,幾乎所有後端框架都走上同一條路:每一次資料庫變更寫成帶版本號的 SQL 檔,例如 V001__create_users.sqlV002__add_email_index.sql,部署時依序套用。Flyway、Liquibase、golang-migrate、Alembic、Knex 全是這個套路的衍生變體。十幾年下來看起來穩定,但實務上卡的問題從來沒少過——schema 飄移、回滾失敗、PR 裡的 SQL 看不出影響範圍、不同環境跑同一份 migration 卻得出不同結果。Atlas 是這幾年裡少數從根本翻掉這個工作流的工具。

Atlas 由 Ariga 開發,採 Apache 2.0 授權,2026 年 2 月發到 1.1 版,GitHub 上累積近 8000 顆星。核心想法非常直白:與其讓開發者一筆筆寫 SQL 變更,不如讓開發者描述「資料庫應該長什麼樣」,剩下的 diff、產生 migration、檢查破壞性變更全部交給工具。整個邏輯跟 Terraform 對基礎設施做的事情幾乎一模一樣。

為什麼 V001、V002 這套已經撐不下去

版本化 migration 的核心假設是:每個變更都是一次有狀態的事件,按順序套用就能還原任何環境。前提沒問題,痛點在執行細節。第一個是回滾。Flyway 標榜支援 down migration,但實務上稍微複雜的變更——把欄位拆成兩個 table、把單一索引換成複合索引——根本沒辦法純靠 SQL 倒退。多數團隊乾脆放棄回滾,改用「往前修補」策略,但這需要每次都重新寫一筆對沖 migration,又是一個新版本號。

第二個是 schema 飄移。生產環境通常會有 DBA 手動下過 ALTER TABLE,或某次 hotfix 直接在 console 跑掉某段 SQL。三個月之後沒人記得當時改了什麼,新的 migration 套上去就炸。Flyway 對這件事完全沒招,只能靠 migrate validate 偵測差異,但偵測完只會回報「對不上」,後續處理還是得靠人腦。

第三個是 review。一筆 ALTER TABLE users DROP COLUMN email 看起來只有一行,背後牽涉的可能是上千萬筆資料、長達數小時的表鎖、以及線上服務的 503。沒有人在 PR 上看得出這件事,得在 staging 跑過才會發現。當 schema 變更頻率拉高、團隊規模拉大,這套人工把關的成本會線性增加。

宣告式 schema 把問題反過來解

Atlas 提供兩種主要工作模式。第一種叫 declarative:開發者用 HCL、SQL DDL,或從 ORM(GORM、Prisma、SQLAlchemy、Drizzle 等 16 種)匯入的 schema 描述目標狀態,Atlas 跟資料庫比對,產生對應的 ALTER 計畫,套用上去。整個過程不需要寫版本號 SQL。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
table "users" {
schema = schema.public
column "id" {
type = bigserial
null = false
}
column "email" {
type = text
null = false
}
primary_key {
columns = [column.id]
}
index "idx_users_email" {
unique = true
columns = [column.email]
}
}

要新增欄位就在這個檔案改一筆,跑 atlas schema apply --to file://schema.hcl --url $DB_URL,Atlas 會自己算出 ALTER TABLE users ADD COLUMN ... 並套用。Terraform 用戶會立刻認出這個工作流。

第二種叫 versioned migration,看起來像傳統 Flyway,但生成 SQL 的人變成 Atlas 自己。開發者改 HCL 之後跑 atlas migrate diff add_phone,Atlas 會比對舊版 schema 跟新版 schema 的差異,產出一個帶時間戳的 migration 檔。部署時用 atlas migrate apply 套用,整個流程跟 Flyway 一致,但少了人為寫錯的可能。

實務上選哪一種要看團隊風險偏好。Declarative 模式適合早期專案、schema 變動頻繁、能接受工具自動推斷變更步驟。Versioned 模式適合成熟系統,要求每筆 ALTER 都能被審計、留下完整歷史。多數團隊會混用:開發環境用 declarative 快速試錯,CI 階段轉成 versioned migration 提交進 git。

migrate lint 把破壞性變更擋在 PR 階段

Atlas 真正讓人有感的不是宣告式語法,而是 CI 階段的 migrate lint。它內建超過 50 條檢查規則,會在 GitHub Actions 跑起來時掃過 PR 帶進來的 migration,標出潛在的破壞性變更:刪欄位、改型別、增加 NOT NULL 卻沒有 default、在大表上 add column 卻沒加 IF NOT EXISTS 導致長時間鎖表。

舉個常見場景。開發者把 varchar(255) 改成 text,PostgreSQL 上這個操作通常不會鎖表,但 MySQL 8.0 之前會。Atlas 知道兩邊的差異,會根據目標資料庫類型給出對應警告。再進一步,它會直接在 PR 上留 comment,告知「這筆變更會鎖表 14 分鐘(依現有 row count 估算)」,讓 reviewer 在合併前就能看到風險。

設定方式短得不像話。.github/workflows/atlas.yml 裡裝上 ariga/setup-atlasariga/atlas-action/migrate/lint,指向 migration 目錄就完成。如果想接 Atlas Cloud,會額外得到歷史紀錄、生產環境的 schema 監控、飄移自動偵測。Cloud 是付費功能,但本地的 lint 跟 diff 完全免費,自架 CI 也能直接用。

跟 Flyway、Bytebase 的定位差在哪

Flyway 跟 Liquibase 跑了快二十年,現在仍是企業 Java 棧最常見的選擇。它們的優勢是穩定、文件齊全、跟 Spring Boot 整合無痛。劣勢是工作流完全不變——還是版本號 SQL、還是手寫、CI 階段檢查工具有限。對只需要把 migration 跑起來的小團隊,這條路依然成立。

Bytebase 是另一條路線:以 GUI workflow 為核心,每筆 schema 變更都走「提交 issue → review → approve → rollout」的審核流程,定位在 enterprise DBaaS 治理層。它跟 Atlas 不是直接競品,比較像「資料庫版的 Jenkins」。如果團隊本來就有 DBA 角色、需要強審計痕跡,Bytebase 解的是另一個問題。

Atlas 的甜蜜點在「開發者自己改 schema、希望 review 能自動化、希望 schema 飄移能被偵測」這段。它沒有 GUI 審核流程,也不打算取代 DBA,但對於 GitOps 工作流已經成熟、把基礎設施當程式碼管理的團隊,它把資料庫這塊最後的非自動化區域補了起來。

部署在 VPS 上的實際做法

Atlas 是單一 Go binary,下載解壓就能用。在 VPS 上部署最簡單的方式是把 binary 放進 CI runner 或部署容器,跟 application image 一起 build。官方 Docker image 大約 50MB,啟動沒有依賴。

整合 application 部署的標準做法是在 application 容器 entry point 之前跑一次 atlas migrate apply,確認資料庫狀態符合預期才啟動應用程式。Kamal 2 跟 Dokploy 這類部署工具都能透過 pre-deploy hook 接進來。Kubernetes 環境裡 Ariga 提供 operator,把 AtlasMigration 變成 CRD,跟 Helm chart 一起管。

需要注意的是宣告式模式不該直接在生產環境跑。生產的標準做法仍是 versioned migration:開發階段用 declarative 改 HCL、產出 versioned SQL、commit 進 repo、CI 階段做 lint、部署階段用 atlas migrate apply 跑出來。直接在生產 apply schema 等於放棄 audit trail,出事沒辦法追責任。

另外一個容易忽略的細節是資料庫帳號權限。atlas migrate apply 預設用同一個帳號做 DDL 跟 DML,但在嚴格環境下 DDL 權限通常只開給 migration 帳號,DML 留給應用程式自己用的帳號。--url 參數可以分別指定,把這兩種權限拆開,符合 least-privilege 原則。

把資料庫納入 GitOps 的最後一塊

Infrastructure-as-code 在 2015 年之後逐步擴張,網路、CDN、DNS、Kubernetes 配置都已經宣告式化。資料庫一直是例外——schema 變更依舊高度依賴人工,每個團隊的 migration 工作流都有一套土法煉鋼的版本。Atlas 不是第一個嘗試解這個問題的工具,但它的設計剛好踩在 Terraform 用戶熟悉的工作流上,學習成本相對低,加上 migrate lint 把 CI 階段的安全檢查補上,導入後立刻能拿到價值。

對於正在規劃從單機 VPS 升級到多機 Docker 部署、或想把資料庫管理納入 GitOps 流程的團隊,Atlas 是值得排進評估清單的選項。NCSE Network 提供臺灣是方電訊機房的 VPS 主機與技術開發服務,配備 Intel Gold CPU 與 NVMe SSD,能穩定支撐資料庫工作負載與 CI/CD 流程的延遲需求,需要協助評估資料庫架構或部署自動化的團隊,可以到 ncse.tw 了解更多細節。

需要技術開發支援?

NCSE Network 提供 Discord Bot、LINE Bot、AI Agent、爬蟲、監控系統等客製化開發服務,從規劃到上線一站式完成。

洽談專案 →