Files
document-haness/docs/keycloak-session-store/tech-log-studio/operations-that-report-success/decision/decision-put-the-reload-in-a-deploy-hook.md
T
DongHyeonkaandClaude Opus 5 2109f726fe feat(pipeline): keycloak-session-store 25편·virtualization 59편을 S3→S5→S6 으로 돌린다
기록 84편을 계약 에이전트로 다시 썼다. 기존 71편(kss 25 · virt 46)과, 계약에만
있고 안 쓰여 있던 새 글감 13편이다. 원장 84개를 열어 단계마다 스킬 영수증과 관문
종료 코드를 적었고 verify-pipeline-run.py 가 error 0 으로 닫는다.

SSOT 결함 둘을 고쳤다.

- kss 의 `약 58일` 이 반입 중 `약 59일` 로 바뀌어 있었다. 원 증거 파일이
  「남은 일수: 88일 … 실제 갱신까지 약 58일」로 산수를 직접 적는다. D-4a 쪽
  `약 59일` 은 강제 갱신 뒤(`VALID: 89 days`)라 맞는 값이라 그대로 뒀다.
- virt §198 의 `11.6GB` 는 §178 의 원 측정 `Mem: 11648`(MiB)과 어긋나는데
  원 가이드의 표기 그대로라 고치지 않고 쓰이는 자리에 대조를 적었다.

기록의 수치 오류 셋을 고쳤다 — CASE 요약의 「게스트 셋에 8240MB」(5120+3120 은
둘이다), k3s 편이 같은 것을 여섯·일곱·여덟로 세던 것, no-docker 편의 「셋을 더
든다」(§281 의 표는 네 행이고 디스크 행이 빠져 있었다).

계약을 셋 고쳤다.

