本文へ移動
cccskills
無料GitHub で公開

ubuntu1-deploy

ubuntu1 배포/재배포/롤아웃, second-brain 이미지 빌드·compose up·마이그레이션 배포를 할 때 사용. rsync 경로·이미지 태그·실행 이미지 ID 대조·백업까지 체크리스트로 강제한다.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md9.9 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

언제 쓰나

  • "ubuntu1에 배포해줘" / "재빌드해줘" / "롤아웃해줘" 같은 요청
  • second-brain 이미지(server/collector/mcp/web) 빌드 후 ubuntu1 compose 스택 갱신
  • 마이그레이션 파일 추가 후 배포 (자동 적용됨 — 아래 5번 참고)

핵심 전제: ubuntu1:~/second-brain-app는 git 리포가 아니라 로컬 리포의 rsync 사본이다. 로컬에서 커밋해도 ubuntu1에는 반영되지 않는다 — 반드시 rsync로 밀어야 한다. compose에는 build: 섹션이 없어 이미지 태그만 참조하므로, 로컬에서 빌드한 이미지를 올리는 게 아니라 ubuntu1 서버 위에서 직접 빌드한다.

사전점검 체크리스트 (착수 전)

  • 이번 배포가 데이터 변형 마이그레이션을 포함하는가? → 포함하면 4번(백업) 필수
  • ssh ubuntu1 'bash -l -s' 로그인 셸로 접속 가능한가 (로그인 셸 없으면 PATH/env 깨짐)
  • 로컬 macOS rsync는 openrsync다 — -az(+웹은 -R)만 쓸 것, rsync 3.x 전용 옵션(--info=stats2 등)은 0바이트 실패 유발
  • Go 변경과 웹 변경을 같은 rsync 명령에 섞지 않는다 (경로 평탄화 사고 재발 방지, 사고 사례 2 참고)
  • ubuntu1:~/second-brain-app/docker-compose.ubuntu1.yml은 리포의 deploy/ubuntu1-stack/docker-compose.yml과 별도 관리 — compose 변경이 있으면 ubuntu1 쪽도 수동 갱신
  • 빌드 태그가 compose가 참조하는 이름과 정확히 일치하는지 사전 확인 (second-brain-<svc>:ubuntu1)
  • 개인데이터(SMS·통화·메일 본문, API 키) 출력 금지 — 검증은 집계·개수·해시로만

단계별 명령

1. Go 소스 전송

rsync -az --exclude '.git' cmd internal migrations go.mod go.sum Dockerfile FOR-AGENTS.md ubuntu1:~/second-brain-app/

2. 웹 소스 전송 (Go와 분리된 명령, 반드시 -R)

rsync -azR --exclude node_modules --exclude .next \
  web/src web/package.json web/bun.lock web/next.config.ts web/tsconfig.json web/Dockerfile \
  ubuntu1:~/second-brain-app/

전송 직후 메인 Dockerfile이 덮이지 않았는지 확인:

ssh ubuntu1 "grep -cE '^FROM .* AS (server|collector|mcp)' ~/second-brain-app/Dockerfile"
# 결과가 3이 아니면 즉시 중단 — web/Dockerfile이 메인 Dockerfile을 덮어썼을 가능성 (사고 사례 2)

3. 이미지 빌드 (ubuntu1 위에서 — compose에 build: 섹션 없음, 직접 빌드)

ssh ubuntu1 'bash -l -s' <<'EOF'
cd ~/second-brain-app
docker build --target server -t second-brain-server:ubuntu1 .
docker build --target collector -t second-brain-collector:ubuntu1 .
docker build --target mcp -t second-brain-mcp:ubuntu1 .
docker build -f web/Dockerfile -t second-brain-web:ubuntu1 web/
EOF

태그는 deploy/ubuntu1-stack/docker-compose.yml(및 ubuntu1의 docker-compose.ubuntu1.yml)이 참조하는 이름과 한 글자도 다르면 안 된다. 다른 태그로 빌드하면 up -d가 옛 이미지를 그대로 재시작하고도 정상처럼 보인다 (사고 사례 1).

4. (데이터 변형 마이그레이션이 있을 때만) 배포 전 백업

