docs(guides): bring the seven setup guides in line with the practitioner skill
The guides were written before the skill existed and a scored audit found
three gaps. Fixed by a subagent running under the skill, with measured
values, versions, IPs and quoted output declared off limits.
The big one: every step showed a command and its output, and almost none
said which line to look at or what it meant. 64 interpretation pairs added
across the seven files, weighted where the reading is hardest — 20 in the
Keycloak stage, where a Secret existing and a pod having received it are
different facts.
Only the extracting form of curl appeared. Where the reader meets a response
for the first time the guides now open with curl -I or curl -v and name the
lines worth reading; -w '%{http_code}' survives only where the code is a
value being compared — two upstream nodes against each other, or the 900-run
control loop.
Listing Secret keys went from a three-stage pipe to kubectl describe secret,
which prints the key names and their byte counts in one native command
without exposing a value.
And a tool assumption: jq and yamllint are installed on neither the lab host
nor the guests. The guides now say so where JSON is read by eye, rather than
sending the reader to install something mid-diagnosis. cloud-init schema is
on the guests and is now the guest-side check.
Also removes a stray Playwright screenshot committed at the repository root
in 919547a; the evidence copy under docs/evidence/b7a-orphan-session/ is the
one the document references.
Four things the audit left standing are recorded in the agent's report rather
than papered over — notably that 04's reload measurements are stated without
a reproduction procedure, and that 05 and 06 reference each other as
prerequisites.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
88b7bd4bf0
commit
8062cc9a19
@@ -85,25 +85,107 @@ sudo ln -s /etc/nginx/sites-available/keycloak-lab /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
**`&&` 가 중요하다.** 설정이 깨진 상태에서 reload 하면 nginx 가 새 워커를
|
||||
띄우지 못한다. `-t` 를 먼저 통과시키고 그때만 reload 한다.
|
||||
**어디를 봐야 하는가** — `nginx -t` 가 내놓는 **마지막 줄**이다. `syntax is
|
||||
ok` 와 `test is successful` 두 마디가 다 나와야 통과다. 앞에 나오는
|
||||
`[warn]` 줄(예: `types_hash_max_size`)은 통과를 막지 않는다 — 04 에서 이
|
||||
경고를 실패로 오독하는 일이 실제로 벌어지므로, 여기서 **경고와 오류를
|
||||
구분하는 눈**을 들여 둔다. 실패면 `[emerg]` 줄에 파일과 줄 번호가 찍힌다.
|
||||
|
||||
**이 결과가 의미하는 것** — 통과했으면 `&&` 뒤의 reload 가 이어서 돌고,
|
||||
`systemctl reload` 는 아무 말 없이 끝난다(무소식이 좋은 소식이다). 실패했으면
|
||||
`&&` 가 reload 를 **막아 준 것**이고, 지금 돌고 있는 nginx 는 옛 설정 그대로
|
||||
멀쩡하다. 설정이 깨진 상태에서 reload 하면 새 워커를 못 띄운다 — `-t` 를
|
||||
먼저 통과시키고 그때만 reload 하는 이유다.
|
||||
|
||||
reload 가 정말 반영됐는지는 워커가 갈렸는지로 본다. 같은 판정 방법을
|
||||
04 에서 인증서 갱신에 그대로 쓴다.
|
||||
|
||||
```bash
|
||||
systemctl status nginx --no-pager | head -20
|
||||
```
|
||||
|
||||
**어디를 봐야 하는가** — `Active:` 줄이 `active (running)` 인가, 그리고 그
|
||||
아래 프로세스 트리에 `nginx: master process` 하나와 `nginx: worker process`
|
||||
여럿이 붙어 있는가. 워커 줄의 **PID** 를 눈에 담아 둔다.
|
||||
|
||||
**이 결과가 의미하는 것** — reload 는 마스터를 그대로 두고 **워커만** 갈아
|
||||
끼운다. 그래서 reload 전후로 워커 PID 가 바뀌면 새 설정이 실제로 적용된
|
||||
것이고, 안 바뀌었으면 `-t` 는 통과했는데 reload 가 안 간 것이다.
|
||||
04 에서 인증서 갱신이 서빙까지 닿았는지를 정확히 이 방법으로 판정한다.
|
||||
|
||||
## 3. 층별로 확인한다 — 아래에서 위로
|
||||
|
||||
한 번에 밖에서 치지 말고, **가까운 층부터** 본다. 어디서 끊겼는지가 바로 나온다.
|
||||
|
||||
> **`curl` 을 두 형태로 쓴다.** 처음 볼 때는 `-I`(헤더까지 읽는 형태)로
|
||||
> **응답을 눈으로 읽고**, 같은 것을 여러 번 재거나 두 노드를 나란히 비교할
|
||||
> 때만 `-w '%{http_code}'`(값만 뽑는 형태)로 바꾼다. 값만 뽑는 형태는
|
||||
> 골라 놓은 한 칸 말고는 전부 버리므로, **무엇이 잘못됐는지 모르는 상태**
|
||||
> 에서는 쓸 것이 못 된다.
|
||||
|
||||
**확인 ①** Traefik 이 듣고 있나 (nginx 를 건너뛴다)
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.122.11
|
||||
curl -I http://192.168.122.11
|
||||
```
|
||||
|
||||
**형태** (이 실험대에서 캡처해 두지 않았다 — 봐야 할 줄만)
|
||||
```
|
||||
HTTP/1.1 404 Not Found
|
||||
...
|
||||
```
|
||||
|
||||
**어디를 봐야 하는가** — 첫 줄의 상태 줄 하나. 그리고 그 앞에 **아무 오류도
|
||||
없이** 헤더가 나왔다는 사실. `curl: (7) Failed to connect` 이면 응답 자체가
|
||||
없는 것이라 상태 코드를 볼 일도 없다.
|
||||
|
||||
**이 결과가 의미하는 것** — **`404` 가 성공 신호다.** 게스트의 80 을 누가
|
||||
듣고 있고(Traefik), 그가 요청을 받아 「매칭되는 Ingress 규칙이 없다」고
|
||||
답한 것이다. 이 층은 통과. `502` 면 Traefik 은 떴는데 그 뒤 백엔드가 없는
|
||||
것이고, 연결 거부·타임아웃이면 Traefik 이 안 떴거나 게스트가 죽은 것이라
|
||||
**02 로 돌아간다.**
|
||||
|
||||
두 노드가 같은지 볼 때는 값만 뽑는 형태가 낫다. 두 줄을 나란히 놓고 눈으로
|
||||
비교하는 것이 목적이기 때문이다.
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.122.11
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.122.12
|
||||
```
|
||||
|
||||
**실측** — `.11` 에서 잰 값이다.
|
||||
```
|
||||
404
|
||||
```
|
||||
|
||||
**`404` 가 성공 신호다.** Traefik 까지 닿았는데 매칭되는 Ingress 규칙이 없다는
|
||||
뜻이다. `502` 나 연결 거부면 그 아래에서 끊긴 것이다.
|
||||
**어디를 봐야 하는가** — 두 줄이 **같은 코드**인가.
|
||||
|
||||
**이 결과가 의미하는 것** — 둘이 같으면 nginx 가 어느 쪽으로 보내도 같은
|
||||
결과가 나온다. 한쪽만 다르면 upstream 두 개 중 하나가 죽은 것이고, 그
|
||||
상태에서는 **요청의 절반만 실패**해서 「가끔 안 된다」로 보인다.
|
||||
|
||||
**확인 ②** nginx 가 80 에서 리다이렉트하나
|
||||
```bash
|
||||
curl -I http://auth.hyeonworks.com
|
||||
```
|
||||
|
||||
**형태** (봐야 할 두 줄만)
|
||||
```
|
||||
HTTP/1.1 301 Moved Permanently
|
||||
Location: https://auth.hyeonworks.com/
|
||||
...
|
||||
```
|
||||
|
||||
**어디를 봐야 하는가** — 상태 줄과 **`Location:` 헤더 한 줄**. `Location` 이
|
||||
`https://` 로 시작하고 원래 호스트명을 그대로 들고 있는가. `$host` 대신
|
||||
설정에 이름을 박아 두면 여기서 엉뚱한 호스트가 나온다.
|
||||
|
||||
**이 결과가 의미하는 것** — 301 이 나왔다는 것은 **바깥 요청이 호스트 nginx
|
||||
까지 닿았다**는 뜻이다(①은 게스트에 직접 친 것이므로 nginx 를 안 거쳤다).
|
||||
DNS·방화벽·80 리스너가 전부 살아 있다. 응답이 아예 없으면 nginx 가 안 떴거나
|
||||
80 이 막힌 것이다. 리다이렉트를 따라가 끝까지 보려면 `-L` 을 붙인다.
|
||||
|
||||
값을 반복해서 잴 때의 형태는 이것이고, 아래가 이 실험대의 실측이다.
|
||||
|
||||
```bash
|
||||
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' http://auth.hyeonworks.com
|
||||
```
|
||||
@@ -119,6 +201,16 @@ curl -s -o /dev/null -w '%{http_code}\n' https://auth.hyeonworks.com/realms/mast
|
||||
200
|
||||
```
|
||||
|
||||
**어디를 봐야 하는가** — 코드 한 칸. 여기서만 값만 뽑는 형태를 바로 쓰는
|
||||
이유는, 이 200 이 **04·05 에서 매번 같은 명령으로 다시 잴 기준값**이기
|
||||
때문이다. 처음 한 번은 `curl -I https://auth.hyeonworks.com/realms/master`
|
||||
로 헤더까지 보고, 그다음부터 이 형태로 줄인다.
|
||||
|
||||
**이 결과가 의미하는 것** — `200` 이면 nginx → Traefik → 파드까지 2홉이 다
|
||||
이어졌다. `502` 는 nginx 는 살아 있는데 upstream 을 못 잡은 것(4번의 로그를
|
||||
본다), `curl: (60)` 같은 인증서 오류는 아직 04 를 안 한 것이다. TLS 단계에서
|
||||
막히면 코드만 보지 말고 `curl -v` 로 협상 과정을 읽는다 — 04 에서 그렇게 한다.
|
||||
|
||||
## 4. upstream 이 둘인 이유
|
||||
|
||||
```
|
||||
@@ -159,6 +251,16 @@ journalctl -u nginx -p err -n 5 # 최근 에러만
|
||||
journalctl -u nginx -f # 지금 벌어지는 것
|
||||
```
|
||||
|
||||
**어디를 봐야 하는가** — 각 줄의 **괄호 안 errno**(`113`·`111`)와 그 뒤의
|
||||
`upstream: "http://192.168.122.1x:80/..."` 부분. 어느 upstream 이 문제인지가
|
||||
거기 적혀 있다. 그리고 **타임스탬프** — 방금 친 요청 시각과 안 맞으면 지금
|
||||
보고 있는 것은 옛 사고다.
|
||||
|
||||
**이 결과가 의미하는 것** — `-p err` 로 걸러도 아무것도 안 나오면 nginx 는
|
||||
정상이고 문제는 더 위(Traefik·파드)에 있다. 두 번째 명령은 **띄워 놓은
|
||||
채로 다른 창에서 요청을 치는** 용도다 — 요청과 로그 줄을 눈으로 짝지으면
|
||||
「이 요청이 어느 upstream 으로 갔나」가 바로 보인다. 끝내려면 Ctrl+C.
|
||||
|
||||
**★ nginx 에러 로그는 2048바이트에서 잘린다.** 긴 URL 이 끝에서 단어 중간에
|
||||
끊겨 보이면 그것이다. 되찾으려면 **access 로그를 본다** — 거기엔 제한이 없다.
|
||||
|
||||
@@ -166,5 +268,15 @@ journalctl -u nginx -f # 지금 벌어지는 것
|
||||
grep oauth2/callback /var/log/nginx/access.log | tail -1
|
||||
```
|
||||
|
||||
이 실험대에서 B-7 의 502 원인이 error 로그에 있었는데 잘려 있었고, access
|
||||
로그에는 3492자로 온전히 남아 있었다.
|
||||
**어디를 봐야 하는가** — 그 한 줄의 **끝**이다. 요청 URL 이 `"` 로 제대로
|
||||
닫혀 있으면 온전한 줄이고, 단어 중간에서 멈춰 있으면 잘린 것이다. 길이가
|
||||
궁금하면 세어 본다.
|
||||
|
||||
```bash
|
||||
grep oauth2/callback /var/log/nginx/access.log | tail -1 | wc -c
|
||||
```
|
||||
|
||||
**이 결과가 의미하는 것** — error 로그와 access 로그의 같은 요청 길이가 다르면
|
||||
**error 쪽이 잘린 것**이지 요청이 잘린 것이 아니다. 이 실험대에서 B-7 의
|
||||
502 원인이 error 로그에 있었는데 잘려 있었고, access 로그에는 3492자로 온전히
|
||||
남아 있었다. 잘린 문자열을 놓고 원인을 추측하면 없는 문제를 좇게 된다.
|
||||
|
||||
Reference in New Issue
Block a user