하우투 가이드의 독자는 이미 무엇을 하려는지 알고 옵니다.
“PostgreSQL을 9에서 14로 마이그레이션하려고 한다.” “Next.js 앱을 Cloudflare에 배포하려고 한다.” “도커 컨테이너에서 인증서를 자동 갱신하려고 한다.” 이런 사람들입니다. 그들에게 필요한 건 왜가 아니라 어떻게입니다. 그것도 가능한 한 가장 짧은 거리로.
하우투가 무너지는 가장 흔한 방식은 두 가지입니다. 첫째, 튜토리얼처럼 설명하기 시작합니다. 둘째, 분기를 잘못 다뤄 독자가 길을 잃습니다. 이번 편은 그 둘을 피하는 방법입니다.
하우투의 다섯 칸 골격
하우투는 다섯 칸으로 단순화할 수 있습니다.
각 칸을 한 번씩 짚습니다.
1. 목적 — 해낸 것을 명시
하우투의 제목은 과업 동사로 시작합니다. “PostgreSQL 마이그레이션”, “Cloudflare에 배포하기”, “인증서 자동 갱신”. 명사형 제목보다 동사형 제목이 검색에도 잘 잡힙니다.
첫 한 단락은 완료의 상태를 정의합니다.
이 가이드를 따라가면 PostgreSQL 9에서 14로 무중단 마이그레이션을 완료한 상태가 됩니다.
구체적으로:
- 기존 9 인스턴스가 read-only로 잠긴 상태
- 14 인스턴스가 동기화된 상태로 트래픽을 받는 중
- 롤백 절차가 준비되어 있는 상태
무엇이 끝난 상태인지가 명확할수록 독자는 자기가 어디로 가는지 압니다.
2. 전제 — 준비물을 명시
튜토리얼의 전제는 최소화하지만, 하우투의 전제는 정확하게입니다. 독자가 이미 무언가를 알고 있다고 가정해도 됩니다. 다만 무엇을 가정하는지를 명시합니다.
## 전제
- PostgreSQL 9.6 인스턴스가 동작 중
- pg_basebackup, pglogical에 익숙함 (몰라도 따라갈 수 있지만 시간이 더 걸립니다)
- 슈퍼유저 권한
- 충분한 디스크 (현재 데이터 크기 × 1.5)
전제가 빠지면 독자는 절반쯤 갔다가 막힙니다. 가장 큰 시간 낭비는 진작에 알았어야 할 것을 중간에 만나는 일입니다.
3. 단계 — 번호 + 동사 + 이유 한 줄
각 단계는 다음 세 부분을 갖습니다.
- 번호: 1, 2, 3 … 명확한 순서
- 동사로 시작하는 제목: “데이터베이스 백업하기”, “동기화 시작하기”
- 그 단계에서 왜 이걸 하는가 한 줄
### 3. pglogical 노드 등록하기
새 14 인스턴스를 기존 9 인스턴스의 subscriber로 등록합니다.
이 단계가 끝나면 두 인스턴스가 같은 데이터를 가지게 됩니다.
```sql
SELECT pglogical.create_subscription(
subscription_name := 'pg14_sub',
provider_dsn := 'host=pg9 port=5432 dbname=app user=replicator'
);
```
이유 한 줄이 있으면 독자는 자기가 왜 이걸 하는지 알고 진행합니다. 도중에 막혀도 무엇을 디버깅해야 하는지 판단할 수 있습니다.
4. 검증 — 실패 신호까지 함께
각 중요한 단계 끝, 그리고 글 전체의 끝에는 검증이 들어갑니다. 그리고 검증은 성공 신호와 실패 신호를 함께 다뤄야 좋습니다.
### 검증
다음 쿼리로 동기화 상태를 확인합니다.
```sql
SELECT * FROM pglogical.show_subscription_status();
```
**성공 신호**: `status` 컬럼이 `replicating`
**실패 신호**: `down` 또는 `disabled` — 이 경우 [트러블슈팅 섹션](#트러블슈팅)으로
실패 신호 없이 성공 신호만 적으면, 실패한 독자는 자기가 실패했다는 것조차 모르고 다음 단계로 갑니다. 이는 운영 환경에서 사고로 이어집니다.
5. 다음 행동 — 완료 후와 롤백
하우투의 끝에는 두 가지가 들어가야 합니다.
완료 후 무엇을 해야 하는가. 이 작업이 끝났다면 보통 그다음이 있습니다. “이제 클라이언트의 connection string을 바꾸세요” 같은 것.
롤백은 어떻게 하는가. 이 작업이 실패했을 때, 어떻게 되돌리는가. 이걸 작업을 시작하기 전에 알려주는 게 가장 좋습니다.
## 롤백
이 작업 중 문제가 발생하면 다음 절차로 9 인스턴스로 되돌립니다.
1. ...
2. ...
3. ...
롤백은 약 N분 안에 완료됩니다.
운영 작업의 하우투는 롤백 없이 출시되지 않아야 합니다.
다섯 칸을 한 페이지에 — PG 9 → 14 시뮬레이션
다섯 칸이 따로 떨어져 있으면 추상적입니다. 가상의 GreenDeck 데이터팀이 운영 중인 100GB 짜리 PostgreSQL을 9.6에서 14로 옮기는 하우투 한 장을 시뮬레이션해봅니다.
# PostgreSQL 9.6 → 14.x 무중단 마이그레이션 (자체 운영, pglogical 사용)
## 완료 후 상태
- 9.6 인스턴스: read-only, 24시간 대기 후 폐기
- 14.x 인스턴스: 트래픽 100%, 동기화 lag < 1s
- 롤백 스크립트: /ops/runbooks/pg-rollback.sh 위치
## 전제
- 데이터 크기 100GB, 디스크 여유 ≥ 150GB
- pglogical extension 양쪽 인스턴스 모두 설치 가능
- 슈퍼유저 권한, maintenance window 1시간
## 단계
1. 14.x 인스턴스 프로비저닝 (15분)
2. pglogical 노드 등록 (5분) — 두 노드가 같은 데이터를 가지게 됨
3. 초기 동기화 + 증분 따라잡기 (40분) — `replication_lag` 메트릭 모니터
4. 애플리케이션 connection string 교체 (1분) — 9.6은 read-only로 잠금
5. 24시간 관찰 후 9.6 폐기
## 검증
- 성공: `SELECT * FROM pglogical.show_subscription_status()` → status = replicating
- 실패: status = down → 롤백 절차로
## 롤백
1. connection string을 9.6으로 되돌림
2. 9.6의 read-only 잠금 해제
3. 14.x의 변경분은 폐기 (이 시점에서 5분 이내의 데이터 손실 허용 정책 적용)
이렇게 한 페이지에 모이면 글의 모양 자체로 하우투가 무엇인지 보입니다. 첫 화면에서 완료 상태가 보이고, 단계는 번호로 매겨졌고, 각 단계에 시간 추정이 있고, 검증과 롤백이 끝까지 같이 있습니다. 다섯 칸을 모두 채운 글은 시작도 끝도 명확합니다.
분기를 다루는 세 가지 방식
하우투가 망가지는 가장 흔한 두 번째 이유가 분기입니다. “Mac이면 X, Windows면 Y, 그런데 ARM이면 Z, …” 같은 분기가 단계마다 들어오면 글은 빠르게 미궁이 됩니다.
분기를 다루는 패턴은 셋입니다.
패턴 1: 초기에 갈라지고 곧 합류
OS, 패키지 매니저, 환경 같은 초기에만 갈라지는 분기는 첫 번째 단계 안에서 처리하고 합류시킵니다.
### 1. 의존성 설치
**Mac**:
```bash
brew install pgloader
```
**Ubuntu**:
```bash
apt install pgloader
```
### 2. 설정 파일 만들기
(여기부터는 두 OS 공통)
패턴 2: 글을 통째로 둘로 나누기
분기가 한 단계가 아니라 글 전체에 걸쳐 다르면, 그건 사실 다른 글입니다. 두 글로 나눕니다.
# PostgreSQL 마이그레이션 — 가이드 모음
상황에 맞는 가이드를 골라주세요.
- [9 → 14 (자체 운영)](./self-hosted.md)
- [AWS RDS PostgreSQL 9 → 14](./aws-rds.md)
- [Heroku Postgres 9 → 14](./heroku.md)
진입 페이지를 따로 두고, 각 가이드는 자기 경로에만 집중하게 합니다. 글 하나하나는 짧고 명확해집니다.
패턴 3 (금지): 매 단계 분기
가장 자주 보이고 가장 빠르게 글을 무너뜨리는 패턴입니다. 단계마다 OS, 환경, 버전을 분기해 글이 트리처럼 펼쳐집니다. 독자는 매번 자기가 어느 가지에 있는지 확인하느라 멈춥니다.
이 패턴을 발견하면 패턴 1 또는 패턴 2로 재구성합니다. 그래도 안 된다면 그 글은 사실 하우투가 아니라 레퍼런스에 가까운 글일 수 있습니다. ep.04에서 다룰 주제입니다.
탭 컴포넌트는 패턴 1의 UI 구현
요즘 Docusaurus·MkDocs Material·Starlight 같은 도구로 만든 문서를 보면 코드 블록 위에 Linux / Mac / Windows 또는 npm / yarn / pnpm 같은 탭이 붙어 있습니다. Docker 설치 가이드, Tailwind Installation, pnpm Installation이 대표적입니다. 탭은 본질적으로 패턴 1의 시각화입니다. 분기는 한 자리에서만 일어나고, 독자는 한 번 골라 뒤로는 같은 길로 갑니다.
탭을 쓸 때 두 가지를 지킵니다.
선택을 페이지 전체에 동기화합니다. Docusaurus의 groupId, MkDocs Material의 linked content tabs, Starlight의 syncKey 같은 기능이 있어서 한 곳에서 Mac을 고르면 같은 페이지의 모든 탭이 Mac으로 맞춰집니다. 이 동기화가 없으면 독자는 8단계까지 내려가는 동안 내가 지금 어느 탭이더라를 매번 확인하게 되고, 이는 패턴 3을 UI로 위장한 것에 지나지 않습니다.
탭 안의 내용은 명령어 한두 줄 차이여야 합니다. 탭마다 흐름이나 개념이 달라진다면 그건 패턴 1이 아니라 패턴 3입니다. 그 경우는 솔직하게 패턴 2로 글을 나눕니다. “탭이 있으니 한 글 안에서 다 다룰 수 있다”는 착각이 가장 흔히 글을 무너뜨립니다.
공개 문서가 분기를 자르는 방식
두 곳의 공개 문서가 분기를 어떻게 다루는지 보면 위의 패턴이 더 또렷해집니다.
- AWS의 re:Post / Knowledge Center: “How do I …?” 형식의 글이 수천 편 쌓여 있지만, 각 글은 한 시나리오에 한 답입니다. RDS인지 Aurora인지, MySQL인지 PostgreSQL인지가 다르면 글이 통째로 다릅니다. 진입 페이지에서 서비스·엔진·시나리오로 골라 들어가게 만들어 패턴 2를 극단까지 밀어붙인 형태입니다.
- Kubernetes의 Tasks 섹션: “Configure a Pod to Use a ConfigMap” 같은 글들은 단계 안에서 클러스터 종류·CRI·CNI를 분기하지 않습니다. 대신 Before you begin 단락에서 “Kubernetes 클러스터와 그에 연결된 kubectl이 있어야 한다”고 환경을 못박고, 본문은 표준
kubectl명령으로 한 길만 갑니다. 분기를 글 안이 아니라 글 바깥(다른 Task 문서·Concept 문서)에 둔 것입니다.
두 사례 모두 핵심은 글 한 편 안에서는 분기를 최소화한다는 것입니다. 분기는 더 많은 짧은 글로 푸는 게 더 적은 긴 글로 푸는 것보다 거의 항상 낫습니다.
하우투가 망가지는 다른 지점들
분기 외에도 자주 무너지는 지점들이 있습니다.
-
설명을 끼워 넣는다.
”참고로 이 명령은 내부적으로 …” 같은 문장이 들어오면 글이 갑자기 늘어지고, 독자는 작업을 멈춥니다. 설명은 ep.05의 글로 빼고, 여기선 링크만 둡니다. -
실패 가능성을 무시한다.
”이 명령을 실행하면 됩니다”로 끝나는 하우투는 모든 게 다 잘 됐을 때만 동작합니다. 실패할 수 있는 단계에는 “X 에러가 보이면 …” 같은 트러블슈팅을 같이 둡니다. -
버전이 명시되지 않는다.
”PostgreSQL을 업그레이드하기”는 6개월 뒤 무용지물이 됩니다. “PostgreSQL 9.6 → 14.x”로 적어두면 1년 뒤에도 어디까지 유효한지 압니다. -
검증 없이 끝난다.
”끝!”으로 끝나는 하우투는 독자가 정말 성공했는지 확인할 길이 없습니다. 마지막 검증 단계를 빼먹지 않습니다. -
롤백 없이 위험한 작업이 적힌다.
데이터 삭제, 권한 변경, 인프라 변경처럼 되돌릴 수 없는 작업은 롤백 또는 되돌릴 수 없음에 대한 경고를 명시합니다.
검증을 도구로 박는다
검증 단계를 글로만 두지 말고 명령으로 박아두면 거짓말이 되기 어렵습니다. 두 가지 도구가 자주 어울립니다.
- smoke test 한 줄: 배포·마이그레이션 끝에
curl -f https://api.example.com/healthz처럼 실패 시 종료 코드가 0이 아닌 명령을 둡니다. 글에서 “헬스체크가 OK여야 합니다” 한 문장보다, 복사해 붙일 수 있는 한 줄이 신뢰도를 올립니다.curl -f는 HTTP 4xx·5xx에서 비-제로로 종료하므로 CI 단계에 그대로 끼울 수 있습니다. - GitHub Actions의
matrix: 같은 검증을 여러 환경에서 자동으로 돌려보고 싶다면strategy.matrix로 OS·런타임 버전을 풀면 됩니다. 하우투 본문에는 결과 표 한 장과 워크플로 파일 링크만 두고, 매트릭스의 모든 분기는 CI가 책임지게 합니다. 글에서 분기를 치우는 또 다른 방법입니다.
이렇게 검증을 도구로 박아두면, 6개월 뒤 환경이 바뀌어 가이드가 거짓말이 되는 순간 CI가 먼저 깨집니다. 글의 거짓말을 사람이 발견할 때까지 기다리지 않아도 됩니다.
좋은 예와 나쁜 예
같은 작업의 짧은 발췌입니다.
나쁜 예
## Postgres 마이그레이션
Postgres를 마이그레이션하려면 먼저 백업을 해야 하는데, 백업은 pg_dump를
쓸 수도 있고 pg_basebackup을 쓸 수도 있습니다. pg_dump는 논리적 백업이라
크기가 크고 시간이 오래 걸리지만 호환성이 좋고, pg_basebackup은 물리적 백업이라
빠르지만 같은 버전에서만 됩니다. 어차피 마이그레이션이니까…
```bash
pg_dump > backup.sql
```
그러면 백업이 되고, 새 인스턴스에서 복원하면 됩니다.
문제: 첫 단락이 비교 설명입니다. 명령어가 추상적입니다(DB 이름이 없음). 어떤 결과가 정상인지 표시가 없습니다. 다음 단계와 검증이 없습니다.
좋은 예
## PostgreSQL 9.6 → 14.x 마이그레이션 (자체 운영)
이 가이드는 자체 운영 환경에서 PostgreSQL 9.6 인스턴스를 14.x로
마이그레이션하는 절차입니다. 완료 후 상태:
- 9.6 인스턴스가 read-only로 잠긴 상태
- 14.x 인스턴스가 트래픽을 받는 상태
- 약 5분 이내의 다운타임
**소요 시간**: 데이터 100GB 기준 약 2시간
**전제**: 슈퍼유저 권한, 디스크 ≥ 데이터 크기 × 1.5
### 1. 백업 받기
마이그레이션 *전*에 논리 백업을 받습니다. 문제가 생기면 이 백업으로 복원합니다.
```bash
pg_dump -U postgres -F c -d app > /backup/app-$(date +%F).dump
```
**검증**: 파일이 생성되었고 크기가 0이 아니면 OK.
```bash
ls -lh /backup/app-*.dump
```
### 2. 새 인스턴스 준비
(다음 단계로 계속)
차이가 보입니다. 완료 후 상태가 명시되어 있습니다. 시간과 전제가 위에 있습니다. 왜 이걸 하는지가 단계 안에 한 줄로 들어 있습니다. 검증이 명령어로 실행 가능합니다.
템플릿
# [동사로 시작하는 과업 제목]
[이 가이드를 따라가면 무엇이 끝나는지 한두 문장]
**완료 후 상태**:
- [상태 1]
- [상태 2]
- [상태 3]
**소요 시간**: 약 [N]분 / [기준]
**전제**:
- [필요한 권한·환경·지식]
## 1. [동사 제목]
[이 단계에서 무엇을 *왜* 하는지 한 줄]
```[언어]
[명령 또는 코드]
```
**검증**: [성공 신호]
**실패 신호**: [실패의 모습] → [어디로 가야 하는지]
## 2. [동사 제목]
...
## 검증 (최종)
[전체가 끝났음을 확인하는 방법]
## 롤백
[문제가 생겼을 때 되돌리는 절차]
## 다음 행동
- [완료 후 자연스럽게 이어지는 작업]
- [관련 가이드]
체크리스트
- 제목이 동사로 시작하는가
- 첫 단락에 완료 후 상태가 정의되어 있는가
- 전제(권한·환경·지식·시간)가 위쪽에 명시되어 있는가
- 각 단계가 번호 + 동사 + 이유 한 줄을 갖추고 있는가
- 분기가 단계마다 펼쳐지지 않는가 (패턴 1 또는 2를 따랐는가)
- 각 중요한 단계에 검증이 있는가
- 실패 신호가 함께 적혀 있는가
- 버전·환경이 명시되어 있는가
- 되돌릴 수 없는 작업에 롤백 또는 경고가 있는가
- 마지막에 다음 행동이 있는가
참고 자료
- Procida, D. Diátaxis: How-to guides. https://diataxis.fr/how-to-guides/
- Bloch, J. R., Lambourne, J., & Bhatti, D. (2021). Docs for Developers. Apress.
- Microsoft. Style Guide: Procedures. https://learn.microsoft.com/en-us/style-guide/procedures-instructions/
다음 편 예고
다음 편은 레퍼런스입니다. 가장 조용한 문서. 작업 중인 사람이 정확한 사실을 찾으러 오는 글입니다. docstring부터 OpenAPI까지, 사람이 쓰는 것과 자동 생성하는 것의 경계를 살펴봅니다.