docs(TechLog): 주제 7~10 을 다시 쓴다

주소가 게시 시점에 굳어 저장되는 구조, 축 링크를 두 번 옮긴 순서, 한글 slug 가
간헐적으로 보인 두 가지 어긋남을 표로 갈랐다. 화면이 실패를 없음으로 그릴 때 작성
도구에서 왜 더 오래 숨는지, Promise.all 이 거절과 던짐에서 다른 경로를 타는 이유를
채웠다. CSS module 이 왜 전역 규칙에 닿지 않는지, 403 과 404 가 원인을 어떻게
좁혔는지도 적었다.

link-audit.py 를 감사 Case 의 evidence 로 걸어 배정한 증거 하나를 메웠다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-09-07 19:06:20 +09:00
co-authored by Claude Opus 5
parent 193da20d09
commit b1653dbba8
15 changed files with 204 additions and 92 deletions
@@ -61,7 +61,13 @@ Dockerfile 이 그 경고를 문자 그대로 적어 두고 있는데도 빠뜨
인자를 넘기지 않으면 기본값이 들어간다. 그 기본값은 존재하지 않는 주소다.
## 요구하는 인자 전부
## 빌드도 배포도 성공한다
빌드는 인자가 없어도 성공한다. 이미지도 정상적으로 올라오고 파드도 healthy 다.
드러나는 곳은 배포본이 첫 요청을 낼 때다. 브라우저가 존재하지 않는 호스트로 요청을 보내고, 화면은 데이터를 받지 못한다.
Dockerfile 이 그 경고를 문자 그대로 적어 두고 있었는데도 빠뜨렸다.
```text
APP_PROFILE=production
@@ -76,8 +82,10 @@ SOURCE_DATE_EPOCH
`kubectl rollout undo` 로 이전 리비전으로 되돌린 뒤 인자를 넣어 다시 빌드하고 다시 올렸다.
되돌리는 것이 빨랐던 이유는 이전 이미지가 클러스터에 아직 있어서다. 레지스트리가 없어도 롤아웃 이력은 남으므로, 이미지를 다시 import 하지 않고 태그만 되돌리면 된다.
## 확인하지 못한 것
빌드가 이 인자를 요구하도록 막지 않았다. 빠뜨리면 여전히 빌드는 성공하고 배포본만 틀린다. 인자 목록을 적어 두고 메모리에 한 건 남긴 것으로 그쳤다 — `techlog-deploy-runtime-api-base.md`.
빌드가 이 인자를 요구하도록 막지 않았다. 빠뜨리면 여전히 빌드는 성공하고 배포본만 틀린다. 지금 남은 것은 인자 목록을 적어 둔 것과 메모리 하나다.
<!-- body:end -->
@@ -62,17 +62,28 @@ tech-log-frontend : 83409be
헬스 판정은 헬스 엔드포인트가 응답하는지를 본다. nginx 프로세스가 살아 있고 그 경로를 돌려주면 통과한다.
SPA 가 부팅에 필요한 설정 파일은 그 판정에 들어 있지 않다.
SPA 가 부팅에 필요한 설정 파일은 그 판정에 들어 있지 않다. 그래서 파드는 healthy 로 올라오고 사이트만 안 된다.
## 빌드가 쓴 권한
빌드가 그 파일을 0600 으로 쓴다. 파일을 만든 사용자만 읽을 수 있고, nginx 를 돌리는 사용자는 다른 사용자다.
빌드가 그 설정 파일을 0600 으로 쓴다. 파일을 만든 사용자만 읽을 수 있고, nginx 를 돌리는 사용자는 다른 사용자다.
증상이 404 가 아니라 403 이라는 것이 원인을 좁혔다. 404 면 파일이 없는 것이고 403 이면 파일은 있는데 읽지 못하는 것이므로, 이미지에 파일이 들어갔는지부터 확인할 필요가 없었다.
이미지가 권한을 정규화하도록 고쳤다.
## 브라우저가 묻는 주소
같은 배포에서 favicon 도 404 였다. `index.html``public/favicon.svg` 를 참조한 적이 없다. 파일은 이미지에 들어 있었고 nginx 도 서빙했지만, 브라우저는 참조가 없으면 `/favicon.ico` 를 묻는다. 그 이름의 파일이 없어 404 를 받고 기본 아이콘으로 떨어졌다.
같은 배포에서 favicon 도 404 였는데 원인이 달랐다. `index.html``public/favicon.svg` 를 참조한 적이 없다.
파일은 이미지에 들어 있었고 nginx 도 서빙했다. 브라우저는 참조가 없으면 `/favicon.ico` 를 묻고, 그 이름의 파일이 없어 404 를 받고 기본 아이콘으로 떨어졌다.
| | 파일이 이미지에 있나 | nginx 가 서빙하나 | 무엇이 문제였나 |
|---|---|---|---|
| 설정 파일 | o | o | 권한이 0600 이라 읽지 못함 |
| favicon | o | o | 아무도 그 이름을 요청하지 않음 |
둘 다 「파일이 없다」가 아니었고, 그래서 이미지를 열어 파일을 찾는 방식으로는 둘 다 정상으로 보였다.
## 확인하지 못한 것
@@ -37,15 +37,13 @@ source:
→ kube-system 의 containerd import Job → kubectl set image
```
공개 Hub 는 소스가 들어간 이미지라 쓸 수 없다. k3s 의 containerd 소켓은 root 전용이라 사용자 셸에서 닿지 않는다. 그래서 클러스터 안에 일회성 Job 을 띄워 tar 를 import 한다.
## 배포 단위가 하나다
공개 Hub 는 소스가 들어간 이미지라 쓸 수 없다. k3s 의 containerd 소켓은 root 전용이라 사용자 셸에서 닿지 않는다. 그래서 클러스터 안에 일회성 Job 을 띄워 tar 를 import 한다 — Job 은 클러스터 권한으로 도므로 그 소켓에 닿는다.
배포 단위는 `hyeonworks.com` 하나이고 서브도메인을 쓰지 않는다. 공개는 `/`, API 는 `/api` 다.
## 무엇이 이미지 안에서 굳는
## 빌드 인자는 이미지에 굳는
빌드 인자는 이미지에 굳는다. 런타임 환경 변수가 아니므로 배포한 뒤에 바꿀 수 고, 잘못 넣으면 다시 빌드해서 다시 올려야 한다.
이 경로에서 설정은 두 가지 방식으로 들어간다. 런타임 환경 변수 배포한 뒤에 바꿀 수 고, 빌드 인자는 이미지에 굳어 다시 빌드해야 바뀐다.
프론트 이미지가 요구하는 인자는 이만큼이다.
@@ -58,14 +56,26 @@ CI_RUNNER_IMAGE=node@sha256:… ← 반드시 @sha256 다이
SOURCE_DATE_EPOCH
```
넘기지 않으면 기본값이 굳는다. 빌드는 성공하고 이미지도 정상적으로 올라오므로, 잘못된 값은 배포본이 요청을 내보낼 때 처음 드러난다.
백엔드 이미지는 Dockerfile 이 `src/` 아래에 있고 `RELEASE_VERSION`·`BUILD_VERSION`·`GIT_SHA`·`SOURCE_URL` 을 받는다. 태그는 짧은 SHA 일곱 자이고 배포된 것과 맞춰야 한다.
## 빌드 산출물에 커밋 해시가 들어간다
백엔드 빌드 산출물 이름에 커밋 해시가 들어간다. 작업 트리가 더러우면 해시가 달라져 stale 산출물 검사가 멈춘다. 커밋한 뒤에 빌드를 돌려야 한다.
백엔드 빌드 산출물 이름에 커밋 해시가 들어간다. 작업 트리가 더러우면 해시가 달라져 stale 산출물 검사가 멈추므로, 커밋한 뒤에 빌드를 돌려야 한다.
이 순서는 산출물이 어느 커밋에서 나왔는지를 이름으로 추적하려고 둔 것이다. 그래서 순서를 지키지 않으면 검사가 통과하지 않고, 검사를 끄면 추적이 사라진다.
## 이 경로가 늦게 알려 주는 것
컨테이너 안의 파일 권한, nginx 가 서빙하기로 한 파일 목록, 빌드에 굳은 주소는 전부 이 단계 뒤에 드러난다.
이미지가 healthy 로 올라오는 것과 사이트가 동작하는 것은 다르다.
| 무엇이 | 언제 드러나나 |
|---|---|
| 컨테이너 안의 파일 권한 | 그 파일을 처음 요청할 때 |
| nginx 가 서빙하기로 한 파일 목록 | 목록에 없는 파일을 요청할 때 |
| 빌드에 굳은 주소 | 배포본이 그 주소로 요청을 낼 때 |
셋 다 헬스 판정을 지난다. 헬스 엔드포인트는 그 파일도 그 목록도 그 주소도 쓰지 않기 때문이다.
<!-- body:end -->