ssh ubuntu1 'bash -l -s' <<'EOF'
mkdir -p ~/backups
docker exec second-brain-postgres sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -t documents -t chunks -Fc' \
  > ~/backups/pre-<마이그레이션번호>-$(date +%Y%m%d-%H%M).dump
EOF

사후 대조를 위해 배포 전 집계 SQL(예: SELECT count(*), source_type FROM documents GROUP BY source_type) 결과도 같이 남겨둔다.

5. 기동

ssh ubuntu1 'bash -l -s' <<'EOF'
cd ~/second-brain-app
docker compose --env-file .env.local -f docker-compose.ubuntu1.yml up -d <서비스...>
EOF

--env-file을 빠뜨리면 환경변수가 비어 들어간다. 마이그레이션은 server 기동 시 RunMigrations가 자동 실행한다 — 추적 테이블이 없어 매 부팅마다 전체 재실행되므로 마이그레이션 SQL은 반드시 멱등해야 한다.

검증 체크리스트 (헬스체크로 대체 불가)

1순위 — 이미지 ID 대조 (다른 모든 검증보다 먼저 실행)

ssh ubuntu1 'bash -l -s' <<'EOF'
for svc in server collector mcp web; do
  running=$(docker inspect -f '{{.Image}}' second-brain-ubuntu1-${svc}-1)
  built=$(docker images -q second-brain-${svc}:ubuntu1)
  echo "${svc}: running=${running} built=${built}"
done
EOF

running과 built가 다르면 배포 실패다. up -d 출력에 Recreated가 없고 Starting/Started만 있었다면 이 신호다. 헬스체크·엔드포인트 200 응답은 옛 이미지도 통과하므로 증거로 인정하지 않는다.

  • 이미지 ID 일치 (위 명령)
  • ~/bin/verify-mounts.sh; echo exit=$? → exit=0
  • server 로그에 migration applied / server listening
  • 워커·수집기 로그에 첫 tick 확인
  • API 스모크 테스트 (응답 본문은 화면에 출력하지 말고 상태 코드·결과 건수만 확인)