- kss 의 sourceRepository 리비전이 cdac9b8 이었는데 그 커밋에는 docs/guides/**
  28개가 아예 없다. 9465582b 로 바꾸고, 반입한 바이트가 어느 커밋과도 같지 않다는
  것을 측정값과 함께 적었다 — 반입은 커밋이 아니라 그 시점의 작업 트리에서 떠 온
  것이다(kss 297/306 · virt 12/14 가 작업 트리와 같고, 200 커밋을 거슬러 전수
  대조했을 때 가장 가까운 커밋도 28개가 어긋났다).
- virt 계약이 「2026-09-11 재배분」이라고 적는데 SSOT 는 재배분 날짜를 적지 않고
  재배분 뒤 값은 이미 2026-09-10 측정에 찍혀 있다.
- kss 후보 대장이 지나친 절 아홉에 처분을 적었다(warn 9 → 0). 새 글감은 0건이고
  넷은 앵커가 h3 슬러그의 접두가 아니라 중간 토막이라 검사기가 못 본 것이었다.

style_profile.mjs 의 결함 둘을 고쳤다 — frontmatter 가 문장으로 세어져
(실측 398자짜리 「문장」 하나) 평균 길이를 기준 안으로 밀어 올리고 있었고,
engPerSent 의 분자는 목록을 포함한 글에서, 분모는 목록을 걷어낸 글에서 세고
있었다(Question 기록에서 11.94 → 3.86).

verify-pipeline.py 전 항목 PASS · error 0 · unittest 334건 OK.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:01:55 +09:00

5.9 KiB

kind, slug, title, topic, topicName, project, status, decisionStatus, source, sourceRevision, evidence
kind slug title topic topicName project status decisionStatus source sourceRevision evidence
PROJECT_DECISION put-the-reload-in-a-deploy-hook reload 를 사람이 아니라 deploy 훅이 부르게 한다 operations-that-report-success 운영 절차의 완료 판정 — 백업 · 판올림 · Secret · 인증서 갱신 keycloak-session-store 게시 전 ADOPTED
final/document.md#선택이-코드와-흐름에-반영되는-방식-d4a
cdac9b8178391311d8eca1ebc6cac15bb62d79af
../../../final/evidence/raw/d4-certificate-renewal__13-verdict.txt
../../../final/evidence/raw/d4a-deploy-hook__01-hook-verified.txt
../../../final/evidence/raw/d4a-deploy-hook__02-certbot-with-hook.txt
../../../final/evidence/raw/d4a-deploy-hook__03-after-state.txt

reload 를 사람이 아니라 deploy 훅이 부르게 한다

인증서 갱신 뒤의 nginx reload 를 사람이 아니라 certbot deploy 훅이 부르게 정했다. 사람이 치던 절차로 두었을 때 갱신에서 서빙까지 2305초가 비었고, 훅을 넣은 뒤에는 1~2초였다.

근거

  • 새 인증서가 디스크에 있고 38분 25초 동안 옛 인증서가 나갔다 사람이 치는 절차로 뒀을 때의 공백 2305초를 잰 기록이다. 이 결정이 고르지 않은 쪽을 실제로 재 본 값이 거기 있다.
  • deploy 훅 하나가 그 공백을 1~2초로 줄였다 이 결정대로 훅을 설치하고 갱신에서 서빙까지를 다시 잰 기록이다.
  • 적용됐는지는 로그 문구가 아니라 상태로 판정한다 훅이 실제로 reload 를 걸었는지를 무엇으로 가릴지, 이 결정이 따르는 기준을 적은 기록이다.
  • 갱신 타이머가 실제 갱신에서도 도는가 이 결정을 강제 갱신에서만 확인했다는 것을 열린 질문으로 남긴 기록이다.

결정문

인증서를 갱신한 뒤의 nginx reload 는 /etc/letsencrypt/renewal-hooks/deploy/ 에 설치한 훅 파일이 부른다. 사람이 손으로 reload 를 치는 절차로 두지 않는다.

훅의 내용은 두 줄이고 nginx -t && nginx -s reload 다.

판단 이유

nginx 는 인증서를 기동 시점에 읽어 메모리에 들고 있는데, certbot 은 인증서 파일의 경로가 아니라 live/ 심볼릭 링크가 가리키는 대상을 갈아끼운다. 그래서 갱신이 끝나도 nginx 설정은 멀쩡해 보이고 옛 인증서가 계속 나간다. 고칠 것은 설정이 아니라 reload 를 부르는 경로인데, 이 실험대에서는 그 경로가 셋 다 비어 있었다. certbot-renew.service 에 ExecStartPost 가 없었고 certbot 에 nginx 플러그인도 설치돼 있지 않았다. renewal-hooks 아래 pre 와 deploy 와 post 세 디렉터리도 모두 비어 있었다.

사람이 치는 절차로 두는 대안은 반사실이 아니라 D-4 에서 실제로 관측했다. 새 인증서가 디스크에 기록되고 서빙이 바뀌기까지 2305초, 38분 25초가 비었고 그 reload 를 부른 것은 자동화가 아니라 사람이었다. 그 38분은 우연히 짧았을 뿐이고, 아무도 치지 않았다면 다음 nginx 재시작까지 옛 인증서가 나갔을 것이다.

훅을 놓을 디렉터리는 셋 중 하나였다. pre 는 갱신을 시도하기 전에 돌아서 새 인증서가 나오기 전이고, post 는 갱신 여부와 무관하게 매번 돈다. 타이머가 하루 두 번 도니 post 에 넣으면 갱신이 없는 날에도 nginx 를 하루 두 번 reload 하게 된다. deploy 는 certbot 이 RENEWED_LINEAGE 를 넘겨줄 때, 즉 실제로 갱신했을 때만 돈다.

두 줄 중 앞의 nginx -t 도 같은 종류의 안전장치다. 설정이 깨진 상태에서 nginx -s reload 를 보내면 마스터가 새 워커를 못 띄우는데, -t 로 먼저 검사해 통과할 때만 reload 하면 실패했을 때 옛 워커가 그대로 서비스를 계속한다. 인증서는 안 바뀌지만 서비스는 죽지 않는다. 이 순서 하나가 「인증서가 안 바뀐다」와 「사이트가 내려간다」를 가른다.

훅을 설치하고 강제 갱신을 다시 돌리자 갱신에서 서빙까지가 1~2초로 줄었다. 워커 PID(process ID, 프로세스 번호)는 사람이 걸었을 때의 28829 에서 37252 로 바뀌었다.

영향

  • 갱신에서 서빙까지는 훅이 없던 D-4 에서 2305초, 훅을 넣은 D-4a 에서 1~2초였다. 두 값은 회차마다 한 번씩 잰 것이라 같은 조건에서 되풀이해 잰 값이 아니다.
  • 이 훅은 인증서를 세우는 구축 절차에 들어간다. 원 가이드가 「이 훅은 구축 절차에 들어가야 한다. 사후에 붙이는 것이 아니다」라고 적었다. D-4 가 잰 2305초의 공백은 훅이 없어서 생긴 것이라, 그 훅은 인증서를 처음 세울 때 같이 놓였어야 했다.
  • 되돌리기는 훅 파일을 지우는 한 줄이지만 지우지 않는다. 훅은 결함을 고치는 파일이라 지우면 D-4 의 상태로 돌아가고, 그 결함은 다음 실제 갱신(약 59일 뒤)에, 증상은 그 뒤 인증서 만료로 나타난다.
  • certbot 은 훅이 성공해도 Hook 'deploy-hook' ran with error output 이라고 찍는다. 훅의 실제 출력은 test is successful 과 signal process started 이고, 그 문구가 붙은 까닭은 nginx 의 types_hash 경고가 stderr 로 나갔기 때문이다. certbot 은 stderr 에 무엇이든 있으면 이 문구를 붙이고, 그 경고 자체는 types_hash_max_size 기본값에서 오는 것이라 갱신과 무관하다. 로그에서 error 를 grep 하는 감시를 걸면 성공한 훅을 실패로 오독한다.
  • 확인은 --force-renewal 로 한 강제 갱신에서만 했다. certbot-renew.timer 가 스스로 갱신하는 경로에서도 같은 훅이 도는지는 아직 재지 않았다.
  • 훅이 거는 reload 가 진행 중이던 요청을 끊지 않는지는 재지 않았다. 무중단을 확인한 측정은 D-4 에서 사람이 손으로 건 reload 를 잰 값이다.