Когда я начал поднимать PostgreSQL через Docker для своих проектов, всё выглядело просто: описал сервис в docker-compose.yml, запустил контейнер — база доступна.
Проблемы начались, когда я начал запускать миграции вместе с контейнерами. Иногда миграции стартовали раньше чем PostgreSQL успевал принять подключения, и приложение падало с ошибкой подключение к базе данных.
С опытом я пришел к более удобному варианту. Сначала запускал сам контейнер с базой и уже далее делал миграции. Так проще контролировать процесс, легче отлаживать ошибки и понятнее, что именно происходит с базой. Для миграций в своих Go-проектах я использовал goose.
goose — это инструмент для работы с миграциями базы данных. Его можно использовать как CLI-утилиту из терминала или подключить как Go-пакет и запускать миграции из кода. В этой статье я покажу вариант с запуском миграций через CLI-утилиту.
Для начала установим goose как CLI-утилиту:
go install github.com/pressly/goose/v3/cmd/goose@latest
После установки можно проверить, что команда доступна:
goose --version
Далее рассмотрим такую структуру проекта и покажу где я буду хранить миграции и как создать файлы для миграций:
my-app/├── cmd/│ └── app/│ └── main.go├── migrations/├── docker-compose.yml├── Makefile├── go.mod└── go.sum
В папке migrations будут лежать SQL-файлы миграций. Каждый такой файл описывает изменение схемы базы: создание таблицы, добавление колонки, создание индекса и так далее.
goose -dir migrations create create_users sql
Флаг -dir указывает папку, где нужно создать файл миграции. create_users — это название миграции, а sql означает, что миграция будет написана обычным SQL.
В docker-compose.yml опишем вот такой контейнер для запуска PostgreSQL:
services: postgres: image: postgres:16-alpine container_name: go_postgres environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: app_db ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/datavolumes: postgres_data:
Сам запуск контейнера здесь подробно разбирать не буду: для этого достаточно выполнить docker compose up -d. Основной фокус статьи — запуск миграций. Запускать свои миграции я буду через Makefile вот так он выглядит внутри:
DB_URL=postgres://postgres:postgres@localhost:5432/app_db?sslmode=disableMIGRATIONS_DIR=migrations.PHONY: migrate-up migrate-down migrate-status migrate-createmigrate-up:goose -dir $(MIGRATIONS_DIR) postgres "$(DB_URL)" upmigrate-down:goose -dir $(MIGRATIONS_DIR) postgres "$(DB_URL)" downmigrate-status:goose -dir $(MIGRATIONS_DIR) postgres "$(DB_URL)" statusmigrate-create:goose -dir $(MIGRATIONS_DIR) create $(name) sql
В моём случае goose запускается с хост-машины, поэтому в DB_URL я использую localhost. Если запускать миграции из другого контейнера внутри docker-compose, вместо localhost нужно будет указать имя сервиса — postgres.
Далее после запуска нашего контейнера базы данных мы уже применить наши миграции. и мы просто должны написать:
make migrate-up
После запуска можете проверить статус:
make migrate-status
Теперь миграции запускаются отдельным шагом после старта PostgreSQL. Поэтому мы не попадаем в ситуацию, когда goose пытается подключиться к базе раньше, чем она готова принимать соединения..
ссылка на оригинал статьи https://habr.com/ru/articles/1040802/