q 없는 /api/v1/search는 search.ValidateQueryInput이 400으로 거부해 스모크로 쓸 수 없다(#285). 무해한 단어를 넣어 200과 결과 건수만 본다.

ssh ubuntu1 'bash -l -s' <<'EOF'
cd ~/second-brain-app
AUTH="Authorization: Bearer $(grep '^API_KEY=' .env.local | cut -d= -f2-)"
curl -s -H "$AUTH" \
  'http://127.0.0.1:8081/api/v1/search?q=%ED%9A%8C%EC%9D%98&limit=1' \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print("count:", d.get("count"))'
EOF
  • (선택) v0.25.1 입력 검증 확인 — NUL 바이트가 400인지 (search.ValidateQueryInput, #282)
ssh ubuntu1 'bash -l -s' <<'EOF'
cd ~/second-brain-app
AUTH="Authorization: Bearer $(grep '^API_KEY=' .env.local | cut -d= -f2-)"
curl -s -o /dev/null -w '%{http_code}\n' -H "$AUTH" \
  'http://127.0.0.1:8081/api/v1/search?q=a%00b&limit=1'
EOF

기대값: 400. 다른 값이면 v0.25.1 입력 검증이 배포 이미지에 없다는 뜻이다.

  • (선택, 이미지 ID 대조가 MATCH일 때만 실행) GraphQL 순환 fragment 400 확인 (#282)

경고: 이 요청은 graphql-go 검증기의 무한 재귀 버그(순환 fragment에서 스택 오버플로 → 복구 불가 → 프로세스 종료)를 건드린다. v0.25.1 이전 이미지(AST 가드 미적용)에 보내면 서버 프로세스가 죽는다. 위 "1순위 — 이미지 ID 대조"가 MATCH임을 먼저 확인한 뒤에만 실행할 것.

ssh ubuntu1 'bash -l -s' <<'EOF'
cd ~/second-brain-app
AUTH="Authorization: Bearer $(grep '^API_KEY=' .env.local | cut -d= -f2-)"
curl -s -o /dev/null -w '%{http_code}\n' -H "$AUTH" -H 'Content-Type: application/json' \
  -d '{"query":"query { ...A } fragment A on Query { ...B } fragment B on Query { ...A }"}' \
  'http://127.0.0.1:8081/api/v1/graphql'
EOF

기대값: 400(AST 가드가 실행 전에 거부). 요청이 멈추거나 응답이 없으면 즉시 컨테이너 상태(docker ps)를 확인할 것 — 프로세스가 죽었을 수 있다.

  • (백업했다면) 배포 후 집계가 사전 집계와 기대한 방향으로만 달라졌는지 대조

사고 사례 (2026-09-19 야간, 같은 절차 5회 반복 중 발생)

사고 1 — 태그 오기로 옛 이미지 재시작을 "배포 완료"로 오보

docker build -t second-brain-ubuntu1-server:latest .처럼 compose가 참조하지 않는 이름으로 빌드 → up -d가 옛 이미지를 그대로 재시작 → 헬스체크·엔드포인트가 정상 응답해 배포 완료로 보고. 실제로는 골든셋 폴백·분류 큐 수정 2건이 미배포 상태였다.

신호: up -d 출력에 Recreated 없이 Starting/Started만 있음. 방어: 검증 1순위(이미지 ID 대조)를 항상 먼저 실행.

사고 2 — rsync 경로 평탄화로 메인 Dockerfile 덮어쓰기

rsync -az cmd internal ... web/src web/Dockerfile ubuntu1:~/second-brain-app/처럼 Go와 웹 파일을 한 명령에 섞어 상대경로(-R) 없이 전송 → 마지막 경로 요소만 남아 web/Dockerfile이 루트의 메인 Dockerfile을 덮어쓰고 web/src가 루트 src/로 흩어짐 → 빌드 시 target stage "server" could not be found.

신호: 빌드 에러 target stage "X" could not be found, 또는 루트에 낯선 src/ 디렉토리 생성. 방어: Go/웹 rsync 명령을 분리하고 웹은 반드시 -R, 전송 후 grep -cE '^FROM .* AS (server|collector|mcp)' Dockerfile이 3인지 확인.

롤백

이미지 문제 (사고 1 유형): 직전 정상 배포 시점의 이미지가 로컬(ubuntu1)에 남아있다면 재태깅 후 재기동.

ssh ubuntu1 'bash -l -s' <<'EOF'
docker tag second-brain-server:ubuntu1 second-brain-server:ubuntu1-broken   # 실패한 이미지 보관
docker tag <이전_정상_이미지_ID> second-brain-server:ubuntu1
cd ~/second-brain-app && docker compose --env-file .env.local -f docker-compose.ubuntu1.yml up -d server
EOF

이전 이미지가 이미 삭제됐다면 로컬 리포에서 배포 직전 커밋으로 되돌려 1~3단계를 다시 수행한다.

데이터 문제 (마이그레이션 부작용): 4단계에서 만든 덤프로 복원. 복원 전 사전 집계와 현재 상태를 비교해 실제로 롤백이 필요한 사고인지(예상된 변화가 아닌지) 먼저 확인한다.

ssh ubuntu1 'bash -l -s' <<'EOF'
docker compose --env-file .env.local -f docker-compose.ubuntu1.yml stop server collector mcp
docker exec -i second-brain-postgres pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists < ~/backups/pre-<번호>-<타임스탬프>.dump
docker compose --env-file .env.local -f docker-compose.ubuntu1.yml up -d
EOF

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Pre-action boundary checking — validates agent tool calls against declared capabilities and task contracts

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Auto-detect project context and optimize harness — deactivate unused agents/skills, suggest missing experts, generate project profile

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Adversarial code review using attacker mindset — trust boundary, attack surface, business logic, and defense evaluation

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Apache Airflow best practices for DAG authoring, testing, and production deployment

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Alembic migration patterns for naming conventions, safety checks, expand-contract, env.py configuration, and CI integration

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

Pre-routing ambiguity analysis — scores request clarity and asks clarifying questions when needed (inspired by ouroboros)

日本語の概要は準備中です。原文の説明を表示しています。

baekenough/second-brain152026年10月8日 更新

baekenough のスキルをすべて見る

このスキルの問題を報告する