Featured image of post Docker 內資料庫建立及連線說明

Docker 內資料庫建立及連線說明

說明 Docker Compose 環境下 PostgreSQL 連線字串的格式與每個欄位的意義,並解釋多個服務共用同一網路時資料庫名稱衝突的成因與解決方式。

自架服務用 Docker Compose 很常見,一直以來半路出家摸索,大多沒遇到什麼問題——直到把 blinko、linkwarden 和 ollama 整合到同一個內網(ollama-network)之後,才發現之前的做法其實暗藏隱患。

問題描述

每次更新 blinko 就很容易出現資料庫連線錯誤。看了 log、問了 AI 之後總算搞懂原因:

我把所有服務都放在同一個 Docker 網路,目的是讓支援 AI 的服務都能透過 http://ollama:11434 連接。這個想法本身沒問題,但問題出在資料庫命名

  • blinko 的 Postgres 服務內有一個叫 blinko 的資料庫
  • linkwarden 的 Postgres 服務內也有一個叫 postgres(或相同)的資料庫名稱

兩者放在不同網路時相安無事;一旦放進同一個網路,更新時 Docker 就可能解析到錯誤的資料庫容器,造成連線失敗。

解決方法很簡單:將各服務的 Postgres 容器名稱和資料庫名稱改為唯一、不重複的名稱即可。


1. PostgreSQL 連線字串格式說明

.envdocker-compose.yml 中常見這樣的連線字串:

DATABASE_URL=postgresql://blinko:Ui4VTuXgi0@blinko-postgres:5432/blinko

這是標準的 PostgreSQL 連線 URL,讓應用程式知道要去哪裡、用什麼身份連接資料庫。

1.1 格式結構

postgresql://<使用者名稱>:<密碼>@<主機名稱>:<埠號>/<資料庫名稱>

1.2 逐段說明

postgresql://blinko:Ui4VTuXgi0@blinko-postgres:5432/blinko 為例:

區塊說明
協定postgresql://表示使用 PostgreSQL 資料庫
使用者名稱blinko對應 POSTGRES_USER=blinko
密碼Ui4VTuXgi0對應 POSTGRES_PASSWORD正式環境應改用 .env 變數,避免硬編碼在設定檔中
主機名稱blinko-postgresDocker Compose 內部的服務名稱,不是 IP;同網路內的容器可直接用此名稱連線
埠號5432PostgreSQL 預設埠號
資料庫名稱blinko對應 POSTGRES_DB=blinko

1.3 實務補充

容器之間以服務名稱作為 DNS 是 Docker 的內建機制。 只要兩個容器在同一個 network 內,就可以直接用服務名稱互連,不需要指定 IP。

若要在本機(非 Docker 環境)測試,需將主機名稱改為 localhost

postgresql://blinko:Ui4VTuXgi0@localhost:5432/blinko

2. Docker Compose 範例

2.1 單一服務的 Postgres 定義

services:
  blinko-postgres:           # 服務名稱 = 容器間連線的 DNS 名稱,必須唯一
    image: postgres:14
    container_name: blinko-postgres   # 可自訂,不設定則由 Docker 隨機命名
    restart: always
    environment:
      POSTGRES_DB: blinko            # 資料庫名稱
      POSTGRES_USER: blinko          # 使用者帳號
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}   # 密碼從 .env 讀取
      TZ: Asia/Taipei
    volumes:
      - blinko-postgres-data:/var/lib/postgresql/data
    networks:
      - ollama-network

volumes:
  blinko-postgres-data:

networks:
  ollama-network:
    external: true

2.2 多服務共用同一網路時的命名建議

當多個服務(如 blinko 和 linkwarden)都在同一個網路下,務必確保每個服務的 Postgres 容器名稱和資料庫名稱都不同,避免 Docker DNS 解析錯亂:

services:
  # blinko 的資料庫
  blinko-postgres:
    image: postgres:14
    container_name: blinko-postgres
    environment:
      POSTGRES_DB: blinko
      POSTGRES_USER: blinko
      POSTGRES_PASSWORD: ${BLINKO_POSTGRES_PASSWORD}
    networks:
      - ollama-network

  # linkwarden 的資料庫
  linkwarden-postgres:
    image: postgres:14
    container_name: linkwarden-postgres
    environment:
      POSTGRES_DB: linkwarden
      POSTGRES_USER: linkwarden
      POSTGRES_PASSWORD: ${LINKWARDEN_POSTGRES_PASSWORD}
    networks:
      - ollama-network

對應的連線字串:

# blinko
DATABASE_URL=postgresql://blinko:${BLINKO_POSTGRES_PASSWORD}@blinko-postgres:5432/blinko

# linkwarden
DATABASE_URL=postgresql://linkwarden:${LINKWARDEN_POSTGRES_PASSWORD}@linkwarden-postgres:5432/linkwarden

重點:服務名稱(blinko-postgreslinkwarden-postgres)就是 Docker 內部的 DNS 名稱,名稱唯一才能確保每個應用程式連到正確的資料庫。