問題現象
在 Docker 容器內運行 FastAPI 應用程式,嘗試連接 Supabase PostgreSQL 資料庫時,出現以下錯誤:
socket.gaierror: [Errno -2] Name or service not known
Code language: CSS (css)使用的連線字串是 Supabase 提供的「直連格式」:
postgresql://postgres:[PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres
Code language: JavaScript (javascript)奇怪的是,同一個連線字串在本機開發環境可以正常連接,但在 Docker 容器內就失敗了。
問題原因
經過排查,發現問題出在 IPv6 與 DNS 解析:
Supabase 直連預設使用 IPv6
根據 Supabase 官方文檔:
Direct connections use IPv6 by default. If your environment doesn’t support IPv6, use Supavisor session mode or get the IPv4 add-on.
直連字串 db.[PROJECT-REF].supabase.co 解析出來是 IPv6 地址。
Docker 容器預設不支援 IPv6
大多數 Docker 環境預設沒有啟用 IPv6 網路,導致:
- DNS 查詢
db.[PROJECT-REF].supabase.co時只查詢 A 記錄(IPv4) - 但 Supabase 直連主機只有 AAAA 記錄(IPv6)
- 結果就是
Name or service not known
可以用以下指令驗證:
# 在容器內執行
nslookup db.[PROJECT-REF].supabase.co
# 回應:NXDOMAIN(找不到)
# 但 API endpoint 可以正常解析
nslookup [PROJECT-REF].supabase.co
# 回應:正常的 IPv4 地址
Code language: CSS (css)解決方案:使用 Supavisor Connection Pooler
Supabase 提供的 Supavisor 是一個連線池(Connection Pooler),有以下優點:
- 支援 IPv4:Supavisor 端點同時支援 IPv4 和 IPv6
- 連線池管理:自動管理資料庫連線,減少連線開銷
- 更好的擴展性:適合 Serverless 和容器化環境
Supavisor 兩種模式
| 模式 | Port | 適用場景 |
|---|---|---|
| Session Mode | 5432 | 持久連線,行為類似直連 |
| Transaction Mode | 6543 | Serverless,每次查詢後釋放連線 |
取得 Supavisor 連線字串
- 開啟 Supabase Dashboard
- 進入 Project Settings → Database
- 找到 Connection string 區塊
- 選擇 Session mode 或 Transaction mode
- 複製 URI 格式
連線字串格式會像這樣:
# Session Mode (port 5432)
postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres
# Transaction Mode (port 6543)
postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres
Code language: PHP (php)直連 vs Pooler 連線字串比較
# 直連(IPv6,Docker 內可能失敗)
postgresql://postgres:[PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres
# Pooler Session Mode(IPv4,推薦)
postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres
Code language: PHP (php)注意兩個關鍵差異:
- 主機名:
db.[REF].supabase.co→aws-0-[REGION].pooler.supabase.com - 用戶名:
postgres→postgres.[PROJECT-REF]
實際修改
原本的 .env(會失敗)
DATABASE_URL=postgresql://postgres:mypassword@db.[PROJECT-REF].supabase.co:5432/postgres
Code language: JavaScript (javascript)修改後的 .env(成功)
DATABASE_URL=postgresql://postgres.[PROJECT-REF]:mypassword@aws-1-ap-southeast-1.pooler.supabase.com:5432/postgres
Code language: JavaScript (javascript)修改後重啟應用程式,資料庫連線立即成功。
其他解決方案
如果你確實需要使用直連,還有以下選項:
方案 A:啟用 Docker IPv6
在 Docker 的 daemon.json 中啟用 IPv6:
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"
}
Code language: JSON / JSON with Comments (json)但這需要你的網路環境支援 IPv6,且設定較為複雜。
方案 B:購買 IPv4 Add-on
Supabase Pro 方案以上可以購買 IPv4 Add-on,讓直連也支援 IPv4。
但對於開發環境來說,使用免費的 Supavisor 是更實際的選擇。
總結
| 連線方式 | IPv4 支援 | 適用環境 |
|---|---|---|
| 直連 | 僅 IPv6(預設) | 支援 IPv6 的 VM、本機開發 |
| Supavisor Session | IPv4 + IPv6 | Docker、K8s、Serverless |
| Supavisor Transaction | IPv4 + IPv6 | Serverless、Edge Functions |
建議:在容器化環境(Docker、Kubernetes)中,一律使用 Supavisor Connection Pooler 的連線字串,避免 IPv6 相關的連線問題。
