我在 Docker 内的两个用 Golang 编写的应用程序之间迁移 PostgreSQL 时遇到问题。 仅创建一个表,该表首先通过 Docker 容器迁移。
我使用迁移实用程序。第一个应用程序是“Items”,第二个应用程序是“Order”。在这些应用程序的每个目录中都有“migrations”文件夹。在“Items/migrations”内部分别有001_create_items_up.sql和“down”,在“order/migrations”内部有001_create_order_up.sql。 如果先启动“items”容器,则不会创建“order”表,反之亦然。
001_create_items_up.sql
CREATE TABLE IF NOT EXISTS items (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL NOT NULL
);
001_create_order_up.sql
CREATE TABLE IF NOT EXISTS orders (
id SERIAL PRIMARY KEY,
item_id INT NOT NULL,
quantity INT DEFAULT 1
);
两个应用程序的 Dockerfile
FROM golang:1.22 as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o service .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/service .
COPY --from=builder /app/migrations /root/migrations
CMD ["./service"]
Docker 组合
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
items-service:
build:
context: /items
dockerfile: Dockerfile
depends_on:
- postgres
orders-service:
build:
context: /order
dockerfile: Dockerfile
depends_on:
- postgres
应用程序“items”和“order”的代码
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",
)
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)
}
}
您使用的工具 go-migrate 假设每个数据库都有一个目录。它将数字标识符(递增数字或日期时间)存储在表中以确定数据库的版本,因此它知道要做什么。
如果您使用递增数字(就像您在问题中所做的那样),当您的第二个服务启动时,migrate 会认为所有迁移都已执行。
如果您使用日期时间(正如您根据@DavidMaze的评论尝试的那样),您会发现迁移可能会发现数据库的版本比您的最高版本高
up
,因此,请尝试降级,却发现没有down
脚本。
解决此问题的方法是使用 x-migrations-table 选项指示 migrate 使用 different 表来跟踪两个不同应用程序的迁移。
所以你的
main
会变成这样:
func main() {
m, err := migrate.New(
"file://migrations",
"postgres://user:password@postgres:5432/dbname?sslmode=disable&x-migrations-table=orders-service-schema",
)
// your error handling and what not
}