PostgreSQL 14 → 18 升級筆記

環境資訊

  • 來源版本: PostgreSQL 14.12-alpine (Docker)
  • 目標版本: PostgreSQL 18-alpine (Docker)
  • 主機: Ubuntu (Snap 版 Docker)
  • 業務資料庫: d_cga, d_feyche, d_kumon, d_opal_auth, d_pinns, d_seesea

升級流程

1. 啟動 PostgreSQL 18 測試容器

cd ~/docker-postgresql

cat > docker-compose-test.yml << 'EOF'
services:
  postgres18:
    image: postgres:18-alpine
    restart: unless-stopped
    volumes:
      - postgres18_data:/var/lib/postgresql/data
    ports:
      - "5433:5432"
    environment:
      - POSTGRES_USER=root
      - POSTGRES_PASSWORD=YOUR_PASSWORD

volumes:
  postgres18_data:
EOF

docker compose -f docker-compose-test.yml up -d

2. 匯出並匯入 Role

# 從 14 匯出 role(包含密碼)
docker exec docker-postgresql-postgres-1 pg_dumpall -U root --roles-only > ~/pg_roles.sql

# 匯入到 18
docker exec -i docker-postgresql-postgres18-1 psql -U root -d postgres < ~/pg_roles.sql

注意: role "root" already exists 錯誤可忽略

3. 建立目標資料庫

# 逐一建立(PostgreSQL 不能在 transaction 內執行 CREATE DATABASE)
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "CREATE DATABASE d_cga;"
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "CREATE DATABASE d_feyche;"
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "CREATE DATABASE d_kumon;"
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "CREATE DATABASE d_opal_auth;"
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "CREATE DATABASE d_pinns;"
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "CREATE DATABASE d_seesea;"

4. 備份並還原資料

for db in d_cga d_feyche d_kumon d_opal_auth d_pinns d_seesea; do
  echo "備份並還原 $db ..."
  docker exec docker-postgresql-postgres-1 pg_dump -U root -d $db | \
    docker exec -i docker-postgresql-postgres18-1 psql -U root -d $db
done

5. 驗證資料

# 確認版本
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "SELECT VERSION();"

# 確認資料庫列表
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "\l"

# 確認 role
docker exec docker-postgresql-postgres18-1 psql -U root -d postgres -c "\du"

# 確認表數量
docker exec docker-postgresql-postgres18-1 psql -U root -d d_seesea -c "\dt" | tail -5

6. 切換正式環境

cd ~/docker-postgresql

# 停止測試容器
docker compose -f docker-compose-test.yml down

# 更新正式 docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
  postgres:
    image: postgres:18-alpine
    restart: always
    volumes:
      - docker-postgresql_postgres18_data:/var/lib/postgresql/data
    ports:
      - "${POSTGRES_PORT}:5432"
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

volumes:
  docker-postgresql_postgres18_data:
    external: true
EOF

# 停止舊的 14
docker compose down

# 啟動新的 18
docker compose up -d

保留舊版本(回滾用)

建立 docker-compose-bak.yml

services:
  postgres14:
    image: postgres:14.12-alpine
    restart: unless-stopped
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    ports:
      - "5434:5432"
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

啟動/關閉舊版:

# 啟動(port 5434)
docker compose -f docker-compose-bak.yml up -d

# 關閉
docker compose -f docker-compose-bak.yml down

常見問題

Q1: role "xxx_user" does not exist 錯誤

原因: 目標資料庫沒有對應的 role

解決: 先匯入 role 再匯入資料

docker exec docker-postgresql-postgres-1 pg_dumpall -U root --roles-only > ~/pg_roles.sql
docker exec -i docker-postgresql-postgres18-1 psql -U root -d postgres < ~/pg_roles.sql

Q2: CREATE DATABASE cannot run inside a transaction block

原因: PostgreSQL 不允許在 transaction 內執行 CREATE DATABASE

解決: 分開執行每個 CREATE DATABASE 語句

Q3: Snap 版 Docker bind mount 失敗

錯誤訊息: change mount propagation through procfd: open o_path procfd

原因: Snap 版 Docker 的 overlay2 storage driver 有限制

解決方案:

  1. 使用 named volume(推薦)
  2. 改用 apt 安裝 Docker(非 snap 版)

Q4: psql: error: database "root" does not exist

原因: 沒有指定資料庫

解決: 加上 -d postgres 參數

docker exec container_name psql -U root -d postgres -c "..."

系統資料庫說明

以下是 PostgreSQL 自帶的系統資料庫,不需要備份還原

資料庫用途
postgres預設管理資料庫
template0乾淨的原始模板,不可修改
template1建立新資料庫時的預設模板

相關指令速查

# 列出資料庫
\l

# 列出 role
\du

# 列出表
\dt

# 查看版本
SELECT VERSION();

# 列出 Docker volume
docker volume ls | grep postgres

# 查看容器
docker ps
404NOTE
404NOTE
文章: 45

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *