Communitygithub.com

lguidolin/zero-downtime-migrations

데이터베이스 스키마를 변경하면서 기존 데이터를 유지해야 할 때 사용합니다. 컬럼, 제약 조건, 인덱스 추가/제거/이름 변경 또는 데이터 백필 시 유용합니다.

zero-downtime-migrations란 무엇인가요?

이 스킬은 무중단 배포 환경에서 데이터베이스 스키마 마이그레이션을 안전하게 수행하기 위한 원칙과 패턴을 제공합니다. Kubernetes 롤링 업데이트와 같은 환경에서 이전 앱 버전과 새 앱 버전이 동시에 단일 데이터베이스를 공유하는 동안 호환성을 유지하는 데 초점을 맞춥니다. 핵심 접근 방식은 Expand(확장)/Contract(축소) 패턴으로, 변경 작업을 세 개의 릴리스로 나누어 수행합니다. 1) 새 구조를 추가하는 Expand, 2) 제한된 배치로 백필하고 듀얼 라이트를 수행하는 Migrate, 3) 이전 구조를 제거하는 Contract 단계로 구성됩니다. 또한 PostgreSQL 관련 위험 요소(예: NOT NULL 컬럼 추가, 인덱스 생성 시 CONCURRENTLY 사용, lock_timeout 설정 등)에 대한 구체적인 대처 방법을 제공합니다. 이 접근 방식은 데이터 손실이나 서비스 중단 없이 스키마를 진화시키고자 하는 모든 프로젝트에 권장되며, graphile-migrate와 같은 도구와 함께 사용될 수 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/lguidolin/agent-skills/tree/main/skills/zero-downtime-migrations

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

무중단 마이그레이션

개요

롤링 배포 중에도 실행 중인 시스템을 정상 상태로 유지하는 스키마 변경 규율입니다. 롤아웃 과정에서 기존 파드와 새 파드는 하나의 데이터베이스를 공유하므로, 스키마는 두 앱 버전과 동시에 호환되어야 합니다. 파괴적인 마이그레이션(migration)을 해당 배포와 함께 수행하는 것이 전형적인 자초한 장애 원인입니다.

작성 규칙 (모든 프로젝트)

  • 두 종류의 마이그레이션을 명확히 구분: 멱등성을 가진 current/ 세트(개발 반복 — 매 사이클마다 재실행, CREATE OR REPLACE/IF NOT EXISTS 사용, 객체는 최종 형태로, 생성 후 ALTER 없음)와 커밋된 마이그레이션(불변, 순서 있음, 실제로 배포되는 것). ALTER DEFAULT PRIVILEGES만 유일하게 허용된 인라인 ALTER입니다.
  • 소유권(ownership) 은 마이그레이션이 실행되는 방식에서 비롯되며, ALTER ... OWNER를 흩뿌리지 않습니다.
  • 단일 부트스트랩 진실 공급원 — 로컬/Docker 초기화 경로와 섀도우/테스트 DB가 동일한 진실 공급원을 공유합니다. 모든 환경이 동일하게 구축됩니다.

확장/축소 (병렬 변경)

적용 대상: 데이터베이스에 배포 시 유지되어야 할 데이터가 있는 경우(데이터가 있는 스테이징, 프로덕션). 면제: 로컬/초기화 친화적인 프로젝트 — 하지만 커밋된 마이그레이션은 이 규칙이 적용된다고 가정하고 작성하십시오. 그래야 프로모션 시 재작성이 필요 없습니다.

스키마 변경은 한 번에 하나가 아닌 세 개의 릴리스에 걸쳐 나누어 수행합니다.

  1. 확장(Expand) — 새로운 구조를 추가적으로, 이전 버전과 호환되게 추가합니다: 새로운 nullable 컬럼, 새로운 테이블, 새로운 함수. 앱 버전 N은 변경 없이 계속 실행됩니다.
  2. 마이그레이션(Migrate) — 제한된 배치(batch) 로 백필합니다(절대 테이블을 잠그는 단일 UPDATE 사용 금지). 필요 시 앱 N+1에서 듀얼 라이트(dual-write)를 수행하고, 읽기를 새 구조로 전환합니다. 지금 NOT NULL을 추가합니다(제약 조건을 NOT VALID로 추가한 후, VALIDATE를 별도로 수행).
  3. 축소(Contract) — 앱 N이 완전히 제거된 후에야 이후 릴리스에서 이전 컬럼/제약 조건을 제거합니다.

PostgreSQL 주의사항

주의사항안전한 접근 방식
변동성이 크거나 대규모 백필 기본값을 가진 NOT NULL 컬럼Nullable로 추가 → 배치 단위로 백필 → 제약 조건을 NOT VALID로 추가 → VALIDATE
제약 조건 추가먼저 NOT VALID로 추가한 후 VALIDATE CONSTRAINT 실행 (약한 락)
인덱스 구축CREATE INDEX CONCURRENTLY — 트랜잭션 내에서 실행 불가; 마이그레이션 도구의 트랜잭션 래핑과 분리하여 실행
프로덕션을 멈추게 하는 차단된 마이그레이션lock_timeout/statement_timeout 설정으로 빠르게 실패 처리
컬럼 이름 변경확장/축소 적용: 새 컬럼 추가 → 백필 → 읽기 전환 → 이전 컬럼 제거 (릴리스 분리)

프로덕션에서 "최종 형태 CREATE OR REPLACE"만으로 충분하지 않은 이유

