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):
- 第一个启动的应用执行完迁移后,
schema_migrations会记录版本001已完成 - 第二个应用启动时,检测到版本
001已存在,直接跳过迁移流程,导致对应表未创建
解决方案
方案1:统一管理迁移脚本(推荐)
将所有迁移脚本集中到独立目录,由专门的迁移服务统一执行,从根源避免版本冲突:
- 在项目根目录创建
shared-migrations文件夹,整合并调整迁移脚本版本号:- 保留
001_create_items_up.sql(原Items脚本) - 将原Order脚本重命名为
002_create_orders_up.sql
- 保留
- 修改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 - 创建
Dockerfile.migrate构建迁移镜像:FROM golang:1.22 RUN go install github.com/golang-migrate/migrate/v4/cmd/migrate@latest WORKDIR /migrations COPY . .
方案2:为应用指定独立迁移Schema
让两个应用使用不同的数据库Schema,隔离迁移版本记录:
- 修改Items应用的迁移代码,指定Schema:
同时在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) } }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 ); - 对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
相关产品推荐
相关产品推荐

