You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker中Golang多服务PostgreSQL迁移异常:仅单表创建

Docker环境下多Golang应用PostgreSQL迁移冲突问题解决

问题现象

两个Golang应用(Items、Order)通过golang-migrate工具执行PostgreSQL迁移时,仅先启动的容器能成功创建对应数据库表,后启动的应用无法生成自身表:

  • Items应用迁移脚本为001_create_items_up.sql,负责创建items表
  • Order应用迁移脚本为001_create_order_up.sql,负责创建orders表
  • 先启动items-service则orders表无法创建,先启动orders-service则items表无法创建

核心原因

golang-migrate依赖数据库内的schema_migrations表记录已执行的迁移版本号。两个应用的迁移脚本使用了相同的版本号(001):

  1. 第一个启动的应用执行完迁移后,schema_migrations会记录版本001已完成
  2. 第二个应用启动时,检测到版本001已存在,直接跳过迁移流程,导致对应表未创建

解决方案

方案1:统一管理迁移脚本(推荐)

将所有迁移脚本集中到独立目录,由专门的迁移服务统一执行,从根源避免版本冲突:

  1. 在项目根目录创建shared-migrations文件夹,整合并调整迁移脚本版本号:
    • 保留001_create_items_up.sql(原Items脚本)
    • 将原Order脚本重命名为002_create_orders_up.sql
  2. 修改docker-compose配置,添加专属迁移服务:
    version: '3.8'
    services:
      postgres:
        image: postgres:13
        environment:
          POSTGRES_USER: user
          POSTGRES_PASSWORD: password
          POSTGRES_DB: dbname
        ports:
          - "5432:5432"
        volumes:
          - /database:/var/lib/postgresql/data  # 修正原配置的路径错误
      migrate:
        build:
          context: ./shared-migrations
          dockerfile: Dockerfile.migrate
        depends_on:
          - postgres
        command: ["migrate", "-path", "/migrations", "-database", "postgres://user:password@postgres:5432/dbname?sslmode=disable", "up"]
      items-service:
        build: 
          context: /items
          dockerfile: Dockerfile
        depends_on:
          - migrate
      orders-service:
        build: 
          context: /order
          dockerfile: Dockerfile
        depends_on:
          - migrate
    
  3. 创建Dockerfile.migrate构建迁移镜像:
    FROM golang:1.22
    RUN go install github.com/golang-migrate/migrate/v4/cmd/migrate@latest
    WORKDIR /migrations
    COPY . .
    

方案2:为应用指定独立迁移Schema

让两个应用使用不同的数据库Schema,隔离迁移版本记录:

  1. 修改Items应用的迁移代码,指定Schema:
    package main
    
    import (
        "log"
    
        "github.com/golang-migrate/migrate/v4"
        _ "github.com/golang-migrate/migrate/v4/database/postgres"
        _ "github.com/golang-migrate/migrate/v4/source/file"
    )
    
    func main() {
        m, err := migrate.New(
            "file://migrations",
            "postgres://user:password@postgres:5432/dbname?sslmode=disable&search_path=items_schema",
        )
        if err != nil {
            log.Fatalf("migration failed to initialize: %v", err)
        }
        if err := m.Up(); err != nil && err != migrate.ErrNoChange {
            log.Fatalf("migration failed: %v", err)
        }
    }
    
    同时在Items的迁移脚本开头添加Schema初始化:
    CREATE SCHEMA IF NOT EXISTS items_schema;
    SET search_path TO items_schema;
    
    CREATE TABLE IF NOT EXISTS items (
        id SERIAL PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        description TEXT,
        price DECIMAL NOT NULL
    );
    
  2. 对Order应用执行相同操作,使用orders_schema:
    • 修改迁移代码中的search_path为orders_schema
    • 在Order的迁移脚本开头添加Schema初始化语句

方案3:修改迁移版本号避免冲突

直接为两个应用的迁移脚本设置不重复的版本号:

  • Items应用保留001_create_items_up.sql
  • Order应用将脚本重命名为002_create_orders_up.sql
    这样两个应用的迁移版本号无重叠,启动时都会执行对应的迁移操作

额外注意点

原docker-compose中postgres的volume路径错误,/var/lib/postgresql_data应改为/var/lib/postgresql/data,否则postgres无法正确持久化数据。

内容的提问来源于stack exchange,提问作者Chelbos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:43:22