그 규칙은 개발자 편의성을 위한 것이며 개발 환경에서는 올바릅니다. 그러나 실시간 사용자가 있는 프로덕션과 롤링 배포 환경에서는 두 앱 버전이 롤아웃 기간 동안 스키마를 공유합니다. 따라서 확장/축소가 변경을 안전하게 만드는 방법입니다. 이 둘을 혼동하지 마십시오.

전체 근거: 헌법 제17조, engineering-constitution/references/engineering-constitution.md에 번들로 포함되어 있습니다. 배포 파이프라인: cloud-delivery-aks.

Individual skills in this repo

This repo contains 18 individual skills — each has its own dedicated page.

lguidolin/change-hygiene-and-code-craft

Use when writing or refactoring code, structuring a commit or PR, or deciding whether to abstract duplication. Symptoms — mixing reorg with logic changes, a PR doing several things at once, a file growing large, the second copy of similar code, or unsure whether to DRY something up.

lguidolin/cloud-delivery-aks

Use when deploying to Kubernetes or Azure Kubernetes Service (AKS), configuring cloud secrets, setting up progressive rollout/canary, per-PR ephemeral environments, or k8s health probes. Keywords — Kubernetes, AKS, Key Vault, Argo Rollouts, Flagger, canary, blue-green, liveness, readiness, PodDisruptionBudget, HPA, rollback, GHCR.

lguidolin/commit-history-rewrite

Use when an existing repository has messy commit history that needs to conform to conventional commits before adopting release-please, or when intermediate WIP/fixup/merge commits need to be cleaned up.

lguidolin/conventional-commits-and-releases

Use when committing, writing a commit message, opening a PR that will be squash-merged, or configuring automated versioning/changelogs. Keywords — conventional commits, release-please, semver, feat/fix/chore, breaking change, changelog.

lguidolin/defense-in-depth-security

Use when handling untrusted input, secrets, authentication/authorization, or dependencies — or threat-modeling a new surface. Keywords — STRIDE, threat model, least privilege, secrets management, supply chain, dependency scanning, input validation, audit log, defense in depth.

lguidolin/designing-before-building

Use when starting a feature, fixing a non-trivial bug, or about to write implementation code — before any code exists. Symptoms you need this: "this is simple, I'll just code it", reaching for the editor before a design is approved, or an idea that hasn't been turned into a spec and plan.

lguidolin/engineering-constitution

Use when starting work in a project that follows the engineering constitution, orienting to its rules, or deciding which engineering practice applies to a task — spec writing, commits, testing, security, deploys, database, or UI work.

lguidolin/graphql-contract-testing

Use when writing a GraphQL query/mutation that the UI and a test will share, or building route/schema contract or smoke tests. Symptoms — copying a query into a test, a test asserting on query text, schema change that didn't break the UI build, or RLS/permission drift. Keywords — graphql-codegen, typed document, contract test, route smoke test.

lguidolin/init-repo-CI

Use when setting up a new repository with conventional commits, release-please, and CI automation, or when retrofitting an existing repository that lacks automated versioning and PR validation workflows.

lguidolin/interface-craft-and-accessibility

Use when building or styling UI — components, layouts, forms, design tokens — or making accessibility decisions. Keywords — a11y, WCAG, keyboard navigation, focus state, contrast, design system, minimalist UI, component reuse, ARIA, semantic HTML.

lguidolin/merge-gates-and-automation

Use when setting up or changing CI, pre-push hooks, or a task runner, or deciding what must pass before merge. Symptoms — tempted to put authoritative checks only in a local hook, skip CI, bypass with --no-verify, or unsure what gates a merge vs. runs locally.

lguidolin/observability-and-slos

Use when adding logging, metrics, tracing, health checks, SLOs, or alerting — or when building a service surface that needs to be operable and debuggable. Keywords — structured logs, OpenTelemetry, correlation id, RED metrics, liveness, readiness, SLI, SLO, error budget, alerting.

lguidolin/performance-and-scale

Use when working on hot paths, list endpoints, pagination, data-access in loops, or public interfaces/schemas. Symptoms — unbounded queries, N+1 access, no latency budget, optimizing without measuring, or changing an interface many consumers depend on. Keywords — pagination, N+1, Hyrum's Law, performance budget, bundle size.

lguidolin/postgres-postgraphile-rls-and-sql

Use when writing PostgreSQL, PostGraphile config, Row-Level Security policies, SQL schema files, or working on the Browser→App→PostGraphile→Postgres data path. Keywords — RLS, SECURITY DEFINER, search_path, pgSettings, grants, roles, GraphQL depth limit, query cost, statement_timeout, SQL file organization.

lguidolin/recording-decisions

Use when a design or architecture decision has been made and needs to be captured — writing a decision record or ADR, updating a decision index, noting a deferred idea, or superseding a past decision. Keywords — ADR, decision record, rationale, rejected alternatives, dependency index.

lguidolin/resilience-and-deploy-safety

Use when planning a deploy, designing a rollback, or responding to an incident or writing a postmortem. Keywords — deploy safety, rollback, immutable artifact, progressive delivery, canary, blast radius, incident response, blameless postmortem, error budget.

lguidolin/ship-it

Use when the user wants to ship work — push, PR, archive decision records, merge, and clean up. Handles the full lifecycle from committing final changes through post-merge cleanup including converting specs/plans to compact decision records.

lguidolin/tests-as-a-control

Use when writing or modifying tests, when a test breaks during a refactor, or when testing permission/role rules. Symptoms — tempted to edit a test to make it pass, testing only the happy path, a deny-test that started passing, flaky tests, or unsure what to assert.

관련 스킬