ingestr 完整教學
跨資料庫零程式碼資料搬遷 CLI 工具
§1 專案概述與定位
1.1 是什麼
ingestr 是由 Bruin Data 開發的開源命令列工具,用一條指令就能將資料從任意來源複製到任意目的地。以 Go 語言實作,底層採用 Apache Arrow 作為記憶體內中間格式,實現高效能的跨系統資料搬遷。
1.2 解決什麼問題
傳統資料搬遷面臨三大痛點:
- ETL 開發成本高:每個來源/目的地組合都需要獨立開發 connector
- 維護負擔重:API 變更、schema 演進、認證方式更新都需要人工介入
- 學習曲線陡:不同工具有不同的設定檔格式與部署方式
ingestr 的解法是「單一 CLI、統一 URI 格式」:使用者只需提供來源與目的地的 connection URI,就能完成資料搬遷。
1.3 關鍵數據
| 指標 | 值 |
|---|---|
| GitHub Stars | 3,699 |
| 支援來源數 | 113 個模組 |
| 支援目的地數 | 27 個模組 |
| 主要語言 | Go (5.9 MB) |
| 最新版本 | v1.0.21 (2026-06-06) |
| 授權 | FSL-1.1-ALv2 |
1.4 適用對象
- 資料工程師:快速建立 ad-hoc 資料搬遷管線
- 後端工程師:跨環境資料同步(dev → staging → prod)
- 資料分析師:將 SaaS 資料拉到本地 DuckDB 分析
- DevOps:CI/CD 中的資料初始化與回填
§2 技術架構與核心設計
2.1 整體架構
ingestr 採用 pipeline 模式,核心流程為:
1Source → RecordBatch (Arrow) → Buffer → Strategy → Destination
- Source:實作
source.Source介面,負責連線、列舉表格、讀取資料 - RecordBatch:使用 Apache Arrow 的 columnar 格式作為中間表示
- Buffer:
databuffer套件負責批次管理,支援記憶體與檔案兩種模式 - Strategy:決定寫入策略(append / merge / delete+insert)
- Destination:實作
destination.Destination介面,負責 schema 建立與資料寫入
2.2 關鍵技術元件
| 元件 | 路徑 | 職責 |
|---|---|---|
| Pipeline 核心 | pkg/pipeline/ | 串接 Source → Destination 的完整流程 |
| Source 介面 | pkg/source/source.go | 定義來源的統一 API |
| Destination 介面 | pkg/destination/destination.go | 定義目的地的統一 API |
| Strategy 引擎 | pkg/strategy/ | 實作 append / merge / delete+insert |
| Schema Evolution | pkg/schemaevolution/ | 來源/目的地 schema 差異處理 |
| Schema Inference | pkg/schemainfer/ | 無 schema 來源的自動推斷 |
| Data Buffer | pkg/databuffer/ | 批次暫存(記憶體或檔案) |
| Arrow 轉換 | pkg/arrowconv/ | 型別轉換與 Arrow 互操作 |
| Naming 策略 | pkg/naming/ | 表格/欄位命名轉換(如 snake_case) |
| Progress 追蹤 | pkg/progress/ | 即時進度顯示 |
| HTTP 工具 | pkg/http/ | 共用 HTTP client 設定(TLS、重試等) |
| Web UI | pkg/webui/ | 內建 web 介面(server 模式) |
2.3 Registry 模式
ingestr 使用自動化 registry 模式管理 113 個來源與 27 個目的地:
1cmd/genregistry/ → 自動產生 import 註冊碼
2pkg/source/*/register.go → 每個來源的自我註冊
3pkg/destination/*/register.go → 每個目的地的自我註冊
執行 go run ./cmd/genregistry 會掃描所有 register.go,產生統一的 import 檔案,避免手動維護巨型 import 清單。
§3 系統架構圖
graph TB
subgraph CLI["CLI Layer (cmd/)"]
ROOT[root.go
Cobra CLI 入口]
INGEST[ingest.go
ingest 子命令]
SERVER[server.go
server 子命令]
TELEM[telemetry.go
匿名使用追蹤]
end
subgraph PIPELINE["Pipeline Core (pkg/pipeline/)"]
PIPE[Pipeline
主引擎]
BUF[DataBuffer
批次暫存]
PROG[Progress
進度追蹤]
end
subgraph STRATEGY["Strategy Layer (pkg/strategy/)"]
APPEND[Append
全量附加]
MERGE[Merge
增量合併]
DELINS[Delete+Insert
刪除後插入]
end
subgraph SOURCE["Source Layer (pkg/source/)"]
SRC_DB["資料庫來源 (25+)
Postgres / MySQL / BigQuery
Snowflake / ClickHouse ..."]
SRC_SAAS["SaaS 來源 (70+)
Shopify / Stripe / HubSpot
Salesforce / Slack ..."]
SRC_FILE["檔案來源 (7+)
CSV / JSON / Parquet
Avro / HTTP / Blob"]
end
subgraph DEST["Destination Layer (pkg/destination/)"]
DST_DB["資料庫目的地 (20+)
Postgres / BigQuery / Snowflake
ClickHouse / DuckDB ..."]
DST_FILE["檔案目的地 (4)
CSV / JSONL / Parquet
Blob Storage"]
end
subgraph SCHEMA["Schema Layer"]
EVOLVE[SchemaEvolution
schema 差異處理]
INFER[SchemaInfer
自動推斷]
ARROW[ArrowConv
型別轉換]
end
ROOT --> INGEST
ROOT --> SERVER
INGEST --> PIPE
PIPE --> BUF
PIPE --> PROG
PIPE --> STRATEGY
APPEND --> DEST
MERGE --> DEST
DELINS --> DEST
SOURCE --> PIPE
PIPE --> SCHEMA
EVOLVE --> DEST
style CLI fill:#E3F2FD,stroke:#1565C0
style PIPELINE fill:#FFF3E0,stroke:#E65100
style STRATEGY fill:#E8F5E9,stroke:#2E7D32
style SOURCE fill:#F3E5F5,stroke:#6A1B9A
style DEST fill:#FCE4EC,stroke:#B71C1C
style SCHEMA fill:#FFFDE7,stroke:#F57F17
sequenceDiagram
participant User as 使用者
participant CLI as CLI (cmd/)
participant Pipe as Pipeline
participant Src as Source
participant Buf as DataBuffer
participant Strat as Strategy
participant Dst as Destination
User->>CLI: ingestr ingest --source-uri ... --dest-uri ...
CLI->>Pipe: New(config)
Pipe->>Src: Connect(ctx, sourceURI)
Src-->>Pipe: connected
Pipe->>Src: ListTables(ctx)
Src-->>Pipe: []TableInfo
Pipe->>Dst: Connect(ctx, destURI)
Dst-->>Pipe: connected
Pipe->>Src: Read(ctx, readOpts)
loop 每個 RecordBatch
Src-->>Buf: Arrow RecordBatch
Buf->>Strat: flush(batch)
Strat->>Dst: Write(batch)
Dst-->>Strat: ok
end
Pipe-->>CLI: done
CLI-->>User: 完成 ✓ (rows, duration)
§4 快速上手
4.1 安裝
1# 方法 1:官方安裝腳本(推薦)
2curl -LsSf https://getbruin.com/install/ingestr | sh
3
4# 方法 2:pip 安裝(Python wrapper)
5pip install ingestr
6
7# 方法 3:Docker
8docker run --rm ghcr.io/bruin-data/ingestr:latest ingest --help
9
10# 驗證安裝
11ingestr --version
4.2 第一次資料搬遷:Postgres → DuckDB
1# 從 Postgres 複製一張表到本地 DuckDB
2ingestr ingest \
3 --source-uri 'postgresql://user:pass@localhost:5432/mydb' \
4 --source-table 'public.orders' \
5 --dest-uri 'duckdb:///local.duckdb' \
6 --dest-table 'raw.orders'
4.3 增量載入(Incremental)
1# 使用 merge 策略,以 id 為主鍵,updated_at 為增量鍵
2ingestr ingest \
3 --source-uri 'postgresql://user:pass@localhost:5432/mydb' \
4 --source-table 'public.orders' \
5 --dest-uri 'bigquery://my-project?credentials_path=./sa.json' \
6 --dest-table 'warehouse.orders' \
7 --incremental-strategy merge \
8 --incremental-key updated_at \
9 --merge-key id
4.4 從 SaaS API 抓資料
1# Shopify → BigQuery
2ingestr ingest \
3 --source-uri 'shopify://?api_key=YOUR_KEY&store_name=mystore' \
4 --source-table 'orders' \
5 --dest-uri 'bigquery://project?credentials_path=./sa.json' \
6 --dest-table 'shopify.orders'
7
8# Stripe → DuckDB
9ingestr ingest \
10 --source-uri 'stripe://?api_key=sk_live_xxx' \
11 --source-table 'charges' \
12 --dest-uri 'duckdb:///analytics.duckdb' \
13 --dest-table 'stripe.charges'
4.5 檔案匯入
1# CSV → Postgres
2ingestr ingest \
3 --source-uri 'csv://.' \
4 --source-table 'data.csv' \
5 --dest-uri 'postgresql://user:pass@localhost:5432/mydb' \
6 --dest-table 'public.imported_data'
7
8# Parquet → BigQuery
9ingestr ingest \
10 --source-uri 'parquet://.' \
11 --source-table 'output.parquet' \
12 --dest-uri 'bigquery://project?credentials_path=./sa.json' \
13 --dest-table 'raw.parquet_data'
§5 進階功能
5.1 增量載入策略
| 策略 | 說明 | 適用場景 |
|---|---|---|
append | 直接附加,不檢查重複 | Log 類資料、事件串流 |
merge | 以主鍵更新或插入 | 維度表、主資料 |
delete+insert | 先刪除符合條件的資料再插入 | 需要精確覆蓋的場景 |
5.2 Schema Evolution
ingestr 自動處理來源/目的地的 schema 差異:
- 新增欄位:自動在目的地新增
- 型別衝突:可設定
discard_row(跳過)或discard_value(設 null) - 欄位遮罩:
--column-mask可隱藏敏感欄位(如密碼)
5.3 Column Masking(欄位遮罩)
1# 遮罩 email 和 phone 欄位
2ingestr ingest \
3 --source-uri 'postgresql://...' \
4 --source-table 'public.users' \
5 --dest-uri 'duckdb:///dev.duckdb' \
6 --dest-table 'dev.users' \
7 --column-mask 'email,phone'
5.4 Server 模式
ingestr 支援 HTTP server 模式,提供 Web UI 與 API:
1ingestr server --port 8080
5.5 CDC 多表同步(PostgreSQL)
1# PostgreSQL CDC:監聽 WAL 變更,同步多表到 BigQuery
2ingestr ingest \
3 --source-uri 'postgres_cdc://user:pass@localhost:5432/mydb?slot=ingestr_slot' \
4 --dest-uri 'bigquery://project?credentials_path=./sa.json' \
5 --dest-table 'cdc.*'
5.6 環境變數支援
所有 CLI 參數都可透過環境變數設定:
| 環境變數 | 對應參數 |
|---|---|
SOURCE_URI / INGESTR_SOURCE_URI | --source-uri |
DESTINATION_URI / INGESTR_DESTINATION_URI | --dest-uri |
SOURCE_TABLE / INGESTR_SOURCE_TABLE | --source-table |
DESTINATION_TABLE / INGESTR_DESTINATION_TABLE | --dest-table |
INCREMENTAL_KEY / INGESTR_INCREMENTAL_KEY | --incremental-key |
INGESTR_DISABLE_TELEMETRY | 停用匿名使用追蹤 |
§6 資安檢測報告
6.1 掃描結果總覽
| 類別 | 狀態 | 說明 |
|---|---|---|
| 硬編碼密鑰 | 🟢 安全 | 未發現硬編碼的密碼、API key 或 token |
| .env 檔案 | 🟢 安全 | 未包含 .env 檔案 |
| 憑證檔案 | 🟢 安全 | 未包含 .pem / .key / credentials 檔案 |
| Gitleaks 設定 | 🟢 良好 | 已配置 .gitleaksignore,已知誤報已排除 |
| SQL 注入風險 | 🟡 注意 | 20 處使用 fmt.Sprintf 組裝 SQL 查詢 |
| TLS 驗證跳過 | 🟡 注意 | 10 處 InsecureSkipVerify,均為使用者可設定選項 |
| 危險檔案操作 | 🟢 安全 | 10 處 os.Remove/WriteFile,均為暫存檔清理或憑證保存(0o600 權限) |
| 外部指令執行 | 🟢 安全 | 未發現 exec.Command 呼叫 |
| unsafe 指標 | 🟢 安全 | 未使用 unsafe.Pointer |
| CGO | 🟢 安全 | 未使用 CGO |
| Telemetry | 🟡 注意 | 內建匿名使用追蹤,可透過 INGESTR_DISABLE_TELEMETRY=true 關閉 |
| Dockerfile | 🟢 良好 | 多階段構建、非 root 使用者、最小化 runtime image |
| 供應鏈 | 🟡 注意 | go.mod 含 292 行相依,需留意供應鏈風險 |
6.2 SQL 注入風險詳細分析
ingestr 在 20 個來源模組中使用 fmt.Sprintf 組裝 SELECT 查詢:
1// 典型模式(以 postgres 為例)
2query := fmt.Sprintf("SELECT %s FROM %s", strings.Join(colNames, ", "), quoteTableName(table))
風險評估:🟡 低風險
- 表名與欄位名來自系統目錄(metadata query),非使用者直接輸入
- 多數模組有
quoteTableName()/quoteColumn()函式做 escaping - 但仍有部分模組(如 adbc、databricks)未做完整 quoting
6.3 TLS 跳過驗證分析
10 處 InsecureSkipVerify = true 分佈於:
pkg/http/options.go— 通用 HTTP client 選項pkg/source/influxdb/— InfluxDB 連線pkg/source/elasticsearch/— Elasticsearch 連線pkg/source/clickhouse/— ClickHouse 連線pkg/source/hana/— SAP HANA 連線pkg/destination/trino/— Trino 目的地
風險評估:🟡 中低風險
- 全部都是使用者透過 URI 參數主動啟用的選項
- 程式碼中有
//nolint:gosec註解標示為已知風險 - 預設行為是啟用 TLS 驗證
6.4 總體評級
1┌─────────────────────────────────────────┐
2│ ingestr 資安評級:🟢 良好 │
3│ │
4│ 整體風險:低 │
5│ 可安全使用:是 │
6│ 建議措施: │
7│ 1. 部署時設定 INGESTR_DISABLE_TELEMETRY│
8│ 2. 生產環境不使用 InsecureSkipVerify │
9│ 3. 定期更新至最新版本 │
10└─────────────────────────────────────────┘
§7 開發環境建置
7.1 前置需求
| 工具 | 版本 | 用途 |
|---|---|---|
| Go | 1.25+ | 編譯主程式 |
| Git | 最新 | 版本控制 |
| Make | 任意 | 建置自動化 |
| gofumpt | 最新 | 程式碼格式化 |
| golangci-lint | v2+ | 靜態分析 |
7.2 建置步驟
1# 1. Clone
2git clone https://github.com/bruin-data/ingestr.git
3cd ingestr
4
5# 2. 安裝開發工具
6make setup
7
8# 3. 安裝相依
9make deps
10
11# 4. 產生 registry imports
12make generate
13
14# 5. 建置
15make build
16
17# 6. 執行測試
18make test
19
20# 7. 格式化與 lint
21make format
22make lint
7.3 開發工作流
1# 新增來源:在 pkg/source/<name>/ 下建立檔案
2# 必須包含:
3# - register.go → 自我註冊
4# - <name>.go → 實作 source.Source 介面
5# 然後執行:
6make generate # 更新 registry
7make build # 重新編譯
8make test # 執行測試
§8 部署模式
8.1 本地 CLI
最簡單的使用方式,適合 ad-hoc 操作:
1ingestr ingest --source-uri ... --dest-uri ...
8.2 Docker
1docker run --rm \
2 -e SOURCE_URI='postgresql://...' \
3 -e DESTINATION_URI='bigquery://...' \
4 -e SOURCE_TABLE='public.orders' \
5 -e DESTINATION_TABLE='raw.orders' \
6 ghcr.io/bruin-data/ingestr:latest ingest
8.3 CI/CD 整合
GitHub Actions 範例:
1name: Daily Data Sync
2on:
3 schedule:
4 - cron: '0 6 * * *'
5
6jobs:
7 sync:
8 runs-on: ubuntu-latest
9 steps:
10 - name: Install ingestr
11 run: curl -LsSf https://getbruin.com/install/ingestr | sh
12
13 - name: Sync orders
14 env:
15 SOURCE_URI: ${{ secrets.SOURCE_DB_URI }}
16 DESTINATION_URI: ${{ secrets.DEST_BQ_URI }}
17 INGESTR_DISABLE_TELEMETRY: 'true'
18 run: |
19 ingestr ingest \
20 --source-table 'public.orders' \
21 --dest-table 'raw.orders' \
22 --incremental-strategy merge \
23 --incremental-key updated_at \
24 --merge-key id
8.4 Server 模式(Web UI)
1ingestr server --port 8080
2# 瀏覽器開啟 http://localhost:8080
§9 與同類工具比較
| 特性 | ingestr | Airbyte | Fivetran | dlt |
|---|---|---|---|---|
| 部署方式 | 單一二進位 | Docker Compose / K8s | SaaS | Python library |
| 來源數量 | 113 | 300+ | 500+ | 100+ |
| 主要語言 | Go | Java/Python | 閉源 | Python |
| 增量載入 | 支援 | 支援 | 支援 | 支援 |
| CDC | PostgreSQL | 多種 | 多種 | 有限 |
| Schema Evolution | 自動 | 自動 | 自動 | 手動 |
| 成本 | 免費 | 開源/商業 | 付費 | 免費 |
| 學習曲線 | 極低 | 中等 | 低 | 中等 |
| 適合場景 | Ad-hoc / CI/CD | 持續同步 | 企業級 | Python 生態 |
ingestr 的獨特優勢
- 零設定檔:不需要 YAML / JSON 設定,純 CLI 參數
- 單一二進位:不需要 Docker、JVM 或 Python runtime
- 效能:Go 原生實作 + Arrow columnar 格式,記憶體效率高
- 113 → 27 的矩陣:任意來源到任意目的地的組合
§10 常見問題與疑難排解
Q1:如何處理大量資料?
ingestr 使用 DataBuffer 機制,支援記憶體與檔案兩種模式。大量資料時會自動切換到檔案模式,避免 OOM。
Q2:如何處理 schema 變更?
使用 --schema-evolution-mode 參數:
add(預設):自動新增欄位discard_row:跳過不符合 schema 的資料列discard_value:不符合的欄位值設為 null
Q3:如何除錯連線問題?
1# 啟用詳細日誌
2ingestr ingest --source-uri '...' --dest-uri '...' --verbose
3
4# 使用 server 模式的 Web UI 測試連線
5ingestr server
Q4:如何關閉 telemetry?
1export INGESTR_DISABLE_TELEMETRY=true
2# 或
3export DISABLE_TELEMETRY=true
Q5:支援自訂欄位型別嗎?
1# 使用 --columns 參數覆寫型別
2ingestr ingest \
3 --source-uri '...' \
4 --source-table 'public.data' \
5 --dest-uri '...' \
6 --dest-table 'raw.data' \
7 --columns 'id:bigint,name:string,amount:decimal(18,2)'
Q6:如何同步多張表?
1# 方法 1:使用 glob pattern
2ingestr ingest \
3 --source-uri '...' \
4 --source-table 'public.*' \
5 --dest-uri '...' \
6 --dest-table 'raw.*'
7
8# 方法 2:CDC 多表模式(PostgreSQL)
9ingestr ingest \
10 --source-uri 'postgres_cdc://...' \
11 --dest-uri '...' \
12 --dest-table 'cdc.*'
§11 總結與建議
11.1 專案成熟度評估
| 面向 | 評分 | 說明 |
|---|---|---|
| 活躍度 | ⭐⭐⭐⭐⭐ | 每日有 commit,每 1-2 天發版 |
| 程式碼品質 | ⭐⭐⭐⭐ | 清晰的模組化架構,有 lint / test 流程 |
| 文件完整度 | ⭐⭐⭐⭐ | 官方文件齊全,但進階用法較少範例 |
| 社群活力 | ⭐⭐⭐ | 團隊主導開發,外部貢獻者較少 |
| 資安表現 | ⭐⭐⭐⭐ | 已配置 gitleaks,無嚴重漏洞 |
| 生產就緒度 | ⭐⭐⭐⭐ | v1.0.x 穩定版,可用於生產 |
11.2 使用建議
推薦使用場景:
- Ad-hoc 資料搬遷(一次性或定期排程)
- CI/CD pipeline 中的資料初始化
- 從 SaaS API 拉資料到 data warehouse
- 開發/測試環境的資料準備
不推薦使用場景:
- 需要即時串流同步(建議用 Kafka / Debezium)
- 需要複雜轉換邏輯(建議用 dbt + ingestr 組合)
- 需要 GUI 管理的企業級方案(建議用 Airbyte / Fivetran)
11.3 與現有工具鏈的整合
1# 典型 Modern Data Stack 整合
2# 1. ingestr 負責 EL(Extract + Load)
3ingestr ingest --source-uri '...' --dest-uri 'bigquery://...'
4
5# 2. dbt 負責 T(Transform)
6dbt run --models staging.orders
7
8# 3. 排程用 cron / Airflow / GitHub Actions
11.4 注意事項
- 授權:FSL-1.1 不是傳統 OSS 授權,商業使用前請確認合規性
- Telemetry:預設會收集匿名使用資料,生產環境建議關閉
- Go 版本:需要 Go 1.25+,確認開發環境版本
- 供應鏈:292 個 Go 相依項目,建議使用
go mod verify驗證
Comments