Ismét a Go fejlesztői eszközkészletet bővítjük. PostgreSQL adatbázist szeretnénk használni és sémamigrációkat kezelni a Go-projektünkben, amit docker-compose és make segítségével viszünk véghez.
Laravel-alkalmazásfejlesztés során épp elégszer használtam már migrációkat, tehát az elvüket és a hasznukat jól ismerem. Az itt bemutatott módszer tulajdonképp nyelv- és környezetfüggetlen.
Először is vegyük elő a PostgreSQL és pgAdmin futtatására összeállított docker-compose.yml
konfigfájlunkat, melyet most bővítünk.
version: "3"
services:
postgres:
image: postgres:12
restart: always
environment:
POSTGRES_DB: ${DB_DATABASE}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
PGDATA: /var/lib/postgresql/data
ports:
- "${DB_PORT}:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
pgadmin:
image: dpage/pgadmin4
restart: always
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
ports:
- "${PGADMIN_PORT}:80"
volumes:
- pgadmin-data:/var/lib/pgadmin
depends_on:
- postgres
migrate:
image: migrate/migrate
restart: "no"
profiles: ["one-off"]
volumes:
- ./migrations:/migrations
depends_on:
- postgres
volumes:
postgres-data:
pgadmin-data:
Mi változott:
- A fontos paraméterek helyére változók kerültek, ezek a .env-ből jönnek.
- Megjelent a migrate konténer.
A következő lépésben elkészítjük a Makefile
fájlt, szintén bővítve az egyszerű kezdetit. Itt már jobban kidomborodik a make
és a .env
értelme.
include .env
DB_URI_PASS = $(shell perl -MURI::Escape -e 'print uri_escape($$ARGV[0])' "${DB_PASSWORD}")
DB_URI = "postgres://${DB_USER}:${DB_URI_PASS}@postgres:${DB_PORT}/${DB_DATABASE}?sslmode=disable"
.PHONY: build run clean pg-up pg-down pg-shell pg-migrate-up pg-migrate-rollback help
build: ## Build the binary. (Default target.)
GOARCH=amd64 GOOS=linux go build -o ${MAKE_BINARY_NAME} ${MAKE_MAIN_NAME}
run: ## Run the code.
@go run ${MAKE_MAIN_NAME}
clean: ## Clean up.
go clean
rm -f ${MAKE_BINARY_NAME}
pg-up: ## Start the required docker containers.
docker-compose --file docker-compose.yml --env-file .env \
up --detach
pg-down: ## Stop the docker containers.
docker-compose --file docker-compose.yml \
down
pg-shell: ## Open the psql shell.
docker-compose --file docker-compose.yml \
exec postgres \
psql -U ${DB_USER} -w ${DB_DATABASE}
pg-migrate-up: ## Run the db migrations.
@docker-compose --file docker-compose.yml \
run --rm migrate \
-path /migrations/ -database ${DB_URI} \
up
pg-migrate-rollback: ## Roll back the last db migration.
@docker-compose --file docker-compose.yml \
run --rm migrate \
-path /migrations/ -database ${DB_URI} \
down 1
help:
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9_-]+:.*?## / {printf "\033[36m%-38s\033[0m %s\n", $$1, $$2}' Makefile
Vegyük sorra az újdonságokat:
- DB_URI_PASS: URL-kódoljuk (percent-encoding) a jelszót a Postgres URI-hoz, amelyet a migrate használ majd. Perl meghívásához szükség van a
shell
parancsra, valamint az$ARGV[0]
escape-elendő, hogy azt a make ne tekintse változónak, ezért szerepel dupla $. - pg-up és pg-down: Explicit módon adtuk meg a
docker-compose.yml
és.env
inputokat: noha ezek az alapértelmezettek, itt lehetünk bőbeszédűek. Csak a postgres és a pgadmin konténereket akarjuk indítani, ezek szolgáltatások, melyek a háttérben futnak. Újabb verziójú, 3.9+ compose fájlban a profiles segítségével könnyen szabályozható, mit indítson az up. Ehhez 1.27+ docker-compose kell. Előtte meg kellett adni az up alparancsnak az indítandó szolgáltatások nevét. - pg-shell: Van ugyan pgAdmin GUI-nk, de legyen shell elérésünk is. A jelszót környezeti változóból veszi a psql.
- pg-migrate-up és pg-migrate-rollback: A migrate konténert parancsként használjuk, egyelőre kettőt definiáltunk. Az
up
a nevükben up-ot tartalmazó sql fájlokat végrehajtva felépíti a sémát, adown
a nevükben down-t tartalmazó sql fájlokat végrehajtva lebontja a sémát. Mivel visszavonni szinte mindig csak az utolsó migrációt akarjuk, ezértdown 1
lett a rollback. - help: Ez egy jó trükk a kommentelt targetek listázására.
A migrate
további lehetőségeit illetően lásd a golang-migrate/migrate GitHub-repót, illetve azon belül a PostgreSQL tutoriált.
A migrációkat érdemes lehet idempotens módon elkészíteni1 (if [not] exists
), amellett, hogy inkrementálisak és reverzibilisek. Mivel szövegfájlokról van szó, így természetesen verziózhatók is.
A migrációs sql fájlok helyének a ./migrations/
mappát adtuk meg (bind mount). Nézzünk néhány példát:
000001_create_users_table.up.sql
:
create table if not exists users (
id serial primary key,
email varchar (255) unique not null,
password varchar(255) not null,
created_at timestamp default current_timestamp not null
);
000001_create_users_table.down.sql
:
drop table if exists users;
000002_add_username_column.up.sql
:
alter table users
add column if not exists username varchar(50) unique not null;
000002_add_username_column.down.sql
:
alter table users
drop column if exists username;
Végezetül a .env
fájlunk tartalma:
MAKE_MAIN_NAME=hello-world.go
MAKE_BINARY_NAME=bin/hello-world
DB_PORT=5432
DB_DATABASE=mydb
DB_USER=root
DB_PASSWORD=root
PGADMIN_PORT=8080
PGADMIN_EMAIL=myemail@address.com
PGADMIN_PASSWORD=root
A .env
soha ne kerüljön git repóba,2 vegyük fel a .gitignore
-ba. Hozzunk létre egy .env.example
fájlt olyan (kamu)adatokkal, amelyek fejlesztéshez megfelelhetnek. Ez alapján könnyen létrehozható a .env
.
Tehát mit értünk el? Így néz ki a projektmappánk:
$ tree -a --dirsfirst
.
├── bin
│ └── hello-world
├── migrations
│ ├── 000001_create_users_table.down.sql
│ ├── 000001_create_users_table.up.sql
│ ├── 000002_add_username_column.down.sql
│ └── 000002_add_username_column.up.sql
├── docker-compose.yml
├── .env
├── .env.example
├── hello-world.go
└── Makefile
És például így futtathatjuk a frissen klónozott forrást (telepített go
és docker-compose
előfeltételekkel):
$ cp .env.example .env && chmod go= .env && nano .env
$ make pg-up
$ make pg-migrate-up
$ make run
Természetesen a Makefile
receptjei tetszés szerint módosíthatók, de az ennyiből is látszik, hogy sokat nyertünk.
-
Eric Hosick: Start Treating Your SQL as a First-Class Language with Idempotent SQL DDL. medium.com, 2022-05-19. ↩︎
-
Basti Ortiz: Please don’t commit .env. dev.to, 2019-02-03. ↩︎