fix(setup): 실험대를 새로 세워 setup 35편을 밟고 어긋난 명령과 결과를 고친다
기반 가이드 7단계로 실험대를 철거하고 다시 세운 뒤 virtualization setup 9편과 keycloak-session-store 26편을 순서대로 밟았다. 24편은 끝까지, 11편은 되는 데까지 밟았고 밟은 범위를 편마다 적었다. 명령이 못 도는 것을 고쳤다. - kubectl 을 `kc-lab-1` 에서 치라고 적었는데 그 기계에 kubeconfig 가 없다. 라벨 639개와 각 편의 「어디서 치는가」를 `[lab host]` 로 옮겼다 - `-o custom-columns=…[0]…` 이 zsh 에서 글로브로 읽혀 안 돈다. 28곳에 따옴표 - busybox `sed` 가 끝 개행을 안 붙여 A-3 의 측정이 언제나 0 이었다 - `--token-file ~/node-token` 뒤에 그 파일을 지우면 k3s agent 가 재부팅을 못 견딘다. `/etc/rancher/node-token` 으로 옮기는 처방을 재서 넣었다 - 게스트에 없는 도구를 전제로 한 명령 넷 — `conntrack`·`dig`·`strings`·`nginx -v` - `echo` 와 JWT 헤더가 `"이름" : [ 값 ]` 으로 찍는데 문서는 공백 없이 옮겨 적어 그 실측으로 만든 grep·sed 가 한 줄도 못 잡는다 - B-0 이 `directAccessGrantsEnabled` 와 계정 완성을 빠뜨려 B-3 이 못 돈다 - D-4·D-4a 가 `test-server` 와 `certbot-renew.*` 를 가리키는데 실제로는 `kc-lab-edge` 의 `certbot.service` 다 - `virsh setmaxmem --config` 를 `dominfo` 로 판정하면 틀린다. `--inactive` 로 - `LIBVIRT_DEFAULT_URI` 를 rc 에만 넣으면 `ssh host '명령'` 에서 안 먹는다 결과가 조건부인 것을 갈랐다. - readiness 는 즉시 안 뒤집힌다. A-1·A-2 의 60초 창을 적었다 - 03 의 층 ②③ `301` 은 04 이후의 값이고 그 단계에서는 `404` 다 - A-0 의 로그 필터를 요청 직후에 치면 정반대 결론이 나온다 - A-5 의 한 방향 차단은 잠깐 `1` 이었다 `2` 로 돌아온다 증거는 두 프로젝트의 `evidence/raw/` 에 99벌을 README 와 함께 남겼다. 비밀은 길이만 적었고 화면에 찍힌 토큰은 가렸다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ab59130196
commit
024362d096
@@ -0,0 +1,167 @@
|
||||
2026-09-17 에 기반 가이드 7단계로 실험대를 처음부터 다시 세우고 A-0 을 그대로 다시
|
||||
밟은 기록이다. 명령과 출력은 그때 화면에 나온 것을 그대로 옮겼다.
|
||||
|
||||
a0-01-baseline.txt 기준선 1~5 — 노드·파드 배치, 파드 IP, ISPN000094 (2), jgroups_ping coord 하나, \dt 100행, 세션 0행
|
||||
a0-02-cache-entries.txt 기준선 6 — Prometheus 의 vendor_statistics_approximate_entries_unique 통째로와 tr/grep 으로 자른 형태
|
||||
a0-03-inject-reset.txt 주입 — 세션 행 삭제와 rollout restart, 새 파드 IP
|
||||
a0-04-test0.txt 시험 0 ①~⑦ — 로그인, 토큰 길이, 클레임 디코드, sid, CID, 두 노드에 grep -c
|
||||
a0-05-claims.txt JWT 클레임 전체 (패딩을 채워 디코드) — sub 이 없다는 것을 확인
|
||||
a0-06-test0-cross-node.txt 시험 0 ⑧⑨ — 반대편 refresh 200 · 같은 sid, 로그아웃 204, 발급 노드에서 400 Session not active
|
||||
a0-07-test0b-cache-delta.txt 시험 0b — 로그인 한 번에 발급 노드만 +1, 반대편 +0
|
||||
a0-08-test0c-ownership.txt 시험 0c — 몰아준 쪽만 늘어 9 + 5 = 14, DB 총계 14
|
||||
a0-09-test0d-sql.txt 시험 0d 첫 시도 — 문장 로깅을 켜고 요청 직후에 걸렀더니 반대편 문장이 안 나왔다
|
||||
a0-10-test0d-retry.txt 같은 필터를 몇 초 뒤에 — 그래도 안 나온 판. 09 와 함께 「너무 일찍 걸렀다」의 증거다
|
||||
a0-11-test0d-window.txt 그 시간대에 반대편이 낸 모든 줄 — 디스커버리 질의뿐이었다
|
||||
a0-12-test0d-controlled.txt 대기를 넣고 다시 — 반대편 pid 가 낸 sid 줄 6개, 세션 테이블 문장 6/12
|
||||
a0-13-test0d-sql-lines.txt 반대편이 날린 여덟 문장과 pid 로 거른 BEGIN~COMMIT 경계. 끝에 문장 로깅을 되돌렸다
|
||||
|
||||
비밀은 옮기지 않았다. 관리자 비밀번호는 길이(19)만 확인했고 값은 어느 파일에도 없다.
|
||||
|
||||
A-1 (JGroups 7800 차단)
|
||||
a1-01-inject.txt 매니페스트 원문과 apply · 적용 시각
|
||||
a1-02-verify.txt 정책이 잡은 파드, 포트 셋(9000=200 · 8080=200 · 7800=exit 7), 클러스터는 아직 2, /proc/net/tcp6 의 1E78
|
||||
a1-03-conntrack.txt conntrack 을 두 노드에서 — 빈 화면이 나왔다
|
||||
a1-04-conntrack-missing.txt 그 빈 화면의 까닭 — conntrack 미설치. 2>/dev/null 이 command not found 를 지웠다
|
||||
a1-05-conntrack-installed.txt 처방 검증 — 깔고 나니 ESTABLISHED [ASSURED] 두 줄이 나온다
|
||||
a1-06-forced-partition.txt 파드를 지워 분단 확정 — 두 노드가 각각 1 을 보고
|
||||
a1-07-readiness.txt 분단된 노드가 0/1 · Ready=False, Endpoints 가 하나로, health/ready 503 과 Failing since
|
||||
a1-08-readiness-commands.txt 문서가 적은 명령 그대로 — describe 는 조건표를 내고, custom-columns 는 zsh 에서 안 돈다
|
||||
a1-09-quoting-and-health.txt 따옴표를 씌운 형태와 헬스 본문을 내는 명령. 정문은 Host 헤더로 200
|
||||
a1-10-cross-node-under-partition.txt 분단 중 네 단계 — 200 · 204 · 200. 로그아웃이 전파되지 않았다 (토큰은 길이만 남기고 가렸다)
|
||||
a1-11-recover.txt 정책 삭제 뒤 30~60초 안에 두 노드가 다시 2
|
||||
|
||||
A-2 (데이터베이스 정상 종료)
|
||||
a2-01-baseline-probe.txt 상주 탐침 a2-probe 와 정지 전 토큰 (길이만)
|
||||
a2-02-inject.txt 정지 전 네 경로 200×4, replicas=0, 파드 삭제, Deployment 0/0
|
||||
a2-03-during-outage.txt 정지 직후 — 네 경로 500×4, JWKS·well-known 200, Connection refused, 그런데 ready 는 아직 true
|
||||
a2-04-outage-progression.txt 약 50초 뒤 ready false,false · 정문 503 으로 뒤집히는 자리
|
||||
a2-05-recover.txt replicas=1 에서 36초 만에 ready true,true · 정문 200 · 재시작 0
|
||||
|
||||
A-3 (데이터베이스 크래시)
|
||||
a3-01-design-check.txt 로그인 트랜잭션에도 SET LOCAL synchronous_commit TO OFF 가 붙는다 · WAL 설정 네 줄
|
||||
a3-02-prepare.txt 세션 비우기, 파드 셋 상태, 루프 파일 주입
|
||||
a3-03-attempt1.txt 시도 ① 첫 판 — /tmp/sids 가 0줄이었다 (아래 04 가 그 까닭)
|
||||
a3-04-sids-no-newline.txt busybox sed 가 끝 개행을 안 붙인다 — 9384바이트 0줄. echo 로 감싼 처방을 재서 10줄 확인
|
||||
a3-05-attempt1-redo.txt 고친 루프로 다시 — 8초에 109건, force delete 는 유실 0
|
||||
a3-06-attempt2.txt 시도 ② kill -9 1 — RESTARTS 0, 400 = 400, 유실 0
|
||||
a3-07-attempt3.txt 시도 ③ 백엔드 SIGKILL — crash recovery 로그와 395 vs 392
|
||||
a3-08-loss-count.txt 문서의 comm 방법으로 센 유실 3건과 그 sid 세 개
|
||||
a3-09-revert.txt 문장 로깅 off 확인, 세션 정리, 파드 재시작, 탐침 삭제
|
||||
|
||||
A-4 (노드 상실)
|
||||
a4-01-baseline.txt virsh uri·VM 셋·파드 배치·PV 가 kc-lab-2 에 고정된 것·관측 스택 위치
|
||||
a4-02-inject-4a.txt kc-lab-2 영향 범위와 virsh destroy. 하이퍼바이저는 shut off 인데 쿠버네티스는 +10초에도 Ready
|
||||
a4-03-4a-progression.txt +28초 Ready/정문 000 → +66초 NotReady/정문 503. 이벤트 NodeNotReady 와 context deadline exceeded
|
||||
a4-04-eviction-and-recover.txt +4분 49초에 deletionTimestamp. Deployment 는 대체 파드(Pending), StatefulSet 은 대체 없이 Terminating
|
||||
a4-05-recovery-progression.txt VM 을 켠 뒤 Ready 로 돌아오고 파드가 서고 정문이 200 이 되기까지
|
||||
a4-06-agent-token-missing.txt 복구가 막힌 진짜 까닭 — 유닛이 지워진 ~/node-token 을 기다린다. 파일을 되돌리자 Ready
|
||||
a4-07-token-remedy.txt 처방 — /etc/rancher/node-token(root 600)으로 옮기고 유닛을 돌리면 홈 사본을 지워도 뜬다
|
||||
|
||||
A-5 (비대칭 분단)
|
||||
a5-01-attempt1.txt 시도 ① filter FORWARD — 카운터는 9·22 로 올라가는데 클러스터는 2 그대로. 게스트 셸의 $K1 이 비어 있는 것도 여기서 확인
|
||||
a5-02-attempt2-3.txt 시도 ② 보내는 쪽 raw — 카운터 0. 시도 ③ 받는 쪽 raw — 카운터 16·20, 멤버 1
|
||||
a5-03-one-direction-watch.txt 한 방향만 막은 채 2분 — 잠깐 1 이었다가 2 로 돌아온다 (문서의 「열린 방향으로 다시 붙는다」)
|
||||
a5-04-bidirectional.txt 양방향 — 멤버 1·1 과 jgroups_ping 의 coord 가 둘 다 t
|
||||
a5-05-revert.txt 두 체인을 비우자 2 와 coord 하나로 복귀
|
||||
|
||||
A-6 (지연 주입)
|
||||
a6-01-attempt1-2.txt 시도 ① eth0 가 없다 · ip -brief link 목록 · enp1s0 는 노드 IP 만, flannel.1 은 파드 IP 가 보인다 (문서가 미검증으로 둔 두 줄)
|
||||
a6-02-inject.txt 주입 전 로그인 0.064~0.068s, flannel.1 에 prio·netem·filter 세 줄
|
||||
a6-03-effect.txt 주입 뒤 1.86~1.91s (문서의 1,872ms 와 28배가 그대로) · netem 83 pkt · tc filter show 의 match 0a2a011d
|
||||
a6-04-revert.txt qdisc del 뒤 noqueue 로 돌아가고 시간도 0.04~0.07s 로 복귀
|
||||
|
||||
A-7 (volatile 로 A층 넷을 다시)
|
||||
a7-01-switch-volatile.txt 세션 비우기, args 를 --features-disabled=persistent-user-sessions 로 patch, 롤아웃
|
||||
a7-02-cross-node-volatile.txt 교차 노드 refresh 200 인데 DB 세션 행은 (0 rows)
|
||||
a7-03-block-7800.txt 캐시가 keycloak-0 에만 1, 그 뒤 NetworkPolicy 로 7800 차단 — 멤버 1·1
|
||||
a7-04-partition-breaks-sharing.txt 분단 + volatile 에서 400·400·400 (persistent 의 200·204·200 과 정반대)
|
||||
a7-05-revert.txt NetworkPolicy 삭제와 args 원복
|
||||
|
||||
A-7a (그 500 의 원인과 캐시 온도 셋)
|
||||
a7a-01-setup.txt 문장 로깅 on, volatile 전환, StatefulSet 밖의 탐침
|
||||
a7a-02-repro-A.txt 재현 A 완전 냉시동 — 로그인이 400 unauthorized_client
|
||||
a7a-03-repro-A-sql.txt 문서의 grep 이 한 줄도 못 잡는다. 속 예외가 JDBCConnectionException 쪽이었다
|
||||
a7a-04-repro-B.txt 재현 B 로그인 한 번으로 덥힌 뒤 DB 정지 — refresh 가 500 unknown_error
|
||||
a7a-05-repro-C-and-revert.txt 재현 C — DB 를 켜니 같은 refresh 가 200. 로깅 off 와 args 원복까지
|
||||
|
||||
A-8 (롤링 재시작)
|
||||
a8-01-baseline.txt 파드·args·DB 0건, 토큰과 sid 를 탐침에 담고 대조군 refresh 200, 그 sid 의 DB 행
|
||||
a8-02-restart.txt 재시작 전 캐시 0, rollout restart, AGE 로 교체 확인. (12번은 탐침의 낡은 K0 때문에 000 이 났다)
|
||||
a8-03-main-test.txt 새 IP 로 다시 — 재시작 전 토큰이 200, created_on 은 그대로이고 last_session_refresh 만 갱신 (토큰은 길이만 남기고 가렸다)
|
||||
|
||||
D-3 (비밀 노출 네 경로)
|
||||
d3-01-secret-paths.txt Secret 목록·describe 의 길이 표시·키 이름·길이, 카나리아 주입, 암호화 Disabled, state.db 0 / -wal 1
|
||||
d3-02-paths-and-revert.txt strings 미설치, RBAC 는 둘 다 no, 카나리아 삭제 뒤 -wal 이 1 → 7 로 늘었다
|
||||
d3-03-strings-missing.txt binutils 를 깔면 strings 가 생기고, 안 깔아도 grep -c 로 같은 7 이 나온다
|
||||
|
||||
B층 준비 (B-0 의 실행 가능한 부분)
|
||||
b0-01-image-import.txt 워크스테이션에서 두 이미지를 빌드해 docker save | ssh | k3s ctr images import 로 두 노드에
|
||||
b0-02-realm-and-user.txt kcadm 로그인, realm keycloak-patterns · client bff-confidential · user labuser 생성
|
||||
b0-03-deploy-bff.txt bff-redis.yaml 적용 — Secret·PVC·redis·bff·Service·Ingress
|
||||
b0-04-bff-status.txt bff 두 replica 와 redis 가 1/1. imagePullPolicy Never 로 반입 이미지가 붙었다
|
||||
|
||||
B-3 (refresh 회전 경쟁) — 전제 검증까지
|
||||
b3-01-setup.txt realm 세 값(revokeRefreshToken false · maxReuse 0 · lifespan 60), 탐침, CS길이 14
|
||||
b3-02-secret-and-token.txt B-0 이 없다고 한 비밀 대조를 만들어 「두 값이 같다」. 그런데 토큰 요청이 unauthorized_client
|
||||
b3-03-direct-grant-missing.txt 원인 — directAccessGrantsEnabled 가 false. 켜니 invalid_grant 로 바뀐다
|
||||
b3-04-account-not-fully-set-up.txt 둘째 원인 — labuser 의 emailVerified false. 고치니 토큰이 나온다 (rt=735자)
|
||||
b3-05-race.txt 회전을 켜고 같은 토큰으로 동시에 5번 — 400 넷·200 하나, 이긴 토큰도 400 (토큰 조각은 가렸다)
|
||||
b3-06-revert.txt revokeRefreshToken 원복과 탐침 삭제
|
||||
|
||||
D-1 (백업과 복구)
|
||||
d1-01-backup.txt 기준선 101 테이블·세션 6건, pg_dump 로 976873 bytes·8569 줄·CREATE TABLE 101
|
||||
d1-02-destroy-restore.txt DROP SCHEMA 뒤 남은 테이블 0 인데 정문은 200, 6초 만에 복구되고 ERROR 0, 101/6 으로 복귀
|
||||
|
||||
D-2 (판올림과 롤백)
|
||||
d2-01-baseline.txt 태그 26.7.0, databasechangelog 210, 마지막 다섯 줄, 세션 6, quay 에 26.7.3 존재(200)
|
||||
d2-02-upgrade.txt 26.7.3 정방향 85초 — 스키마 210 그대로, 세션 보존, 정문 200
|
||||
d2-03-rollback-and-reverse.txt 롤백 67초 성공. 역방향 26.0 은 liquibase Validation Failed 로 keycloak-1 만 못 뜨고 정문은 200
|
||||
d2-04-revert.txt 체크섬 줄(1 changesets check sum)과 26.7.0 원복
|
||||
|
||||
B-6 (키 회전) — 전제까지만
|
||||
b6-01-deploy-echo.txt echo.yaml 로 header-lab 네임스페이스와 echo 두 replica (반입 이미지로 뜬다)
|
||||
b6-02-jwks-before.txt JWKS 를 Host 헤더로 받는다. RS256 1개, kid 둘
|
||||
b6-03-providers.txt kcadm 세션이 파드 교체로 사라진 것과 재로그인. 문서가 「빈 결과」라던 질의가 실제로는 결과를 낸다
|
||||
b6-04-old-token.txt 토큰 1397자. echo 는 유효한 토큰에 401, 토큰 없이는 200
|
||||
b6-05-echo-401.txt 그 까닭 — echo 의 issuer/jwk URI 가 https 이고 닿지 않는다. kid 를 뽑으려면 공백을 허용해야 한다
|
||||
b6-06-kid-and-issuer.txt 두 URI 원문, issuer=000(exit 7), 헤더의 "kid" : "…" 공백 형태와 두 sed 비교
|
||||
|
||||
B-4 (신원 헤더 위조) — TLS 를 Host 헤더로 대체해 실행
|
||||
b4-01-forged-headers.txt Ingress 네 줄, echo 응답 전문(들여쓰고 콜론 양옆에 공백), 대조군은 비어 있다
|
||||
b4-02-forged-headers-retry.txt 동명 헤더 둘 · 값 안의 쉼표 · 위조한 신원이 전부 그대로 도착. 문서의 콜론 붙인 grep 은 한 줄도 못 잡는다
|
||||
|
||||
C-2 (백채널 로그아웃) — 브라우저 없이 되는 두 단계
|
||||
c2-01-backchannel-probe.txt 세 후보 경로가 전부 302 이고 Location 이 로그인 시작점. 워크스테이션 grep 도 빈 출력(디렉터리는 있다)
|
||||
|
||||
B-7a / B-7 (엣지 세션) — 전제에서 막힌 자리를 쟀다
|
||||
b7a-01-oauth2-proxy.txt oauth2-proxy 배포가 롤아웃 타임아웃. redis-cli dbsize 0 과 빈 스캔은 정상 동작
|
||||
b7a-02-oauth2-proxy-blocked.txt 까닭 — 기동 시 OIDC 디스커버리가 https://auth.hyeonworks.com 으로 가고 connection refused. CrashLoopBackOff
|
||||
|
||||
B-0 / B-1 / B-2 — 브라우저 없이 되는 측정
|
||||
b1-01-beans.txt /actuator/beans 빈 437개, authorizedClientService 가 JdbcOAuth2AuthorizedClientService, RedisSessionConfiguration 존재. 문서의 미검증 두 줄이 돈다
|
||||
b2-01-jdbc-table.txt oauth2_authorized_client 표는 생겨 있고 행은 0 (행은 브라우저 로그인 뒤에 생긴다)
|
||||
|
||||
D-4 / D-4a (인증서 갱신과 배포 훅) — 인증서 없이 되는 부분
|
||||
d4-01-renewal-automation.txt certbot 은 kc-lab-edge 에 있고 test-server 에는 타이머가 없다. 유닛 이름은 certbot.timer/.service (certbot-renew.* 아님). 기본 유닛에 ExecStartPost 도 --deploy-hook 도 없고 훅 디렉터리도 비었다. certificates 는 No certificates found
|
||||
d4a-01-hook-state.txt test-server 에 nginx 프로세스가 없다(엣지에 있다). 훅 디렉터리 total 8. lab host 와 엣지의 시계가 94초 어긋나 있다
|
||||
|
||||
B-5 (Redis 상실)
|
||||
b5-01-baseline.txt Redis PONG·키 없음·save 와 appendonly·/data 가 PVC redis-data
|
||||
b5-02-redis-down.txt replicas=0 뒤 health 는 DOWN 인데 readiness 는 UP. 파드 둘 다 1/1, 엔드포인트도 ready true,true
|
||||
b5-03-revert.txt replicas=1 로 되살리자 health 가 다시 UP
|
||||
|
||||
C-1 (여러 앱의 SSO) — 브라우저 없이 되는 세션 정리 구간
|
||||
c1-01-clear-sessions.txt logout-all 을 쳐도 세션이 6건 그대로. 자식 1633 · 부모 6 순서로 지워야 한다. flushall·롤아웃 뒤 둘 다 0. 롤아웃이 kcadm 세션을 날린다
|
||||
|
||||
이 폴더가 덮는 범위
|
||||
-------------------
|
||||
2026-09-17 에 기반 가이드 7단계로 실험대를 철거하고 새로 세운 뒤 kss 26편을 순서대로
|
||||
밟은 기록이다. 끝까지 밟은 편이 17, 되는 데까지 밟은 편이 9 다. 어느 편이 어디까지인지는
|
||||
SSOT 의 「2026-09-17 재현 — 어디까지 밟았고 무엇이 막았나」와 각 기록의
|
||||
「이 실험대에서 아직 못 밟은 단계」에 적혀 있다.
|
||||
|
||||
막은 것은 하나다 — https://auth.hyeonworks.com 이 서지 않는다. 와일드카드 인증서
|
||||
(Cloudflare API 토큰)와 호스트의 libvirt guest_input 구멍(호스트 sudo)이 둘 다 필요하다.
|
||||
|
||||
비밀은 어느 파일에도 값으로 들어 있지 않다. 비밀번호는 길이(19·22)만 적었고, 화면에
|
||||
찍혀 나온 토큰은 <REDACTED n자> 로 가렸다.
|
||||
@@ -0,0 +1,131 @@
|
||||
=== a0 기준선 1 노드·파드 ===
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
kc-lab-1 Ready control-plane 18m v1.36.4+k3s1
|
||||
kc-lab-2 Ready <none> 16m v1.36.4+k3s1
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
keycloak-0 1/1 Running 0 8m46s 10.42.1.3 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 8m46s 10.42.0.9 kc-lab-1 <none> <none>
|
||||
postgres-7b474b88c8-s6vdh 1/1 Running 0 8m46s 10.42.1.5 kc-lab-2 <none> <none>
|
||||
=== a0 기준선 2 파드 IP ===
|
||||
10.42.1.3 10.42.0.9
|
||||
=== a0 기준선 3 클러스터 뷰 ===
|
||||
2026-09-17 04:35:25,386 INFO [org.infinispan.CLUSTER] (executor-thread-1) ISPN000094: Received new cluster view for channel ISPN: [keycloak-1-3159(v=16.0.12)|1] (2) [keycloak-1-3159(v=16.0.12), keycloak-0-13057(v=16.0.12)]
|
||||
2026-09-17 04:35:25,333 INFO [org.infinispan.CLUSTER] (jgroups-5,keycloak-1-3159(v=16.0.12)) ISPN000094: Received new cluster view for channel ISPN: [keycloak-1-3159(v=16.0.12)|1] (2) [keycloak-1-3159(v=16.0.12), keycloak-0-13057(v=16.0.12)]
|
||||
=== a0 기준선 4 디스커버리 ===
|
||||
name | ip | coord
|
||||
------------------+----------------+-------
|
||||
keycloak-0-13057 | 10.42.1.3:7800 | f
|
||||
keycloak-1-3159 | 10.42.0.9:7800 | t
|
||||
(2 rows)
|
||||
|
||||
=== a0 기준선 5 테이블 목록 ===
|
||||
List of relations
|
||||
Schema | Name | Type | Owner
|
||||
--------+-------------------------------+-------+----------
|
||||
public | admin_event_entity | table | keycloak
|
||||
public | associated_policy | table | keycloak
|
||||
public | auth_session | table | keycloak
|
||||
public | authentication_execution | table | keycloak
|
||||
public | authentication_flow | table | keycloak
|
||||
public | authenticator_config | table | keycloak
|
||||
public | authenticator_config_entry | table | keycloak
|
||||
public | broker_link | table | keycloak
|
||||
public | client | table | keycloak
|
||||
public | client_attributes | table | keycloak
|
||||
public | client_auth_flow_bindings | table | keycloak
|
||||
public | client_initial_access | table | keycloak
|
||||
public | client_node_registrations | table | keycloak
|
||||
public | client_scope | table | keycloak
|
||||
public | client_scope_attributes | table | keycloak
|
||||
public | client_scope_client | table | keycloak
|
||||
public | client_scope_role_mapping | table | keycloak
|
||||
public | cluster_event | table | keycloak
|
||||
public | component | table | keycloak
|
||||
public | component_config | table | keycloak
|
||||
public | composite_role | table | keycloak
|
||||
public | credential | table | keycloak
|
||||
public | databasechangelog | table | keycloak
|
||||
public | databasechangeloglock | table | keycloak
|
||||
public | default_client_scope | table | keycloak
|
||||
public | event_entity | table | keycloak
|
||||
public | fed_issued_ver_credential | table | keycloak
|
||||
public | fed_user_attribute | table | keycloak
|
||||
public | fed_user_consent | table | keycloak
|
||||
public | fed_user_consent_cl_scope | table | keycloak
|
||||
public | fed_user_credential | table | keycloak
|
||||
public | fed_user_group_membership | table | keycloak
|
||||
public | fed_user_required_action | table | keycloak
|
||||
public | fed_user_role_mapping | table | keycloak
|
||||
public | fed_user_ver_credential | table | keycloak
|
||||
public | federated_identity | table | keycloak
|
||||
public | federated_user | table | keycloak
|
||||
public | group_attribute | table | keycloak
|
||||
public | group_role_mapping | table | keycloak
|
||||
public | identity_provider | table | keycloak
|
||||
public | identity_provider_config | table | keycloak
|
||||
public | identity_provider_mapper | table | keycloak
|
||||
public | idp_mapper_config | table | keycloak
|
||||
public | issued_ver_credential | table | keycloak
|
||||
public | jgroups_ping | table | keycloak
|
||||
public | keycloak_group | table | keycloak
|
||||
public | keycloak_role | table | keycloak
|
||||
public | login_failure | table | keycloak
|
||||
public | migration_model | table | keycloak
|
||||
public | offline_client_session | table | keycloak
|
||||
public | offline_user_session | table | keycloak
|
||||
public | org | table | keycloak
|
||||
public | org_domain | table | keycloak
|
||||
public | org_invitation | table | keycloak
|
||||
public | outbox_entry | table | keycloak
|
||||
public | policy_config | table | keycloak
|
||||
public | protocol_mapper | table | keycloak
|
||||
public | protocol_mapper_config | table | keycloak
|
||||
public | realm | table | keycloak
|
||||
public | realm_attribute | table | keycloak
|
||||
public | realm_default_groups | table | keycloak
|
||||
public | realm_enabled_event_types | table | keycloak
|
||||
public | realm_events_listeners | table | keycloak
|
||||
public | realm_localizations | table | keycloak
|
||||
public | realm_required_credential | table | keycloak
|
||||
public | realm_smtp_config | table | keycloak
|
||||
public | realm_supported_locales | table | keycloak
|
||||
public | redirect_uris | table | keycloak
|
||||
public | required_action_config | table | keycloak
|
||||
public | required_action_provider | table | keycloak
|
||||
public | resource_attribute | table | keycloak
|
||||
public | resource_policy | table | keycloak
|
||||
public | resource_scope | table | keycloak
|
||||
public | resource_server | table | keycloak
|
||||
public | resource_server_perm_ticket | table | keycloak
|
||||
public | resource_server_policy | table | keycloak
|
||||
public | resource_server_resource | table | keycloak
|
||||
public | resource_server_scope | table | keycloak
|
||||
public | resource_uris | table | keycloak
|
||||
public | revoked_token | table | keycloak
|
||||
public | role_attribute | table | keycloak
|
||||
public | root_auth_session | table | keycloak
|
||||
public | scope_mapping | table | keycloak
|
||||
public | scope_policy | table | keycloak
|
||||
public | server_config | table | keycloak
|
||||
public | single_use_object | table | keycloak
|
||||
public | user_attribute | table | keycloak
|
||||
public | user_consent | table | keycloak
|
||||
public | user_consent_client_scope | table | keycloak
|
||||
public | user_entity | table | keycloak
|
||||
public | user_federation_config | table | keycloak
|
||||
public | user_federation_mapper | table | keycloak
|
||||
public | user_federation_mapper_config | table | keycloak
|
||||
public | user_federation_provider | table | keycloak
|
||||
public | user_group_membership | table | keycloak
|
||||
public | user_required_action | table | keycloak
|
||||
public | user_role_mapping | table | keycloak
|
||||
public | user_ver_credential | table | keycloak
|
||||
public | web_origins | table | keycloak
|
||||
public | workflow_state | table | keycloak
|
||||
(100 rows)
|
||||
|
||||
=== a0 기준선 5b 세션 수 ===
|
||||
offline_flag | count
|
||||
--------------+-------
|
||||
(0 rows)
|
||||
|
||||
+99
File diff suppressed because one or more lines are too long
+19
@@ -0,0 +1,19 @@
|
||||
=== a0 주입 1-① 세션 행을 지운다 ===
|
||||
DELETE 0
|
||||
=== a0 주입 1-② 재시각과 롤아웃 ===
|
||||
13:45:12 재시작
|
||||
statefulset.apps/keycloak restarted
|
||||
=== a0 주입 1-③ 다 설 때까지 ===
|
||||
Waiting for partitioned roll out to finish: 0 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for partitioned roll out to finish: 1 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
=== a0 주입 검증 — 새 파드와 새 IP ===
|
||||
keycloak-0 1/1 Running 0 21s 10.42.1.7 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 43s 10.42.0.13 kc-lab-1 <none> <none>
|
||||
10.42.1.7 10.42.0.13
|
||||
@@ -0,0 +1,13 @@
|
||||
### 탐침 파드 환경변수 (길이만)
|
||||
K0=10.42.1.7 K1=10.42.0.13 PW길이=19
|
||||
### 시험 0-① 발급 노드에 로그인하고 응답을 그대로 본다
|
||||
{"access_token":"<REDACTED 198자 · 화면에 잘려 나온 조각>"exp":1789620334,"iat":1789620274,"jti":"onltro:32cc3942-8475-c164-0629-9512d7325f7c","iss":"https://auth.hyeonworks.com/realms/master","typ":"Bearer","azp":"admin-cli","sid":"MjPiYcA-AWfeos1E8AaUtSeD","scope":"profile email
|
||||
### 시험 0-④ sid 만 뽑는다 (문서가 미검증으로 둔 줄)
|
||||
SID=MjPiYcA-AWfeos1E8AaUtSeD
|
||||
### 시험 0-⑥ CID (문서가 미검증으로 둔 줄)
|
||||
CID=2d7893fb-6003-4f0e-b6a8-d6e7e9e8fa25
|
||||
### 시험 0-⑦ 같은 질문을 두 노드에 (문서가 미검증으로 둔 루프)
|
||||
10.42.1.7 : 1
|
||||
10.42.0.13 : 1
|
||||
### 반대편 노드에 refresh 를 먼저 쓴다
|
||||
{"access_token":"<REDACTED 91자 · 화면에 잘려 나온 조각>
|
||||
@@ -0,0 +1,8 @@
|
||||
### 클레임 전체 (패딩을 채워 디코드)
|
||||
{"exp":1789620347,"iat":1789620287,"jti":"onltro:ba0c11cf-5e4a-a378-7268-4efd5cef32b8","iss":"https://auth.hyeonworks.com/realms/master","typ":"Bearer","azp":"admin-cli","sid":"jbFsOn6E0EPyjFf8PwNJ-1q7","scope":"profile email"}
|
||||
### 클레임 이름만
|
||||
azp exp iat iss jti scope sid typ
|
||||
### sub 이 있는가
|
||||
0
|
||||
### 문서의 형태(패딩 없이)는 어디서 끊기나
|
||||
0EPyjFf8PwNJ-1q7","scope":"profile email
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
발급 sid = 71afhj32x97hsvCFqQYB2KaV
|
||||
### 시험 0-⑧ 반대편 노드에서 refresh (기대 200, sid 같음)
|
||||
200
|
||||
갱신 sid = 71afhj32x97hsvCFqQYB2KaV
|
||||
### 시험 0-⑨ 반대편에서 로그아웃 (기대 204)
|
||||
204
|
||||
### 그 뒤 발급 노드에서 갱신 시도 (기대 400 invalid_grant / Session not active)
|
||||
{"error":"invalid_grant","error_description":"Session not active"}
|
||||
400
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
=== 시험 0b 전값 ===
|
||||
keycloak-0 clientSessions 3
|
||||
keycloak-0 sessions 3
|
||||
keycloak-1 clientSessions 0
|
||||
keycloak-1 sessions 0
|
||||
=== 발급 노드(keycloak-0) 에만 로그인 한 번 ===
|
||||
200
|
||||
=== 30초 기다린다 (스크레이프 간격 15초) ===
|
||||
=== 시험 0b 후값 ===
|
||||
keycloak-0 clientSessions 4
|
||||
keycloak-0 sessions 4
|
||||
keycloak-1 clientSessions 0
|
||||
keycloak-1 sessions 0
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
keycloak-0 = 10.42.1.7
|
||||
keycloak-1 = 10.42.0.13
|
||||
=== 시험 0c 시작값 ===
|
||||
keycloak-0 clientSessions 4
|
||||
keycloak-0 sessions 4
|
||||
keycloak-1 clientSessions 0
|
||||
keycloak-1 sessions 0
|
||||
=== ① 반대편(keycloak-1) 에 로그인 5회 ===
|
||||
200 200 200 200 200
|
||||
=== 5회 뒤 ===
|
||||
keycloak-0 clientSessions 4
|
||||
keycloak-0 sessions 4
|
||||
keycloak-1 clientSessions 5
|
||||
keycloak-1 sessions 5
|
||||
=== ② 발급 노드(keycloak-0) 에 로그인 5회 ===
|
||||
200 200 200 200 200
|
||||
=== 5회 더 뒤 ===
|
||||
keycloak-0 clientSessions 9
|
||||
keycloak-0 sessions 9
|
||||
keycloak-1 clientSessions 5
|
||||
keycloak-1 sessions 5
|
||||
=== 대조: PostgreSQL 에는 몇 건인가 ===
|
||||
count
|
||||
-------
|
||||
14
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
=== 0d-① 문장 로깅을 켠다 ===
|
||||
ALTER SYSTEM
|
||||
ALTER SYSTEM
|
||||
pg_reload_conf
|
||||
----------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
=== 0d-② 적용됐는지 읽는다 ===
|
||||
log_statement
|
||||
---------------
|
||||
all
|
||||
(1 row)
|
||||
|
||||
log_line_prefix
|
||||
-----------------
|
||||
%m [%p] %h
|
||||
(1 row)
|
||||
|
||||
K0=10.42.1.7 K1=10.42.0.13
|
||||
=== 0d-③ 로그인 한 번 · 반대편에서 refresh 한 번 ===
|
||||
SID=wITYiY7I4t8Ovy9wzwM1ewOA
|
||||
REFRESH_ON_K1=200
|
||||
=== 반대편 노드가 날린 문장만 ===
|
||||
2026-09-17 04:47:30.547 UTC [916] 10.42.0.13 LOG: execute <unnamed>: SELECT address, name, ip, coord, coordinated_by, last_update FROM JGROUPS_PING WHERE cluster_name=$1
|
||||
=== 그 sid 가 들어간 줄만 120자씩 ===
|
||||
2026-09-17 04:47:31.285 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '0', $2 = 'wITYiY7I4t8Ovy9wzwM1ewOA'
|
||||
2026-09-17 04:47:31.288 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '2d7893fb-6003-4f0e-b6a8-d6e7e9e8fa25', $2 = 'loca
|
||||
2026-09-17 04:47:31.294 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '0', $2 = 'wITYiY7I4t8Ovy9wzwM1ewOA'
|
||||
2026-09-17 04:47:31.295 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '2d7893fb-6003-4f0e-b6a8-d6e7e9e8fa25', $2 = 'loca
|
||||
2026-09-17 04:47:31.296 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = NULL, $2 = '1789620451', $3 = '{"ipAddress":"10.42
|
||||
2026-09-17 04:47:31.296 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '{"authMethod":"openid-connect","notes":{"clientId
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
=== 좀 지난 뒤 같은 필터를 다시 (K1=10.42.0.13) ===
|
||||
2026-09-17 04:47:43.568 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
2026-09-17 04:47:43.580 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
=== 그 sid 가 들어간 줄 전부 ===
|
||||
2026-09-17 04:47:31.285 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '0', $2 = 'wITYiY7I4t8Ovy9wzwM1ewOA'
|
||||
2026-09-17 04:47:31.288 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '2d7893fb-6003-4f0e-b6a8-d6e7e9e8fa25', $2 = 'loca
|
||||
2026-09-17 04:47:31.294 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '0', $2 = 'wITYiY7I4t8Ovy9wzwM1ewOA'
|
||||
2026-09-17 04:47:31.295 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '2d7893fb-6003-4f0e-b6a8-d6e7e9e8fa25', $2 = 'loca
|
||||
2026-09-17 04:47:31.296 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = NULL, $2 = '1789620451', $3 = '{"ipAddress":"10.42
|
||||
2026-09-17 04:47:31.296 UTC [948] 10.42.1.7 DETAIL: parameters: $1 = '{"authMethod":"openid-connect","notes":{"clientId
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
=== 04:47:31~04:47:50 사이 10.42.0.13 이 낸 모든 줄 ===
|
||||
2026-09-17 04:47:40.548 UTC [915] 10.42.0.13 LOG: execute S_34: SELECT address, name, ip, coord, coordinated_by, last_update FROM JGROUPS_PING WHERE cluster_name=$1
|
||||
2026-09-17 04:47:40.548 UTC [915] 10.42.0.13 DETAIL: parameters: $1 = 'ISPN'
|
||||
2026-09-17 04:47:40.548 UTC [916] 10.42.0.13 LOG: statement:
|
||||
2026-09-17 04:47:43.566 UTC [915] 10.42.0.13 LOG: statement: BEGIN
|
||||
2026-09-17 04:47:43.566 UTC [915] 10.42.0.13 LOG: execute S_36: DELETE from JGROUPS_PING WHERE address=$1
|
||||
2026-09-17 04:47:43.566 UTC [915] 10.42.0.13 DETAIL: parameters: $1 = 'uuid://00000000-0000-0000-0000-000000000003'
|
||||
2026-09-17 04:47:43.567 UTC [915] 10.42.0.13 LOG: execute S_37: INSERT INTO JGROUPS_PING (address, name, cluster_name, ip, coord, last_update, coordinated_by) values ($1
|
||||
2026-09-17 04:47:43.567 UTC [915] 10.42.0.13 DETAIL: parameters: $1 = 'uuid://00000000-0000-0000-0000-000000000003', $2 = 'keycloak-1-50073', $3 = 'ISPN', $4 = '10.42.0.
|
||||
2026-09-17 04:47:43.568 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
2026-09-17 04:47:43.578 UTC [915] 10.42.0.13 LOG: statement: BEGIN
|
||||
2026-09-17 04:47:43.578 UTC [915] 10.42.0.13 LOG: execute S_36: DELETE from JGROUPS_PING WHERE address=$1
|
||||
2026-09-17 04:47:43.578 UTC [915] 10.42.0.13 DETAIL: parameters: $1 = 'uuid://00000000-0000-0000-0000-000000000004'
|
||||
2026-09-17 04:47:43.580 UTC [915] 10.42.0.13 LOG: execute S_37: INSERT INTO JGROUPS_PING (address, name, cluster_name, ip, coord, last_update, coordinated_by) values ($1
|
||||
2026-09-17 04:47:43.580 UTC [915] 10.42.0.13 DETAIL: parameters: $1 = 'uuid://00000000-0000-0000-0000-000000000004', $2 = 'keycloak-0-25228', $3 = 'ISPN', $4 = '10.42.1.
|
||||
2026-09-17 04:47:43.580 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
2026-09-17 04:47:48.315 UTC [915] 10.42.0.13 LOG: execute S_34: SELECT address, name, ip, coord, coordinated_by, last_update FROM JGROUPS_PING WHERE cluster_name=$1
|
||||
2026-09-17 04:47:48.315 UTC [915] 10.42.0.13 DETAIL: parameters: $1 = 'ISPN'
|
||||
=== 같은 창의 줄 수 (pod 별) ===
|
||||
17
|
||||
26
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
K0(keycloak-0)=10.42.1.7 K1(keycloak-1)=10.42.0.13
|
||||
=== 캐시 전값 ===
|
||||
keycloak-0 clientSessions 10
|
||||
keycloak-0 sessions 10
|
||||
keycloak-1 clientSessions 5
|
||||
keycloak-1 sessions 5
|
||||
SID=j7eRVo7v08st1EAoQj1WLcjG
|
||||
MARK_BEFORE_REFRESH
|
||||
REFRESH_ON_K1=200
|
||||
=== 그 sid 가 들어간 DB 줄 — 어느 파드가 냈나 ===
|
||||
6 [915]
|
||||
6 [948]
|
||||
=== 같은 창에서 세션 테이블을 건드린 문장을 파드별로 ===
|
||||
6 [915]
|
||||
12 [948]
|
||||
=== 캐시 후값 (refresh 를 받은 keycloak-1 이 늘었나) ===
|
||||
keycloak-0 clientSessions 11
|
||||
keycloak-0 sessions 11
|
||||
keycloak-1 clientSessions 5
|
||||
keycloak-1 sessions 5
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
=== 반대편 노드(keycloak-1, pid 915) 가 날린 문장 — 문서의 여덟 줄과 대조 ===
|
||||
[915] 10.42.0.13 LOG: statement:
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[915] 10.42.0.13 LOG: statement: BEGIN
|
||||
[915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
[915] 10.42.0.13 LOG: statement: BEGIN
|
||||
[915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[915] 10.42.0.13 LOG: statement:
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[917] 10.42.0.13 LOG: statement:
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[915] 10.42.0.13 LOG: statement: BEGIN
|
||||
[915] 10.42.0.13 LOG: execute S_54/C_73: select puse1_0.OFFLINE_FLAG,puse1_0.USER_SESSION_ID,puse1_0.BROKER_SESSION_ID,puse1_0.CREATED_ON,puse1_0.DATA,puse1_0.LAST_
|
||||
[915] 10.42.0.13 LOG: execute <unnamed>/C_74: select puse1_0.VERSION from OFFLINE_USER_SESSION puse1_0 where puse1_0.USER_SESSION_ID=$1 and puse1_0.OFFLINE_FLAG=$2
|
||||
[915] 10.42.0.13 LOG: execute S_56/C_75: select pcse1_0.CLIENT_ID,pcse1_0.CLIENT_STORAGE_PROVIDER,pcse1_0.EXTERNAL_CLIENT_ID,pcse1_0.OFFLINE_FLAG,pcse1_0.USER_SESSI
|
||||
[915] 10.42.0.13 LOG: execute <unnamed>/C_76: select pcse1_0.VERSION from OFFLINE_CLIENT_SESSION pcse1_0 where pcse1_0.USER_SESSION_ID=$1 and pcse1_0.OFFLINE_FLAG=$
|
||||
[915] 10.42.0.13 LOG: execute <unnamed>: update OFFLINE_CLIENT_SESSION set TIMESTAMP=$1,VERSION=$2 where CLIENT_ID=$3 and CLIENT_STORAGE_PROVIDER=$4 and EXTERNAL_CL
|
||||
[915] 10.42.0.13 LOG: execute <unnamed>: update OFFLINE_USER_SESSION set LAST_SESSION_REFRESH=$1,VERSION=$2 where OFFLINE_FLAG=$3 and USER_SESSION_ID=$4 and VERSION
|
||||
[915] 10.42.0.13 LOG: execute <unnamed>: SET LOCAL synchronous_commit TO OFF
|
||||
[915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
[915] 10.42.0.13 LOG: statement: BEGIN
|
||||
[915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
[915] 10.42.0.13 LOG: statement: BEGIN
|
||||
[915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
[915] 10.42.0.13 LOG: statement: BEGIN
|
||||
[915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
[915] 10.42.0.13 LOG: statement: BEGIN
|
||||
[915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
[916] 10.42.0.13 LOG: statement:
|
||||
|
||||
=== 그 트랜잭션의 경계 (pid 915 의 BEGIN~COMMIT) ===
|
||||
2026-09-17 04:48:13.896 UTC [915] 10.42.0.13 LOG: statement: BEGIN
|
||||
2026-09-17 04:48:13.898 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
2026-09-17 04:48:13.908 UTC [915] 10.42.0.13 LOG: statement: BEGIN
|
||||
2026-09-17 04:48:13.912 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
2026-09-17 04:48:45.920 UTC [915] 10.42.0.13 LOG: statement: BEGIN
|
||||
2026-09-17 04:48:45.922 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
2026-09-17 04:48:45.933 UTC [915] 10.42.0.13 LOG: statement: BEGIN
|
||||
2026-09-17 04:48:45.934 UTC [915] 10.42.0.13 LOG: execute S_2: COMMIT
|
||||
=== 되돌리기 — 문장 로깅을 끈다 ===
|
||||
ALTER SYSTEM
|
||||
ALTER SYSTEM
|
||||
pg_reload_conf
|
||||
----------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
log_statement
|
||||
---------------
|
||||
none
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
=== a1 주입 1-① 매니페스트를 먼저 읽는다 ===
|
||||
# Experiment A-1 — cut the JGroups transport (TCP 7800) while leaving discovery alone.
|
||||
#
|
||||
# The point is to separate two things that are easy to conflate:
|
||||
#
|
||||
# discovery how the nodes FIND each other -> PostgreSQL JGROUPS_PING table
|
||||
# transport how they actually TALK -> TCP 7800
|
||||
#
|
||||
# Blocking only the transport produces a state that cannot happen on a single
|
||||
# node: both members stay registered in the database, so each believes the other
|
||||
# exists, yet no message gets through.
|
||||
#
|
||||
# kubectl apply -f deploy/lab/k8s/a1-block-jgroups-transport.yaml
|
||||
# kubectl -n keycloak-lab delete networkpolicy a1-block-jgroups-transport
|
||||
#
|
||||
# NetworkPolicy is an ALLOWLIST, not a firewall with deny rules. There is no way
|
||||
# to write "deny 7800". The moment a pod is selected by a policy carrying
|
||||
# policyTypes: [Ingress], every inbound port is denied unless a rule permits it.
|
||||
# So 7800 is blocked by *omission*: 8080 and 9000 are listed, 7800 is not.
|
||||
#
|
||||
# That makes the two allow rules load-bearing — get them wrong and the experiment
|
||||
# measures a dead Keycloak instead of a partitioned cluster:
|
||||
#
|
||||
# 8080 the HTTP endpoint. Traefik, the other pod's REST calls, and the probe
|
||||
# traffic all arrive here.
|
||||
# 9000 the management port: /health/started, /health/ready, /health/live and
|
||||
# /metrics. Losing it means the kubelet fails the readiness probe and
|
||||
# kills the pod — the cluster would break for the wrong reason.
|
||||
#
|
||||
# Both rules deliberately omit `from:`, which allows those ports from any source.
|
||||
# Narrowing the source is not the subject here; the 2-hop experiment already
|
||||
# established how to do that by label when it matters.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: a1-block-jgroups-transport
|
||||
namespace: keycloak-lab
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: keycloak
|
||||
policyTypes: [Ingress]
|
||||
ingress:
|
||||
- ports:
|
||||
- { port: 8080, protocol: TCP } # HTTP — must stay open
|
||||
- { port: 9000, protocol: TCP } # health + metrics — must stay open
|
||||
# 7800 is absent on purpose. That is the whole experiment.
|
||||
=== a1 주입 1-② 적용하고 시각 ===
|
||||
networkpolicy.networking.k8s.io/a1-block-jgroups-transport created
|
||||
13:53:51 적용
|
||||
@@ -0,0 +1,29 @@
|
||||
=== a1 검증 1 정책 ===
|
||||
NAME POD-SELECTOR AGE
|
||||
a1-block-jgroups-transport app=keycloak 11s
|
||||
Name: a1-block-jgroups-transport
|
||||
Namespace: keycloak-lab
|
||||
Created on: 2026-09-17 13:52:16 +0900 KST
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
Spec:
|
||||
PodSelector: app=keycloak
|
||||
Allowing ingress traffic:
|
||||
To Port: 8080/TCP
|
||||
To Port: 9000/TCP
|
||||
From: <any> (traffic not restricted by source)
|
||||
Not affecting egress traffic
|
||||
Policy Types: Ingress
|
||||
=== 파드가 죽지 않았는지 ===
|
||||
keycloak-0 1/1 Running 0 8m25s 10.42.1.7 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 8m47s 10.42.0.13 kc-lab-1 <none> <none>
|
||||
=== a1 검증 2 포트 셋 (K0=10.42.1.7) ===
|
||||
9000 200
|
||||
8080 200
|
||||
7800 000
|
||||
exit=7
|
||||
=== a1 검증 3 클러스터가 깨졌나 ===
|
||||
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"vendor_cluster_size","cache_manager":"keycloak","exported_node":"keycloak-1-50073","instance":"10.42.0.13:9000","job":"keycloak","node":"kc-lab-1","pod":"keycloak-1"},"value":[1789620750.808,"2"]},{"metric":{"__name__":"vendor_cluster_size","cache_manager":"keycloak","exported_node":"keycloak-0-25228","instance":"10.42.1.7:9000","job":"keycloak","node":"kc-lab-2","pod":"keycloak-0"},"value":[1789620750.808,"2"]}]}}
|
||||
=== 7800 은 16진수로 1E78 ===
|
||||
4: 0000000000000000FFFF000007012A0A:1E78 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 47139 1 00000000a06c8407 100 0 0 10 0
|
||||
11: 0000000000000000FFFF000007012A0A:1E78 0000000000000000FFFF00000D002A0A:E94D 01 00000000:00000000 02:000A3CB8 00000000 1000 0 47142 2 00000000c8c90f53 22 4 30 10 -1
|
||||
@@ -0,0 +1,3 @@
|
||||
=== a1 검증 4 conntrack — kc-lab-1 ===
|
||||
--- 같은 것을 2>/dev/null 없이 (요약 줄이 보인다) ---
|
||||
=== a1 검증 4 conntrack — kc-lab-2 ===
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
=== conntrack 이 게스트에 있나 ===
|
||||
sudo: conntrack: command not found
|
||||
(exit 0)
|
||||
--- 실행 파일 ---
|
||||
ls: cannot access '/usr/sbin/conntrack': No such file or directory
|
||||
dpkg-query: no packages found matching conntrack
|
||||
=== nf_conntrack 모듈과 표는 있나 ===
|
||||
6
|
||||
218 /proc/net/nf_conntrack
|
||||
=== 대안: /proc/net/nf_conntrack 에서 7800 을 찾는다 ===
|
||||
ipv4 2 tcp 6 86399 ESTABLISHED src=10.42.0.13 dst=10.42.1.7 sport=59725 dport=7800 src=10.42.1.7 dst=10.42.0.13 sport=7800 dport=59725 [ASSURED] mark=0 zone=0 use=2
|
||||
ipv4 2 tcp 6 85891 ESTABLISHED src=10.42.0.13 dst=10.42.1.7 sport=38439 dport=57800 src=10.42.1.7 dst=10.42.0.13 sport=57800 dport=38439 [ASSURED] mark=0 zone=0 use=2
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
=== 처방 검증: 두 노드에 conntrack 을 깐다 ===
|
||||
--- kc-lab-1 ---
|
||||
Setting up conntrack (1:1.4.7-1+b2) ...
|
||||
Processing triggers for man-db (2.11.2-2) ...
|
||||
tcp 6 86398 ESTABLISHED src=10.42.0.13 dst=10.42.1.7 sport=59725 dport=7800 src=10.42.1.7 dst=10.42.0.13 sport=7800 dport=59725 [ASSURED] mark=0 use=1
|
||||
tcp 6 85885 ESTABLISHED src=10.42.0.13 dst=10.42.1.7 sport=38439 dport=57800 src=10.42.1.7 dst=10.42.0.13 sport=57800 dport=38439 [ASSURED] mark=0 use=1
|
||||
--- kc-lab-2 ---
|
||||
Setting up conntrack (1:1.4.7-1+b2) ...
|
||||
Processing triggers for man-db (2.11.2-2) ...
|
||||
tcp 6 86397 ESTABLISHED src=10.42.0.13 dst=10.42.1.7 sport=59725 dport=7800 src=10.42.1.7 dst=10.42.0.13 sport=7800 dport=59725 [ASSURED] mark=0 use=1
|
||||
tcp 6 85884 ESTABLISHED src=10.42.0.13 dst=10.42.1.7 sport=38439 dport=57800 src=10.42.1.7 dst=10.42.0.13 sport=57800 dport=38439 [ASSURED] mark=0 use=1
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
=== a1 6-① 시각을 남기고 파드를 지운다 ===
|
||||
13:55:06 재시작
|
||||
pod "keycloak-0" deleted from keycloak-lab namespace
|
||||
=== a1 6-② 새 파드와 새 주소 ===
|
||||
keycloak-1 1/1 Running 0 9m54s 10.42.0.13 kc-lab-1 <none> <none>
|
||||
=== 60초 뒤 파드 상태 (분단된 노드가 Ready 를 잃었나) ===
|
||||
keycloak-0 1/1 Running 0 60s 10.42.1.17 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 10m 10.42.0.13 kc-lab-1 <none> <none>
|
||||
=== 멤버 수 ===
|
||||
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"vendor_cluster_size","cache_manager":"keycloak","exported_node":"keycloak-1-50073","instance":"10.42.0.13:9000","job":"keycloak","node":"kc-lab-1","pod":"keycloak-1"},"value":[1789620875.437,"1"]},{"metric":{"__name__":"vendor_cluster_size","cache_manager":"keycloak","exported_node":"keycloak-0-53888","instance":"10.42.1.17:9000","job":"keycloak","node":"kc-lab-2","pod":"keycloak-0"},"value":[1789620875.437,"1"]}]}}
|
||||
=== Service 뒤에 누가 남았나 ===
|
||||
Endpoints: 10.42.0.13:8080,10.42.1.17:8080
|
||||
@@ -0,0 +1,40 @@
|
||||
=== 분단이 확정되고 몇 분 뒤 ===
|
||||
14:22:18
|
||||
keycloak-0 0/1 Running 0 27m 10.42.1.17 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 37m 10.42.0.13 kc-lab-1 <none> <none>
|
||||
--- Ready 조건 ---
|
||||
PodReadyToStartContainers=True Initialized=True Ready=False ContainersReady=False PodScheduled=True
|
||||
PodReadyToStartContainers=True Initialized=True Ready=True ContainersReady=True PodScheduled=True
|
||||
--- readiness 프로브 설정 ---
|
||||
{"failureThreshold":3,"httpGet":{"path":"/health/ready","port":"management","scheme":"HTTP"},"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}
|
||||
--- Service Endpoints ---
|
||||
Endpoints: 10.42.0.13:8080
|
||||
--- 두 노드의 health/ready 를 직접 ---
|
||||
keycloak-0 ready=503
|
||||
keycloak-1 ready=200
|
||||
--- keycloak-0 의 실패 항목 ---
|
||||
{
|
||||
"status": "DOWN",
|
||||
"checks": [
|
||||
{
|
||||
"name": "Graceful Shutdown",
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Keycloak Initialized",
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Keycloak cluster health check",
|
||||
"status": "DOWN",
|
||||
"data": {
|
||||
"Failing since": "2026-09-17 04:54:25,769"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Keycloak database connections async health check"
|
||||
--- 멤버 수 ---
|
||||
"pod":"keycloak-1"}
|
||||
"1"]}
|
||||
"pod":"keycloak-0"}
|
||||
"1"]}]}}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
=== 문서가 적은 명령 그대로: describe pod | grep -A5 Conditions ===
|
||||
Conditions:
|
||||
Type Status
|
||||
PodReadyToStartContainers True
|
||||
Initialized True
|
||||
Ready False
|
||||
ContainersReady False
|
||||
=== 문서의 Ready 칸 뽑기 형태 ===
|
||||
zsh:5: no matches found: custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[0].ready,RESTARTS:.status.containerStatuses[0].restartCount
|
||||
=== EndpointSlice 형태 ===
|
||||
zsh:7: no matches found: custom-columns=NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
=== 이 호스트의 셸 ===
|
||||
/bin/zsh
|
||||
zsh
|
||||
=== 따옴표를 씌우면 ===
|
||||
keycloak-0 false 0
|
||||
keycloak-1 true 0
|
||||
NAME ADDR READY
|
||||
keycloak-lxk8h [10.42.0.13],[10.42.1.17] true,false
|
||||
=== 헬스 본문을 내는 명령 (문서가 JSON 을 실은 자리의 진짜 출처) ===
|
||||
{
|
||||
"status": "DOWN",
|
||||
"checks": [
|
||||
{
|
||||
"name": "Graceful Shutdown",
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Keycloak Initialized",
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Keycloak cluster health check",
|
||||
"status": "DOWN",
|
||||
"data": {
|
||||
"Failing since": "2026-09-17 04:54:25,769"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Keycloak database connections async health check",
|
||||
"status": "UP"
|
||||
}
|
||||
]
|
||||
}
|
||||
=== 밖에서 정문 (Host 헤더로 TLS 없이) ===
|
||||
200
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
분단 상태 K0=10.42.1.17 K1=10.42.0.13
|
||||
# [1] keycloak-0 에서 로그인
|
||||
sid=XliiKcW3DYw4hY_a3m2FX6e4# [2] keycloak-1 에서 refresh
|
||||
200
|
||||
# [3] keycloak-1 에서 로그아웃
|
||||
204
|
||||
# [4] keycloak-0 에서 재갱신 시도
|
||||
{"access_token":"<REDACTED 758자>","expires_in":60,"refresh_expires_in":1800,"refresh_token":"<REDACTED 612자>","token_type":"Bearer","not-before-policy":0,"session_state":"XliiKcW3DYw4hY_a3m2FX6e4","scope":"profile email"}
|
||||
200
|
||||
@@ -0,0 +1,14 @@
|
||||
a1 토큰 노출 경고 추가
|
||||
=== a1 되돌리기 1-① 시각을 남기고 정책을 지운다 ===
|
||||
14:23:52 해제
|
||||
networkpolicy.networking.k8s.io "a1-block-jgroups-transport" deleted from keycloak-lab namespace
|
||||
=== 30초 간격으로 멤버 수 ===
|
||||
14:24:22 "pod":"keycloak-1"} "1"]} "pod":"keycloak-0"} "1"]}]}}
|
||||
14:24:52 "pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}}
|
||||
14:25:22 "pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}}
|
||||
14:25:52 "pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}}
|
||||
=== 파드 상태 ===
|
||||
keycloak-0 1/1 Running 0 30m 10.42.1.17 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 40m 10.42.0.13 kc-lab-1 <none> <none>
|
||||
|
||||
[exited with code 0]
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
K0=10.42.1.17 K1=10.42.0.13
|
||||
=== a2 상주 탐침 파드 ===
|
||||
pod/a2-probe created
|
||||
pod/a2-probe condition met
|
||||
=== 환경변수 (길이만) ===
|
||||
K0=10.42.1.17 K1=10.42.0.13 PW길이=19
|
||||
=== 정지 전 네 경로 — 토큰을 파드 안 파일에 담는다 ===
|
||||
rt0=613자 rt1=613자 at=759자
|
||||
CID=2d7893fb-6003-4f0e-b6a8-d6e7e9e8fa25
|
||||
@@ -0,0 +1,18 @@
|
||||
=== 정지 전 네 경로 ===
|
||||
① 200
|
||||
② 200
|
||||
③ 200
|
||||
④ 200
|
||||
=== a2 주입 ① 시각과 replicas=0 ===
|
||||
14:27:23 정지
|
||||
deployment.apps/postgres scaled
|
||||
=== ② 파드가 사라질 때까지 ===
|
||||
pod/postgres-7b474b88c8-s6vdh condition met
|
||||
14:27:24 삭제완료
|
||||
=== 검증 1 파드와 Deployment ===
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
a2-probe 1/1 Running 0 10s 10.42.1.22 kc-lab-2 <none> <none>
|
||||
keycloak-0 1/1 Running 0 32m 10.42.1.17 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 42m 10.42.0.13 kc-lab-1 <none> <none>
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
postgres 0/0 0 0 51m
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
=== 정지 직후 네 경로 ===
|
||||
① 500
|
||||
② 500
|
||||
③ 500
|
||||
④ 500
|
||||
=== 500 의 본문 ===
|
||||
{"error":"unknown_error","error_description":"For more on this error consult the server log."}
|
||||
=== 서명 검증만 필요한 두 경로 ===
|
||||
JWKS 200
|
||||
well-known 200
|
||||
=== 커넥션 풀 로그 ===
|
||||
Caused by: java.net.ConnectException: Connection refused
|
||||
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:219)
|
||||
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:365)
|
||||
=== Ready 와 재시작 ===
|
||||
keycloak-0 true 0
|
||||
keycloak-1 true 0
|
||||
=== Endpoints ===
|
||||
NAME ADDR READY
|
||||
keycloak-lxk8h [10.42.0.13],[10.42.1.17] true,true
|
||||
=== 정문 (TLS 없이 Host 헤더로) ===
|
||||
200
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
14:28:13 ready=false,false, 정문=503 엔드포인트=false,false
|
||||
14:28:43 ready=false,false, 정문=503 엔드포인트=false,false
|
||||
14:29:13 ready=false,false, 정문=503 엔드포인트=false,false
|
||||
@@ -0,0 +1,19 @@
|
||||
=== a2 복구 시각과 replicas=1 ===
|
||||
14:29:20 복구
|
||||
deployment.apps/postgres scaled
|
||||
Waiting for deployment "postgres" rollout to finish: 0 out of 1 new replicas have been updated...
|
||||
Waiting for deployment "postgres" rollout to finish: 0 of 1 updated replicas are available...
|
||||
deployment "postgres" successfully rolled out
|
||||
14:29:56 ready=true,true, 정문=200 재시작=0,0,
|
||||
14:30:21 ready=true,true, 정문=200 재시작=0,0,
|
||||
14:30:46 ready=true,true, 정문=200 재시작=0,0,
|
||||
14:31:12 ready=true,true, 정문=200 재시작=0,0,
|
||||
=== 복구 뒤 네 경로 (④ 는 토큰이 만료됐을 수 있다) ===
|
||||
① 200
|
||||
② 200
|
||||
③ 200
|
||||
④ 401
|
||||
=== 탐침 파드를 지운다 ===
|
||||
pod "a2-probe" deleted from keycloak-lab namespace
|
||||
|
||||
[exited with code 0]
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
=== a3 설계 확인 ① 문장 로깅 켜기 ===
|
||||
t
|
||||
(1 row)
|
||||
|
||||
log_statement
|
||||
---------------
|
||||
all
|
||||
(1 row)
|
||||
|
||||
=== ② 탐침 파드 ===
|
||||
pod/a3-probe created
|
||||
pod/a3-probe condition met
|
||||
=== ③ 길이만 ===
|
||||
19
|
||||
K0=10.42.1.17 PW길이=19
|
||||
=== ④ 로그인 한 번 ===
|
||||
200
|
||||
=== ⑤ 그 로그인의 트랜잭션 ===
|
||||
2026-09-17 05:31:55.093 UTC [41] LOG: statement: BEGIN
|
||||
2026-09-17 05:31:55.099 UTC [41] LOG: execute S_6: COMMIT
|
||||
2026-09-17 05:31:55.101 UTC [41] LOG: statement: BEGIN
|
||||
2026-09-17 05:31:55.104 UTC [41] LOG: execute <unnamed>: insert into OFFLINE_USER_SESSION (BROKER_SESSION_ID,CREATED_ON,DATA,LAST_SESSION_REFRESH,REALM_ID,REMEMBER_ME,USER_ID,VERSION,OFFLINE_FLAG,USER_SESSION_ID) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)
|
||||
2026-09-17 05:31:55.104 UTC [41] LOG: execute <unnamed>: insert into OFFLINE_CLIENT_SESSION (DATA,REALM_ID,TIMESTAMP,VERSION,CLIENT_ID,CLIENT_STORAGE_PROVIDER,EXTERNAL_CLIENT_ID,OFFLINE_FLAG,USER_SESSION_ID) values ($1,$2,$3,$4,$5,$6,$7,$8,$9)
|
||||
2026-09-17 05:31:55.104 UTC [41] LOG: execute <unnamed>: SET LOCAL synchronous_commit TO OFF
|
||||
2026-09-17 05:31:55.104 UTC [41] LOG: execute S_6: COMMIT
|
||||
2026-09-17 05:31:59.694 UTC [40] LOG: statement: BEGIN
|
||||
2026-09-17 05:31:59.696 UTC [40] LOG: execute S_1: COMMIT
|
||||
=== ⑥ 문장 로깅 끄기 ===
|
||||
(1 row)
|
||||
|
||||
log_statement
|
||||
---------------
|
||||
none
|
||||
(1 row)
|
||||
|
||||
=== 커밋·WAL 설정 네 줄 ===
|
||||
name | setting | unit | source
|
||||
------------------------+---------+------+---------
|
||||
commit_delay | 0 | | default
|
||||
synchronous_commit | on | | default
|
||||
wal_writer_delay | 200 | ms | default
|
||||
wal_writer_flush_after | 128 | 8kB | default
|
||||
(4 rows)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
=== a3 4-① 세션 비우기 ===
|
||||
DELETE 5
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
=== 5. 파드 셋 ===
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
a3-probe 1/1 Running 0 30s 10.42.1.24 kc-lab-2 <none> <none>
|
||||
keycloak-0 1/1 Running 0 38m 10.42.1.17 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 48m 10.42.0.13 kc-lab-1 <none> <none>
|
||||
postgres-7b474b88c8-sspdm 1/1 Running 0 4m38s 10.42.1.23 kc-lab-2 <none> <none>
|
||||
=== 주입 1-② 루프 파일을 파드에 밀어 넣는다 ===
|
||||
18 /tmp/a3-login-loop.sh
|
||||
@@ -0,0 +1,18 @@
|
||||
=== 8초 뒤 쌓인 수 ===
|
||||
0 /tmp/sids
|
||||
=== 시도 ① --grace-period=0 --force ===
|
||||
14:34:15.621 종료
|
||||
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
|
||||
pod "postgres-7b474b88c8-sspdm" force deleted from keycloak-lab namespace
|
||||
14:34:15.722 반환
|
||||
=== 루프 출력 ===
|
||||
=== 파드 상태 ===
|
||||
NAME READY RESTARTS AGE
|
||||
postgres-7b474b88c8-mh86k true 0 2026-09-17T05:32:42Z
|
||||
=== 클라이언트가 200 받은 수 vs DB 행 수 ===
|
||||
0 /tmp/sids
|
||||
count
|
||||
-------
|
||||
217
|
||||
(1 row)
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
=== 왜 0 줄인가 — 파일에 개행이 없다 ===
|
||||
0 /tmp/sids
|
||||
9384 /tmp/sids
|
||||
0022240 K K E Q - g O y
|
||||
0022250
|
||||
=== busybox sed 가 끝에 개행을 안 붙인다 ===
|
||||
0000000 A B C
|
||||
0000003
|
||||
=== 처방: echo 로 감싼다 ===
|
||||
처방 결과: 10 줄 / 250 바이트
|
||||
iAxu1SRCu_c7uWTAka5MK-Xa
|
||||
4PU8l__EjhBWQVQTCnjyg_fD
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
19 /tmp/a3-login-loop.sh
|
||||
=== 8초 뒤 쌓인 수 ===
|
||||
109 /tmp/sids
|
||||
=== 시도 ① --grace-period=0 --force ===
|
||||
14:35:47.693 종료
|
||||
pod "postgres-7b474b88c8-mh86k" force deleted from keycloak-lab namespace
|
||||
14:35:47.797 반환
|
||||
=== 루프 출력 ===
|
||||
=== 새 파드 ===
|
||||
NAME READY RESTARTS
|
||||
postgres-7b474b88c8-prlxx true 0
|
||||
=== 클라이언트 200 수 vs DB 행 수 ===
|
||||
292 /tmp/sids
|
||||
count
|
||||
-------
|
||||
296
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
=== 시도 ① 검증 — 재시작 횟수와 파드 나이 ===
|
||||
NAME RESTARTS START
|
||||
postgres-7b474b88c8-prlxx 0 2026-09-17T05:34:14Z
|
||||
=== crash recovery 로그가 있나 ===
|
||||
2026-09-17 05:34:14.924 UTC [1] LOG: starting PostgreSQL 16.15 on x86_64-pc-linux-musl, compiled by gcc (Alpine 15.2.0) 15.2.0, 64-bit
|
||||
2026-09-17 05:34:14.939 UTC [27] LOG: database system was shut down at 2026-09-17 05:34:13 UTC
|
||||
|
||||
=== 시도 ② kill -9 1 ===
|
||||
113 /tmp/sids
|
||||
14:36:29.106 SIGKILL
|
||||
=== 시도 ② 결과 ===
|
||||
NAME READY RESTARTS
|
||||
postgres-7b474b88c8-prlxx true 0
|
||||
400 /tmp/sids
|
||||
count
|
||||
-------
|
||||
400
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
=== 시도 ③ 준비 — ps 로 무엇을 죽일지 본다 ===
|
||||
PID USER TIME COMMAND
|
||||
1 postgres 0:00 postgres
|
||||
25 postgres 0:00 postgres: checkpointer
|
||||
26 postgres 0:00 postgres: background writer
|
||||
28 postgres 0:00 postgres: walwriter
|
||||
29 postgres 0:00 postgres: autovacuum launcher
|
||||
30 postgres 0:00 postgres: logical replication launcher
|
||||
39 postgres 0:00 postgres: keycloak keycloak 10.42.1.17(44654) idle
|
||||
40 postgres 0:00 postgres: keycloak keycloak 10.42.1.17(44660) idle
|
||||
41 postgres 0:00 postgres: keycloak keycloak 10.42.1.17(44670) idle
|
||||
42 postgres 0:00 postgres: keycloak keycloak 10.42.1.17(44686) idle
|
||||
43 postgres 0:00 postgres: keycloak keycloak 10.42.1.17(44690) idle
|
||||
=== 죽이기 직전 쌓인 수 ===
|
||||
113 /tmp/sids
|
||||
죽일 백엔드 PID=39
|
||||
14:37:10.925 백엔드 SIGKILL
|
||||
=== 시도 ③ 결과 ===
|
||||
NAME READY RESTARTS
|
||||
postgres-7b474b88c8-prlxx true 0
|
||||
--- crash recovery 로그 ---
|
||||
2026-09-17 05:35:36.810 UTC [1] LOG: server process (PID 39) was terminated by signal 9: Killed
|
||||
2026-09-17 05:35:36.810 UTC [1] LOG: terminating any other active server processes
|
||||
2026-09-17 05:35:36.817 UTC [1] LOG: all server processes terminated; reinitializing
|
||||
2026-09-17 05:35:36.863 UTC [206] LOG: database system was not properly shut down; automatic recovery in progress
|
||||
2026-09-17 05:35:36.885 UTC [207] LOG: checkpoint starting: end-of-recovery immediate wait
|
||||
--- 클라이언트 200 수 ---
|
||||
395 /tmp/sids
|
||||
--- DB 행 수 ---
|
||||
count
|
||||
-------
|
||||
392
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
=== 크래시 흔적 여섯 줄 ===
|
||||
2026-09-17 05:34:14.944 UTC [1] LOG: database system is ready to accept connections
|
||||
2026-09-17 05:35:36.810 UTC [1] LOG: server process (PID 39) was terminated by signal 9: Killed
|
||||
2026-09-17 05:35:36.817 UTC [1] LOG: all server processes terminated; reinitializing
|
||||
2026-09-17 05:35:36.863 UTC [206] LOG: database system was not properly shut down; automatic recovery in progress
|
||||
2026-09-17 05:35:36.865 UTC [206] LOG: redo starts at 0/1F80A00
|
||||
2026-09-17 05:35:36.873 UTC [206] LOG: redo done at 0/21D72B8 system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
|
||||
2026-09-17 05:35:36.909 UTC [207] LOG: checkpoint complete: wrote 243 buffers (1.5%); 0 WAL file(s) added, 0 removed, 1 recycled; write=0.008 s, sync=0.009 s, total=0.029 s; sync files=26, longest=0.007 s, average=0.001 s; distance=2397 kB, estimate=2397 kB; lsn=0/21D8048, redo lsn=0/21D8048
|
||||
2026-09-17 05:35:36.912 UTC [1] LOG: database system is ready to accept connections
|
||||
=== 관찰 ① 클라이언트 sid 목록 ===
|
||||
395 /tmp/client-sids.txt
|
||||
uyMM_LOM5QgdNXZPymOt_d5-
|
||||
iNI2VuirdOjA-FT7iwt7F21I
|
||||
01uQ99zaBSaNtNt4v5tT-ned
|
||||
=== ② 총계 ===
|
||||
count
|
||||
-------
|
||||
392
|
||||
(1 row)
|
||||
|
||||
=== ③ 값만 파일로 ===
|
||||
392 /tmp/db-sids.txt
|
||||
=== ④ 정렬해서 왼쪽 전용만 ===
|
||||
395 /tmp/a.txt
|
||||
392 /tmp/b.txt
|
||||
787 total
|
||||
=== ⑤ 유실 건수 ===
|
||||
3
|
||||
=== 유실된 sid (있으면) ===
|
||||
KvrWnKhKue4DlxozYc63HU4E
|
||||
S1iYLwU5oASbsePYH2Q1SB_A
|
||||
cUFSAEsClRh-OS-KvNnaa1Lu
|
||||
@@ -0,0 +1,15 @@
|
||||
=== a3 되돌리기 ===
|
||||
log_statement
|
||||
---------------
|
||||
none
|
||||
(1 row)
|
||||
|
||||
DELETE 392
|
||||
statefulset.apps/keycloak restarted
|
||||
pod "a3-probe" deleted from keycloak-lab namespace
|
||||
=== DB 건강 ===
|
||||
count
|
||||
-------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
=== a4 1-② virsh uri ===
|
||||
qemu:///system
|
||||
|
||||
=== 주입 전 ① VM 전원 ===
|
||||
Id Name State
|
||||
-----------------------------
|
||||
13 kc-lab-1 running
|
||||
14 kc-lab-2 running
|
||||
15 kc-lab-edge running
|
||||
|
||||
=== ② 노드와 파드 배치 ===
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
kc-lab-1 Ready control-plane 72m v1.36.4+k3s1
|
||||
kc-lab-2 Ready <none> 71m v1.36.4+k3s1
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
keycloak-0 1/1 Running 0 37s 10.42.1.27 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 60s 10.42.0.14 kc-lab-1 <none> <none>
|
||||
postgres-7b474b88c8-prlxx 1/1 Running 0 3m29s 10.42.1.26 kc-lab-2 <none> <none>
|
||||
=== PVC 와 그 PV 가 요구하는 노드 ===
|
||||
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
|
||||
postgres-data Bound pvc-fe269834-3dd1-4b1f-82f6-a53413310a30 5Gi RWO local-path <unset> 63m
|
||||
PV=pvc-fe269834-3dd1-4b1f-82f6-a53413310a30
|
||||
{"required":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"kubernetes.io/hostname","operator":"In","values":["kc-lab-2"]}]}]}}
|
||||
=== 관측 스택이 어느 노드에 ===
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
grafana-845b5678cf-bblgz 1/1 Running 0 59m 10.42.0.11 kc-lab-1 <none> <none>
|
||||
node-exporter-82mmn 1/1 Running 0 59m 192.168.122.12 kc-lab-2 <none> <none>
|
||||
node-exporter-g688j 1/1 Running 0 59m 192.168.122.11 kc-lab-1 <none> <none>
|
||||
prometheus-6774f94f7c-pj8w9 1/1 Running 0 59m 10.42.0.12 kc-lab-1 <none> <none>
|
||||
@@ -0,0 +1,27 @@
|
||||
=== 4a ① kc-lab-2 에 무엇이 있나 (영향 범위) ===
|
||||
keycloak-lab keycloak-0
|
||||
keycloak-lab postgres-7b474b88c8-prlxx
|
||||
kube-system svclb-traefik-72a92206-5jpxg
|
||||
observability node-exporter-82mmn
|
||||
=== ② 차단 시각 ===
|
||||
14:39:28 차단
|
||||
=== ③ 전원을 뽑는다 ===
|
||||
Domain 'kc-lab-2' destroyed
|
||||
|
||||
=== 하이퍼바이저가 뭐라 하나 ===
|
||||
Id Name State
|
||||
------------------------------
|
||||
13 kc-lab-1 running
|
||||
15 kc-lab-edge running
|
||||
- kc-lab-2 shut off
|
||||
|
||||
=== 10초 뒤 쿠버네티스 ===
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
kc-lab-1 Ready control-plane 72m v1.36.4+k3s1
|
||||
kc-lab-2 Ready <none> 71m v1.36.4+k3s1
|
||||
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
|
||||
keycloak-0 1/1 Running 0 58s 10.42.1.27 kc-lab-2 <none> <none>
|
||||
keycloak-1 1/1 Running 0 81s 10.42.0.14 kc-lab-1 <none> <none>
|
||||
postgres-7b474b88c8-prlxx 1/1 Running 0 3m50s 10.42.1.26 kc-lab-2 <none> <none>
|
||||
=== 정문 (터미널 C: 밖에서) ===
|
||||
000
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
--- 14:39:56 ---
|
||||
kc-lab-1 Ready kc-lab-2 Ready | 파드: keycloak-0 Running kc-lab-2;keycloak-1 Running kc-lab-1;postgres-7b474b88c8-prlxx Running kc-lab-2; | 정문=000
|
||||
--- 14:40:34 ---
|
||||
kc-lab-1 Ready kc-lab-2 NotReady | 파드: keycloak-0 Running kc-lab-2;keycloak-1 Running kc-lab-1;postgres-7b474b88c8-prlxx Running kc-lab-2; | 정문=503
|
||||
--- 14:41:08 ---
|
||||
kc-lab-1 Ready kc-lab-2 NotReady | 파드: keycloak-0 Running kc-lab-2;keycloak-1 Running kc-lab-1;postgres-7b474b88c8-prlxx Running kc-lab-2; | 정문=503
|
||||
--- 14:41:38 ---
|
||||
kc-lab-1 Ready kc-lab-2 NotReady | 파드: keycloak-0 Running kc-lab-2;keycloak-1 Running kc-lab-1;postgres-7b474b88c8-prlxx Running kc-lab-2; | 정문=503
|
||||
--- 14:42:08 ---
|
||||
kc-lab-1 Ready kc-lab-2 NotReady | 파드: keycloak-0 Running kc-lab-2;keycloak-1 Running kc-lab-1;postgres-7b474b88c8-prlxx Running kc-lab-2; | 정문=503
|
||||
--- 14:42:41 ---
|
||||
kc-lab-1 Ready kc-lab-2 NotReady | 파드: keycloak-0 Running kc-lab-2;keycloak-1 Running kc-lab-1;postgres-7b474b88c8-prlxx Running kc-lab-2; | 정문=503
|
||||
uccessfulCreate statefulset/keycloak Create Pod keycloak-0 in StatefulSet keycloak successful
|
||||
3m38s Normal Started pod/keycloak-0 Container started
|
||||
3m38s Normal Created pod/keycloak-0 Container created
|
||||
3m38s Normal Pulled pod/keycloak-0 Container image "quay.io/keycloak/keycloak:26.7.0" already present on machine and can be accessed by the pod
|
||||
3m28s Warning Unhealthy pod/keycloak-0 Startup probe failed: Get "http://10.42.1.27:9000/health/started": dial tcp 10.42.1.27:9000: connect: connection refused
|
||||
117s Warning NodeNotReady pod/keycloak-0 Node is not ready
|
||||
117s Warning NodeNotReady pod/postgres-7b474b88c8-prlxx Node is not ready
|
||||
6s Warning Unhealthy pod/keycloak-1 Readiness probe failed: Get "http://10.42.0.14:9000/health/ready": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
=== 차단 +약 6분 — 축출이 일어났나 ===
|
||||
14:46:15
|
||||
keycloak-0 Terminating kc-lab-2
|
||||
keycloak-1 Running kc-lab-1
|
||||
postgres-7b474b88c8-5zp6v Pending <none>
|
||||
postgres-7b474b88c8-prlxx Terminating kc-lab-2
|
||||
kc-lab-1 Ready
|
||||
kc-lab-2 NotReady
|
||||
--- StatefulSet 파드와 Deployment 파드의 처지가 다른가 ---
|
||||
keycloak-0 Running 2026-09-17T05:44:17Z
|
||||
keycloak-1 Running <none>
|
||||
postgres-7b474b88c8-5zp6v Pending <none>
|
||||
postgres-7b474b88c8-prlxx Running 2026-09-17T05:44:17Z
|
||||
=== 복구: VM 을 다시 켠다 ===
|
||||
14:46:15 복구
|
||||
Domain 'kc-lab-2' started
|
||||
|
||||
kc-lab-1 Ready
|
||||
kc-lab-2 NotReady
|
||||
keycloak-0 1/1 Terminating kc-lab-2
|
||||
keycloak-1 0/1 Running kc-lab-1
|
||||
postgres-7b474b88c8-5zp6v 0/1 Pending <none>
|
||||
postgres-7b474b88c8-prlxx 1/1 Terminating kc-lab-2
|
||||
정문=503
|
||||
|
||||
[exited with code 0]
|
||||
--- 14:47:55 복구 확인 ---
|
||||
kc-lab-1 Ready
|
||||
kc-lab-2 NotReady
|
||||
keycloak-0 1/1 Terminating kc-lab-2
|
||||
keycloak-1 0/1 Running kc-lab-1
|
||||
postgres-7b474b88c8-5zp6v 0/1 Pending <none>
|
||||
postgres-7b474b88c8-prlxx 1/1 Terminating kc-lab-2
|
||||
정문=503
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
14:48:49 kc-lab-1=Ready kc-lab-2=NotReady | keycloak-0:Terminating keycloak-1:Running postgres-7b474b88c8-5zp6v:Pending postgres-7b474b88c8-prlxx:Terminating | 정문=503
|
||||
14:49:34 kc-lab-1=Ready kc-lab-2=NotReady | keycloak-0:Terminating keycloak-1:Running postgres-7b474b88c8-5zp6v:Pending postgres-7b474b88c8-prlxx:Terminating | 정문=503
|
||||
14:50:19 kc-lab-1=Ready kc-lab-2=NotReady | keycloak-0:Terminating keycloak-1:Running postgres-7b474b88c8-5zp6v:Pending postgres-7b474b88c8-prlxx:Terminating | 정문=503
|
||||
14:51:05 kc-lab-1=Ready kc-lab-2=Ready | keycloak-0:Unknown keycloak-1:Running postgres-7b474b88c8-5zp6v:ContainerCreating postgres-7b474b88c8-prlxx:Unknown | 정문=503
|
||||
14:51:50 kc-lab-1=Ready kc-lab-2=Ready | keycloak-0:Running keycloak-1:Running postgres-7b474b88c8-5zp6v:Running | 정문=200
|
||||
14:48:49 kc-lab-1=Ready kc-lab-2=NotReady | keycloak-0:Terminating keycloak-1:Running postgres-7b474b88c8-5zp6v:Pending postgres-7b474b88c8-prlxx:Terminating | 정문=503
|
||||
14:49:34 kc-lab-1=Ready kc-lab-2=NotReady | keycloak-0:Terminating keycloak-1:Running postgres-7b474b88c8-5zp6v:Pending postgres-7b474b88c8-prlxx:Terminating | 정문=503
|
||||
14:50:19 kc-lab-1=Ready kc-lab-2=NotReady | keycloak-0:Terminating keycloak-1:Running postgres-7b474b88c8-5zp6v:Pending postgres-7b474b88c8-prlxx:Terminating | 정문=503
|
||||
14:51:05 kc-lab-1=Ready kc-lab-2=Ready | keycloak-0:Unknown keycloak-1:Running postgres-7b474b88c8-5zp6v:ContainerCreating postgres-7b474b88c8-prlxx:Unknown | 정문=503
|
||||
14:51:50 kc-lab-1=Ready kc-lab-2=Ready | keycloak-0:Running keycloak-1:Running postgres-7b474b88c8-5zp6v:Running | 정문=200
|
||||
|
||||
[exited with code 0]
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
=== 원인: 유닛이 --token-file 로 지운 파일을 가리킨다 ===
|
||||
'--token-file' \
|
||||
'/home/donghyeon/node-token' \
|
||||
|
||||
=== 처방 ① 그 파일을 되돌려 놓는다 (값은 이 기계 밖으로 안 나간다) ===
|
||||
109
|
||||
=== agent 가 뜨나 ===
|
||||
active
|
||||
kc-lab-1 Ready
|
||||
kc-lab-2 Ready
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
=== 처방 ② 토큰을 root 만 읽는 자리로 옮기고 유닛을 그쪽으로 돌린다 ===
|
||||
bash: line 1: /etc/rancher/node-token: Permission denied
|
||||
'--token-file' \
|
||||
'/etc/rancher/node-token' \
|
||||
=== 홈의 파일을 지운 뒤에도 뜨나 ===
|
||||
ls: cannot access '/home/donghyeon/node-token': No such file or directory
|
||||
active
|
||||
kc-lab-1 Ready
|
||||
kc-lab-2 Ready
|
||||
=== 재부팅을 견디는지 확인 — agent 를 완전히 다시 시작 ===
|
||||
active
|
||||
kc-lab-1 Ready
|
||||
kc-lab-2 Ready
|
||||
=== 옮긴 파일의 권한과 길이 ===
|
||||
-rw------- 1 root root 109 Sep 17 05:50 /etc/rancher/node-token
|
||||
109
|
||||
=== 유닛이 가리키는 자리 ===
|
||||
'--token-file' \
|
||||
'/etc/rancher/node-token' \
|
||||
=== 노드 ===
|
||||
kc-lab-1 Ready
|
||||
kc-lab-2 Ready
|
||||
@@ -0,0 +1,17 @@
|
||||
K0(keycloak-0, kc-lab-2)=10.42.1.30 K1(keycloak-1, kc-lab-1)=10.42.0.14
|
||||
=== 문서의 [kc-lab-1] 블록을 그대로 — 게스트 셸에 $K1 이 있나 ===
|
||||
게스트 셸의 K1=[]
|
||||
=== 시도 ① filter FORWARD (보내는 쪽 노드에) ===
|
||||
14:54:11 주입
|
||||
--- 규칙과 카운터 ---
|
||||
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
|
||||
num pkts bytes target prot opt in out source destination
|
||||
1 9 516 DROP 6 -- * * 0.0.0.0/0 10.42.1.30 tcp dpt:57800
|
||||
2 22 2767 DROP 6 -- * * 0.0.0.0/0 10.42.1.30 tcp dpt:7800
|
||||
3 921 1849K KUBE-ROUTER-FORWARD 0 -- * * 0.0.0.0/0 0.0.0.0/0 /* kube-router netpol - TEMCG2JMHZYE7H7T */
|
||||
--- 멤버 수 ---
|
||||
"pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}}
|
||||
=== 시도 ① 되돌리기 ===
|
||||
Chain FORWARD (policy ACCEPT)
|
||||
num target prot opt source destination
|
||||
1 KUBE-ROUTER-FORWARD 0 -- 0.0.0.0/0 0.0.0.0/0 /* kube-router netpol - TEMCG2JMHZYE7H7T */
|
||||
@@ -0,0 +1,15 @@
|
||||
=== 시도 ② raw PREROUTING 을 보내는 쪽(kc-lab-2)에 ===
|
||||
14:55:06 주입
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
num pkts bytes target prot opt in out source destination
|
||||
1 0 0 DROP 6 -- * * 0.0.0.0/0 10.42.1.30 tcp dpt:57800
|
||||
2 0 0 DROP 6 -- * * 0.0.0.0/0 10.42.1.30 tcp dpt:7800
|
||||
"pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}}
|
||||
=== 시도 ② 되돌리기 ===
|
||||
=== 시도 ③ raw PREROUTING 을 받는 쪽(kc-lab-1)에 — 목적지는 keycloak-1 ===
|
||||
14:55:57 주입
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
num pkts bytes target prot opt in out source destination
|
||||
1 16 916 DROP 6 -- * * 0.0.0.0/0 10.42.0.14 tcp dpt:57800
|
||||
2 20 3257 DROP 6 -- * * 0.0.0.0/0 10.42.0.14 tcp dpt:7800
|
||||
"pod":"keycloak-1"} "1"]} "pod":"keycloak-0"} "1"]}]}}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
=== 한 방향만 막은 채로 2분 더 — 다시 붙나 ===
|
||||
14:57:49 멤버="pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}} | coord=
|
||||
14:58:24 멤버="pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}} | coord=
|
||||
14:58:59 멤버="pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}} | coord=
|
||||
14:59:34 멤버="pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}} | coord=
|
||||
|
||||
[exited with code 0]
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
=== a5 네 번째 주입 — 양방향 ===
|
||||
15:00:13 주입
|
||||
--- 두 노드의 규칙과 카운터 ---
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
21 1208 DROP 6 -- * * 0.0.0.0/0 10.42.0.14 tcp dpt:57800
|
||||
21 3317 DROP 6 -- * * 0.0.0.0/0 10.42.0.14 tcp dpt:7800
|
||||
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
|
||||
pkts bytes target prot opt in out source destination
|
||||
0 0 DROP 6 -- * * 0.0.0.0/0 10.42.1.30 tcp dpt:57800
|
||||
19 2595 DROP 6 -- * * 0.0.0.0/0 10.42.1.30 tcp dpt:7800
|
||||
--- 멤버 수 ---
|
||||
"pod":"keycloak-1"} "1"]} "pod":"keycloak-0"} "1"]}]}}
|
||||
--- coord 가 둘인가 ---
|
||||
name | coord
|
||||
------------------+-------
|
||||
keycloak-0-13476 | t
|
||||
keycloak-1-8002 | t
|
||||
(2 rows)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
=== a5 되돌리기 — 두 노드의 raw 체인을 비운다 ===
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
num target prot opt source destination
|
||||
Chain PREROUTING (policy ACCEPT)
|
||||
num target prot opt source destination
|
||||
=== 다시 붙었나 ===
|
||||
"pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}}
|
||||
name | coord
|
||||
------------------+-------
|
||||
keycloak-0-13476 | f
|
||||
keycloak-1-8002 | t
|
||||
(2 rows)
|
||||
|
||||
keycloak-0 1/1 Running
|
||||
keycloak-1 1/1 Running
|
||||
postgres-7b474b88c8-5zp6v 1/1 Running
|
||||
@@ -0,0 +1,29 @@
|
||||
K0=10.42.1.30 K1=10.42.0.14 PG=10.42.1.29
|
||||
=== a6 시도 ① eth0 (예제 그대로) ===
|
||||
Cannot find device "eth0"
|
||||
=== ② 이 게스트에 무엇이 있나 ===
|
||||
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
|
||||
enp1s0 UP 52:54:00:aa:bb:12 <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||
flannel.1 UNKNOWN da:f1:1f:7f:9e:da <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||
cni0 UP c6:f2:76:f6:72:0e <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||
veth5f5079ef@if2 UP 7a:c7:1b:85:f0:92 <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||
veth5ef1875b@if2 UP 82:ef:56:9c:1d:52 <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||
veth8d0ac36c@if2 UP 56:50:6c:30:63:ac <BROADCAST,MULTICAST,UP,LOWER_UP>
|
||||
=== 시도 ② 미검증 두 줄 — 물리 쪽 ===
|
||||
IP 10.42.1.30.7800 > 10.42.0.14.50799: Flags [.], ack 208, win 509, options [nop,nop,TS val 2179731813 ecr 4085265222], length 0
|
||||
06:02:02.268760 IP 192.168.122.12.53654 > 192.168.122.11.8472: OTV, flags [I] (0x08), overlay 0, instance 1
|
||||
IP 10.42.1.30.7800 > 10.42.0.14.50799: Flags [P.], seq 238:336, ack 208, win 509, options [nop,nop,TS val 2179731905 ecr 4085265222], length 98
|
||||
06:02:02.309848 IP 192.168.122.11.60237 > 192.168.122.12.8472: OTV, flags [I] (0x08), overlay 0, instance 1
|
||||
IP 10.42.0.14.50799 > 10.42.1.30.7800: Flags [.], ack 336, win 823, options [nop,nop,TS val 4085265356 ecr 2179731905], length 0
|
||||
5 packets captured
|
||||
5 packets received by filter
|
||||
0 packets dropped by kernel
|
||||
=== 터널 쪽 ===
|
||||
06:02:05.445308 IP 10.42.0.14.52916 > 10.42.1.29.5432: Flags [P.], seq 2469151212:2469151253, ack 2840346855, win 502, options [nop,nop,TS val 1040631333 ecr 678493794], length 41
|
||||
06:02:05.445613 IP 10.42.1.29.5432 > 10.42.0.14.52916: Flags [P.], seq 1:343, ack 41, win 502, options [nop,nop,TS val 678500272 ecr 1040631333], length 342
|
||||
06:02:05.446042 IP 10.42.0.14.52916 > 10.42.1.29.5432: Flags [.], ack 343, win 502, options [nop,nop,TS val 1040631334 ecr 678500272], length 0
|
||||
06:02:08.968064 IP 10.42.0.14.52916 > 10.42.1.29.5432: Flags [P.], seq 41:82, ack 343, win 502, options [nop,nop,TS val 1040634856 ecr 678500272], length 41
|
||||
06:02:08.968065 IP 10.42.0.14.52928 > 10.42.1.29.5432: Flags [P.], seq 617750272:617750278, ack 754926471, win 502, options [nop,nop,TS val 1040634856 ecr 678493795], length 6
|
||||
5 packets captured
|
||||
9 packets received by filter
|
||||
0 packets dropped by kernel
|
||||
@@ -0,0 +1,14 @@
|
||||
PG=10.42.1.29 K1=10.42.0.14
|
||||
=== 주입 전 기준 — 로그인 한 번의 시간 ===
|
||||
200 0.623459s
|
||||
200 0.067946s
|
||||
200 0.064262s
|
||||
=== a6 성공한 주입 — flannel.1 에 세 줄 ===
|
||||
15:03:55 주입
|
||||
=== 넣은 직후의 카운터 ===
|
||||
qdisc prio 1: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
|
||||
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
|
||||
backlog 0b 0p requeues 0
|
||||
qdisc netem 30: parent 1:3 limit 1000 delay 200ms
|
||||
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
|
||||
backlog 0b 0p requeues 0
|
||||
@@ -0,0 +1,15 @@
|
||||
=== 주입 뒤 — 같은 로그인 (keycloak-1 은 kc-lab-1 에 있고 DB 는 kc-lab-2 다) ===
|
||||
200 1.905504s
|
||||
200 1.903161s
|
||||
200 1.860396s
|
||||
200 1.867929s
|
||||
200 1.872740s
|
||||
=== 카운터가 올라갔나 ===
|
||||
qdisc netem 30: parent 1:3 limit 1000 delay 200ms
|
||||
Sent 8791 bytes 83 pkt (dropped 0, overlimits 0 requeues 0)
|
||||
backlog 0b 0p requeues 0
|
||||
=== 필터 목록 (문서가 미검증으로 둔 줄) ===
|
||||
filter parent 1: protocol ip pref 3 u32 chain 0
|
||||
filter parent 1: protocol ip pref 3 u32 chain 0 fh 800: ht divisor 1
|
||||
filter parent 1: protocol ip pref 3 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 *flowid 1:3 not_in_hw
|
||||
match 0a2a011d/ffffffff at 12
|
||||
@@ -0,0 +1,6 @@
|
||||
=== a6 되돌리기 ===
|
||||
qdisc noqueue 0: root refcnt 2
|
||||
=== 되돌린 뒤 같은 로그인 ===
|
||||
200 0.067775s
|
||||
200 0.043802s
|
||||
200 0.045763s
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
=== a7 7. 세션 테이블을 비운다 ===
|
||||
DELETE 11
|
||||
=== 8. args 를 volatile 로 (patch 형태) ===
|
||||
statefulset.apps/keycloak patched
|
||||
15:05:19 전환
|
||||
Waiting for partitioned roll out to finish: 0 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for partitioned roll out to finish: 1 out of 2 new pods have been updated...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
Waiting for 1 pods to be ready...
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
=== 주입 검증 — args 가 바뀌었나 ===
|
||||
["start","--features-disabled=persistent-user-sessions"]
|
||||
keycloak-0 1/1 Running 10.42.1.34 kc-lab-2
|
||||
keycloak-1 1/1 Running 10.42.0.15 kc-lab-1
|
||||
postgres-7b474b88c8-5zp6v 1/1 Running 10.42.1.29 kc-lab-2
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
=== a7 관찰 — A-0 의 시험 0 을 글자 그대로 다시 ===
|
||||
# [1] keycloak-0 에서 로그인
|
||||
sid=_szXQIOVaE8_v2-b-frn9npt
|
||||
# [2] keycloak-1 에서 refresh (교차 노드)
|
||||
200
|
||||
=== DB 세션 행은 몇 건인가 ===
|
||||
user_session_id
|
||||
-----------------
|
||||
(0 rows)
|
||||
|
||||
=== 노드별 캐시 엔트리 ===
|
||||
keycloak-0 clientSessions 0
|
||||
keycloak-0 sessions 0
|
||||
keycloak-1 clientSessions 0
|
||||
keycloak-1 sessions 0
|
||||
@@ -0,0 +1,14 @@
|
||||
=== 스크레이프 뒤 캐시 — 세션이 어디 사나 ===
|
||||
keycloak-0 clientSessions 1
|
||||
keycloak-0 sessions 1
|
||||
keycloak-1 clientSessions 0
|
||||
keycloak-1 sessions 0
|
||||
=== 7800 을 막는다 (A-1 의 NetworkPolicy 를 그대로) ===
|
||||
networkpolicy.networking.k8s.io/a1-block-jgroups-transport created
|
||||
15:06:59 적용
|
||||
pod "keycloak-0" deleted from keycloak-lab namespace
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
=== 멤버 수 ===
|
||||
"pod":"keycloak-1"} "1"]} "pod":"keycloak-0"} "1"]}]}}
|
||||
|
||||
[exited with code 0]
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
분단 + volatile 에서 K0=10.42.1.36 K1=10.42.0.15
|
||||
=== A-1 의 네 단계를 그대로 (volatile 판) ===
|
||||
# [1] keycloak-0 에서 로그인
|
||||
sid=9tpo41BVY32uJdYOyv8maA5j# [2] keycloak-1 에서 refresh
|
||||
400
|
||||
# [3] keycloak-1 에서 로그아웃
|
||||
400
|
||||
# [4] keycloak-0 에서 재갱신 시도
|
||||
{"error":"invalid_grant","error_description":"Invalid refresh token"}
|
||||
400
|
||||
=== DB 행 ===
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
=== a7 복구 ① NetworkPolicy 를 지운다 ===
|
||||
networkpolicy.networking.k8s.io "a1-block-jgroups-transport" deleted from keycloak-lab namespace
|
||||
=== ② args 를 원래대로 ===
|
||||
statefulset.apps/keycloak patched
|
||||
15:09:07 원복
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
["start"]
|
||||
@@ -0,0 +1,16 @@
|
||||
=== a7a 6. 문장 로깅을 켠다 ===
|
||||
(1 row)
|
||||
|
||||
log_statement
|
||||
---------------
|
||||
all
|
||||
(1 row)
|
||||
|
||||
=== 7. volatile 로 바꾼다 ===
|
||||
statefulset.apps/keycloak patched
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
["start","--features-disabled=persistent-user-sessions"]
|
||||
=== 4. 탐침 파드를 StatefulSet 밖에 ===
|
||||
pod/a7a-probe created
|
||||
pod/a7a-probe condition met
|
||||
K0=10.42.1.39 K1=10.42.0.17
|
||||
@@ -0,0 +1,10 @@
|
||||
=== a7a 재현 A — 완전 냉시동 ===
|
||||
statefulset.apps/keycloak restarted
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
deployment.apps/postgres scaled
|
||||
pod/postgres-7b474b88c8-5zp6v condition met
|
||||
pod/a7a-probe condition met
|
||||
=== ③ 로그인을 본문과 함께 (기대: 400 unauthorized_client) ===
|
||||
{"error":"unauthorized_client","error_description":"Unexpected error when authenticating client"}
|
||||
400
|
||||
=== ④ 실패한 SQL 을 Keycloak 로그에서 ===
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
=== ④ 문서가 적은 형태 그대로 ===
|
||||
(위가 비면 아래를 본다)
|
||||
=== 더 넓게 ===
|
||||
2026-09-17 06:11:31,802 WARN [org.keycloak.jgroups.protocol.KEYCLOAK_JDBC_PING2] (blocking-thread--p3-t2) Failed to fetch the cluster members from the database.: org.postgresql.util.PSQLException: FATAL: terminating connection due to administrator command
|
||||
2026-09-17 06:11:59,291 ERROR [org.keycloak.services] (executor-thread-3) KC-SERVICES0015: Unexpected error when authenticating client: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection [Connection to postgres:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.] [n/a]
|
||||
=== 실제로 찍힌 오류 줄 ===
|
||||
2026-09-17 06:11:49,114 ERROR [org.keycloak.jgroups.protocol.KEYCLOAK_JDBC_PING2] (Timer runner-2,keycloak-0-44929(v=16.0.12)) keycloak-0-44929(v=16.0.12): failed reading from the DB: org.postgresql.util.PSQLException: Connection to postgres:5432 refused. Chec
|
||||
2026-09-17 06:11:55,190 ERROR [org.keycloak.jgroups.protocol.KEYCLOAK_JDBC_PING2] (Timer runner-2,keycloak-0-44929(v=16.0.12)) keycloak-0-44929(v=16.0.12): failed writing to DB: org.postgresql.util.PSQLException: Connection to postgres:5432 refused. Check that
|
||||
2026-09-17 06:11:59,291 ERROR [org.keycloak.services] (executor-thread-3) KC-SERVICES0015: Unexpected error when authenticating client: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection [Connection to postgres:5432 refused. Che
|
||||
2026-09-17 06:11:59,295 WARN [org.keycloak.events] (executor-thread-3) type="LOGIN_ERROR", realmId="f9bed085-ff57-4ab0-92ab-af83adeb320e", realmName="master", clientId="admin-cli", userId="null", ipAddress="10.42.1.42", error="invalid_client_credentials", gra
|
||||
@@ -0,0 +1,17 @@
|
||||
=== 넓힌 grep 이 둘 다 잡나 ===
|
||||
KC-SERVICES0015: Unexpected error when authenticating client: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection [Connection to postgres:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.]
|
||||
|
||||
=== a7a 재현 B — 로그인 한 번으로 캐시를 덥힌 뒤 DB 를 내린다 ===
|
||||
deployment.apps/postgres scaled
|
||||
deployment "postgres" successfully rolled out
|
||||
statefulset.apps/keycloak restarted
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
pod/a7a-probe condition met
|
||||
--- 로그인 한 번 (DB 살아 있을 때) ---
|
||||
rt=612자
|
||||
--- DB 를 내린다 ---
|
||||
deployment.apps/postgres scaled
|
||||
pod/postgres-7b474b88c8-dg4vb condition met
|
||||
--- refresh (기대: 500) ---
|
||||
{"error":"unknown_error","error_description":"For more on this error consult the server log."}
|
||||
500
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
=== a7a 재현 C — DB 를 살리고 같은 refresh 를 다시 ===
|
||||
deployment.apps/postgres scaled
|
||||
deployment "postgres" successfully rolled out
|
||||
200
|
||||
=== a7a 되돌리기 ===
|
||||
(1 row)
|
||||
|
||||
log_statement
|
||||
---------------
|
||||
none
|
||||
(1 row)
|
||||
|
||||
statefulset.apps/keycloak patched
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
pod "a7a-probe" deleted from keycloak-lab namespace
|
||||
["start"]
|
||||
keycloak-0 1/1 Running
|
||||
keycloak-1 1/1 Running
|
||||
postgres-7b474b88c8-48lrr 1/1 Running
|
||||
|
||||
[exited with code 0]
|
||||
@@ -0,0 +1,21 @@
|
||||
=== a8 1~3 기준선 ===
|
||||
keycloak-0 1/1 Running 103s 10.42.1.47
|
||||
keycloak-1 1/1 Running 2m17s 10.42.0.20
|
||||
postgres-7b474b88c8-48lrr 1/1 Running 2m57s 10.42.1.46
|
||||
["start"] replicas=2
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
=== 4~6 탐침과 토큰 ===
|
||||
pod/a8-probe condition met
|
||||
rt=613자 sid=z_FpRg03WlwmkgqrpKZgzfNP
|
||||
# 대조군 — 재시작 전 refresh
|
||||
200
|
||||
=== 7. 그 세션이 DB 에 있나 ===
|
||||
user_session_id | created_on | last_session_refresh
|
||||
--------------------------+------------+----------------------
|
||||
z_FpRg03WlwmkgqrpKZgzfNP | 1789625835 | 1789625835
|
||||
(1 row)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
=== 8. 캐시와 클러스터 크기 ===
|
||||
keycloak-0 clientSessions 0
|
||||
keycloak-0 sessions 0
|
||||
keycloak-1 clientSessions 0
|
||||
keycloak-1 sessions 0
|
||||
=== 9. 롤링 재시작 ===
|
||||
15:18:57 재시작
|
||||
statefulset.apps/keycloak restarted
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
=== 10. 파드가 진짜 바뀌었나 (AGE) ===
|
||||
keycloak-0 1/1 Running 31s 10.42.1.49
|
||||
keycloak-1 1/1 Running 63s 10.42.0.21
|
||||
=== 12. 본 시험 — 재시작 전 토큰이 아직 통하는가 ===
|
||||
|
||||
000
|
||||
command terminated with exit code 3
|
||||
=== 13. DB 행의 두 시각 ===
|
||||
user_session_id | created_on | last_session_refresh
|
||||
--------------------------+------------+----------------------
|
||||
z_FpRg03WlwmkgqrpKZgzfNP | 1789625835 | 1789625835
|
||||
(1 row)
|
||||
|
||||
=== 14. 캐시와 클러스터 ===
|
||||
keycloak-0 clientSessions 0
|
||||
keycloak-0 sessions 0
|
||||
keycloak-1 clientSessions 0
|
||||
keycloak-1 sessions 0
|
||||
"pod":"keycloak-1"} "2"]} "pod":"keycloak-0"} "2"]}]}}
|
||||
@@ -0,0 +1,10 @@
|
||||
새 K0=10.42.1.49 (탐침 안의 낡은 값=10.42.1.47)
|
||||
=== 12. 본 시험 — 새 IP 를 명령줄로 넘긴다 ===
|
||||
{"access_token":"<REDACTED 758자>","expires_in":60,"refresh_expires_in":1800,"refresh_token":"<REDACTED 612자>","token_type":"Bearer","not-before-policy":0,"session_state":"z_FpRg03WlwmkgqrpKZgzfNP","scope":"profile email"}
|
||||
200
|
||||
=== 13. DB 행의 두 시각 (갱신됐나) ===
|
||||
user_session_id | created_on | last_session_refresh
|
||||
--------------------------+------------+----------------------
|
||||
z_FpRg03WlwmkgqrpKZgzfNP | 1789625835 | 1789625952
|
||||
(1 row)
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
=== 이미지 두 개를 두 노드에 밀어 넣는다 (문서의 형태 그대로) ===
|
||||
--- keycloak-pattern-bff:lab → kc-lab-1 ---
|
||||
application/vnd.oci.image.index.v1+json sha256:9fb29178e7f8556a8d3b38cf6e23b55cfbc27396530451bb86dcea99206b7bbb
|
||||
Importing elapsed: 7.8 s total: 0.0 B (0.0 B/s)
|
||||
--- keycloak-pattern-bff:lab → kc-lab-2 ---
|
||||
application/vnd.oci.image.index.v1+json sha256:9fb29178e7f8556a8d3b38cf6e23b55cfbc27396530451bb86dcea99206b7bbb
|
||||
Importing elapsed: 6.9 s total: 0.0 B (0.0 B/s)
|
||||
--- keycloak-pattern-api:lab → kc-lab-1 ---
|
||||
application/vnd.oci.image.index.v1+json sha256:ff6ce2988e2fd19c44f38591c58e7cecc79c443368a502e328f356bee23d6ab3
|
||||
Importing elapsed: 5.6 s total: 0.0 B (0.0 B/s)
|
||||
--- keycloak-pattern-api:lab → kc-lab-2 ---
|
||||
application/vnd.oci.image.index.v1+json sha256:ff6ce2988e2fd19c44f38591c58e7cecc79c443368a502e328f356bee23d6ab3
|
||||
Importing elapsed: 5.8 s total: 0.0 B (0.0 B/s)
|
||||
=== 두 노드의 이미지 목록 ===
|
||||
--- kc-lab-1 ---
|
||||
docker.io/library/keycloak-pattern-api:lab
|
||||
docker.io/library/keycloak-pattern-bff:lab
|
||||
--- kc-lab-2 ---
|
||||
docker.io/library/keycloak-pattern-api:lab
|
||||
docker.io/library/keycloak-pattern-bff:lab
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
=== b0 3-① kcadm 로그인 ===
|
||||
Logging into http://localhost:8080 as user admin of realm master
|
||||
(exit=0)
|
||||
=== ③ realm 과 클라이언트 ===
|
||||
Created new realm with id 'keycloak-patterns'
|
||||
Created new client with id '7ae3362a-2bed-4902-b6af-d7307ea4ad0b'
|
||||
=== ④ realm 세 칸 ===
|
||||
{
|
||||
"realm" : "keycloak-patterns",
|
||||
"accessTokenLifespan" : 60,
|
||||
"enabled" : true
|
||||
}
|
||||
=== 4. 사용자 ===
|
||||
Created new user with id '07d3be2a-9f22-4779-a211-e530c8b7ff3b'
|
||||
[ {
|
||||
"username" : "labuser",
|
||||
"enabled" : true
|
||||
} ]
|
||||
@@ -0,0 +1,29 @@
|
||||
=== bff-redis.yaml 이 무엇을 만드나 ===
|
||||
kind: Secret
|
||||
name: bff-secrets
|
||||
kind: PersistentVolumeClaim
|
||||
name: redis-data
|
||||
kind: Deployment
|
||||
name: redis
|
||||
kind: Service
|
||||
name: redis
|
||||
kind: Deployment
|
||||
name: bff
|
||||
kind: Service
|
||||
name: bff
|
||||
kind: Ingress
|
||||
name: bff
|
||||
=== 적용 ===
|
||||
secret/bff-secrets created
|
||||
persistentvolumeclaim/redis-data created
|
||||
deployment.apps/redis created
|
||||
service/redis created
|
||||
deployment.apps/bff created
|
||||
service/bff created
|
||||
ingress.networking.k8s.io/bff created
|
||||
bff-5d97897676-nmlqs 0/1 Running kc-lab-1
|
||||
bff-5d97897676-zvfhp 0/1 Running kc-lab-2
|
||||
keycloak-0 1/1 Running kc-lab-2
|
||||
keycloak-1 1/1 Running kc-lab-1
|
||||
postgres-7b474b88c8-48lrr 1/1 Running kc-lab-2
|
||||
redis-f94bc6dbf-pjllr 0/1 ContainerCreating kc-lab-2
|
||||
@@ -0,0 +1,26 @@
|
||||
=== 파드 상태 ===
|
||||
bff-5d97897676-nmlqs 1/1 Running kc-lab-1
|
||||
bff-5d97897676-zvfhp 1/1 Running kc-lab-2
|
||||
keycloak-0 1/1 Running kc-lab-2
|
||||
keycloak-1 1/1 Running kc-lab-1
|
||||
postgres-7b474b88c8-48lrr 1/1 Running kc-lab-2
|
||||
redis-f94bc6dbf-pjllr 1/1 Running kc-lab-2
|
||||
=== bff 가 안 뜨면 왜인지 ===
|
||||
2026-09-17T06:24:23.717Z INFO 1 --- [keycloak-bff] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2026-09-17T06:24:23.718Z INFO 1 --- [keycloak-bff] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2221 ms
|
||||
2026-09-17T06:24:23.943Z INFO 1 --- [keycloak-bff] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
|
||||
2026-09-17T06:24:24.223Z INFO 1 --- [keycloak-bff] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@be6d228
|
||||
2026-09-17T06:24:24.225Z INFO 1 --- [keycloak-bff] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
|
||||
2026-09-17T06:24:24.808Z INFO 1 --- [keycloak-bff] [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html]
|
||||
2026-09-17T06:24:25.272Z INFO 1 --- [keycloak-bff] [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 5 endpoints beneath base path '/actuator'
|
||||
2026-09-17T06:24:25.909Z INFO 1 --- [keycloak-bff] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8083 (http) with context path '/'
|
||||
2026-09-17T06:24:25.926Z INFO 1 --- [keycloak-bff] [ main] c.e.keycloakpattern.bff.BffApplication : Started BffApplication in 5.298 seconds (process running for 5.885)
|
||||
2026-09-17T06:24:41.136Z INFO 1 --- [keycloak-bff] [nio-8083-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
|
||||
2026-09-17T06:24:41.137Z INFO 1 --- [keycloak-bff] [nio-8083-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
||||
2026-09-17T06:24:41.139Z INFO 1 --- [keycloak-bff] [nio-8083-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
|
||||
=== 이미지 경로가 맞았나 ===
|
||||
keycloak-pattern-bff:lab Never
|
||||
Events:
|
||||
Type Reason Age From Message
|
||||
---- ------ ---- ---- -------
|
||||
Normal Scheduled 2m39s default-scheduler Successfully assigned keycloak-lab/bff-5d97897676-nmlqs to kc-lab-1
|
||||
@@ -0,0 +1,23 @@
|
||||
=== BFF 파드: bff-5d97897676-nmlqs ===
|
||||
=== /actuator/beans 를 파드 안에서 받는다 ===
|
||||
155395 /tmp/beans.json
|
||||
=== ① 빈의 개수 (문서가 미검증으로 둔 줄) ===
|
||||
437
|
||||
=== ② 저장소 계열 빈 (문서가 미검증으로 둔 줄) ===
|
||||
"org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientConfigurations$OAuth2AuthorizedClientServiceConfiguration": -> org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientConfigurations$OAuth2AuthorizedClientServiceConfiguration"
|
||||
"authorizedClientManagerRegistrar": -> org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2AuthorizedClientManagerRegistrar"
|
||||
"org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2AuthorizedClientManagerConfiguration": -> org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration$OAuth2AuthorizedClientManagerConfiguration"
|
||||
"authorizedClientManager": -> org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager"
|
||||
"authorizedClientService": -> org.springframework.security.oauth2.client.JdbcOAuth2AuthorizedClientService"
|
||||
"authorizedClientRepository": -> org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository"
|
||||
=== 세션 저장소 쪽도 ===
|
||||
"reactiveRedisTemplate": -> org.springframework.data.redis.core.ReactiveRedisTemplate"
|
||||
"redisConnectionDetails": -> org.springframework.boot.autoconfigure.data.redis.PropertiesRedisConnectionDetails"
|
||||
"org.springframework.boot.autoconfigure.session.SessionAutoConfiguration$ServletSessionConfiguration$ServletSessionRepositoryConfiguration": -> org.springframework.boot.autoconfigure.session.SessionAutoConfiguration$ServletSessionConfiguration$ServletSessionRepositoryConfiguration"
|
||||
"redisCustomConversions": -> org.springframework.data.redis.core.convert.RedisCustomConversions"
|
||||
"org.springframework.boot.autoconfigure.session.RedisSessionConfiguration": -> org.springframework.boot.autoconfigure.session.RedisSessionConfiguration"
|
||||
=== 이 BFF 의 저장소 설정 ===
|
||||
SPRING_SESSION_STORE_TYPE=redis
|
||||
BFF_DB_URL=jdbc:postgresql://postgres.keycloak-lab.svc:5432/keycloak
|
||||
BFF_DB_USER=keycloak
|
||||
BFF_DB_PASSWORD=
|
||||
@@ -0,0 +1,15 @@
|
||||
=== b2 — JDBC 토큰 저장소의 표가 있나 ===
|
||||
Table "public.oauth2_authorized_client"
|
||||
Column | Type | Collation | Nullable | Default
|
||||
-------------------------+-----------------------------+-----------+----------+-------------------------
|
||||
client_registration_id | character varying(100) | | not null |
|
||||
principal_name | character varying(200) | | not null |
|
||||
access_token_type | character varying(100) | | not null |
|
||||
access_token_value | bytea | | not null |
|
||||
access_token_issued_at | timestamp without time zone | | not null |
|
||||
access_token_expires_at | timestamp without time zone | | not null |
|
||||
access_token_scopes | character varying(1000) | | | NULL::character varying
|
||||
refresh_token_value | bytea | | |
|
||||
refresh_token_issued_at | timestamp without time zone | | |
|
||||
=== 행 수 ===
|
||||
0
|
||||
@@ -0,0 +1,12 @@
|
||||
=== b3 2. kcadm 세션 ===
|
||||
Logging into http://localhost:8080 as user admin of realm master
|
||||
=== 3. realm 의 세 값 ===
|
||||
{
|
||||
"revokeRefreshToken" : false,
|
||||
"refreshTokenMaxReuse" : 0,
|
||||
"accessTokenLifespan" : 60
|
||||
}
|
||||
=== 4-① 탐침 파드 ===
|
||||
pod/b3-probe condition met
|
||||
=== ② 길이만 ===
|
||||
KC=http://keycloak.keycloak-lab.svc:8080/realms/keycloak-patterns/protocol/openid-connect/token CS길이=14
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
=== 문서가 없다고 한 그 대조 — 두 값이 같은가 (길이와 해시만) ===
|
||||
매니페스트 쪽 길이=14 Keycloak 쪽 길이=14
|
||||
두 값이 같다
|
||||
=== b3 5. 토큰을 하나 받는다 ===
|
||||
rt=0자
|
||||
{"error":"unauthorized_client","error_description":"Client not allowed for direct access g
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
=== B-0 이 만든 클라이언트의 그랜트 설정 ===
|
||||
{
|
||||
"clientId" : "bff-confidential",
|
||||
"standardFlowEnabled" : true,
|
||||
"directAccessGrantsEnabled" : false,
|
||||
"publicClient" : false
|
||||
}
|
||||
=== 켜 본다 ===
|
||||
{
|
||||
"clientId" : "bff-confidential",
|
||||
"directAccessGrantsEnabled" : true
|
||||
}
|
||||
=== 켠 뒤 같은 토큰 요청 ===
|
||||
rt=0자
|
||||
{"error":"invalid_grant","error_description":"Account is not
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
=== 전체 오류 문구 ===
|
||||
{"error":"invalid_grant","error_description":"Account is not fully set up"}
|
||||
=== B-0 이 만든 사용자의 상태 ===
|
||||
{
|
||||
"username" : "labuser",
|
||||
"emailVerified" : false,
|
||||
"enabled" : true,
|
||||
"requiredActions" : [ ]
|
||||
}
|
||||
=== 처방: 계정을 완전하게 만든다 ===
|
||||
{
|
||||
"username" : "labuser",
|
||||
"emailVerified" : true,
|
||||
"enabled" : true,
|
||||
"requiredActions" : [ ]
|
||||
}
|
||||
=== 다시 토큰 요청 ===
|
||||
rt=735자
|
||||
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2l
|
||||
@@ -0,0 +1,16 @@
|
||||
=== b3 주입 — 회전을 켠다 ===
|
||||
15:29:22 회전 켬
|
||||
{
|
||||
"revokeRefreshToken" : true,
|
||||
"refreshTokenMaxReuse" : 0
|
||||
}=== 관찰 — 같은 토큰으로 동시에 다섯 번 ===
|
||||
|
||||
refresh=810자 SID=7yVb2FfztKznk461jR10VpIT
|
||||
요청 1: HTTP 400 {"error":"invalid_grant","error_description":"Session doesn't have required client"}
|
||||
요청 2: HTTP 400 {"error":"invalid_grant","error_description":"Session doesn't have required client"}
|
||||
요청 3: HTTP 400 {"error":"invalid_grant","error_description":"Maximum allowed refresh token reuse exceeded
|
||||
요청 4: HTTP 200 {"access_token":"<REDACTED 73자 조각>
|
||||
요청 5: HTTP 400 {"error":"invalid_grant","error_description":"Session doesn't have required client"}
|
||||
이긴 요청의 새 refresh 길이: 810
|
||||
그 토큰을 다시 쓰면: 400
|
||||
error_description=Session doesn't have required client
|
||||
@@ -0,0 +1,6 @@
|
||||
=== b3 되돌리기 ===
|
||||
{
|
||||
"revokeRefreshToken" : false,
|
||||
"refreshTokenMaxReuse" : 0
|
||||
}
|
||||
pod "b3-probe" deleted from keycloak-lab namespace
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
=== b4 1. app1 이 경로에 따라 어디로 가는가 ===
|
||||
NS NAME HOST PATH SVC
|
||||
header-lab echo app1.hyeonworks.com /api echo
|
||||
keycloak-lab bff app1.hyeonworks.com / bff
|
||||
keycloak-lab keycloak auth.hyeonworks.com / keycloak
|
||||
observability grafana app2.hyeonworks.com / grafana
|
||||
=== 2. echo 응답을 통째로 (TLS 대신 Host 헤더) ===
|
||||
{
|
||||
"headers" : {
|
||||
"host" : [ "app1.hyeonworks.com" ],
|
||||
"user-agent" : [ "curl/8.21.0" ],
|
||||
"accept" : [ "*/*" ],
|
||||
"x-forwarded-host" : [ "app1.hyeonworks.com" ],
|
||||
"x-forwarded-port" : [ "80" ],
|
||||
"x-forwarded-proto" : [ "http" ],
|
||||
"x-forwarded-server" : [ "traefik-59b7647586-t8fc7" ],
|
||||
"x-real-ip" : [ "10.42.0.1" ],
|
||||
"accept-encoding" : [ "gzip" ]
|
||||
},
|
||||
"remoteAddr" : "10.42.0.1",
|
||||
"localAddr" : "10.42.1.58",
|
||||
"scheme" : "http",
|
||||
"secure" : false,
|
||||
"serverName" : "app1.hyeonworks.com",
|
||||
"serverPort" : 80,
|
||||
"requestUrl" : "http://app1.hyeonworks.com/api/echo"
|
||||
}
|
||||
=== 3. 대조군 — 아무것도 안 붙였을 때 ===
|
||||
(위가 비면 대조군에는 그 헤더가 없다)
|
||||
=== 주입 1. 동명 헤더 두 개 ===
|
||||
=== 주입 2. 값 안의 쉼표 ===
|
||||
=== 주입 4. 신원 자체를 위조 ===
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
=== 주입 1. 동명 헤더 두 개 (문서의 grep 형태) ===
|
||||
"x-auth-request-roles" : [ "admin", "editor" ]
|
||||
=== 주입 2. 값 안의 쉼표 ===
|
||||
"x-auth-request-roles" : [ "admin,editor,viewer" ]
|
||||
"x-auth-request-roles" : [ "role-with,comma" ]
|
||||
=== 주입 4. 신원 위조 ===
|
||||
"x-auth-request-email" : [ "attacker@evil.invalid" ]
|
||||
"x-auth-request-user" : [ "attacker" ]
|
||||
=== 문서가 적은 x-forwarded-proto grep 형태 ===
|
||||
(위가 비면 공백 때문이다)
|
||||
"x-forwarded-proto" : [ "http" ]
|
||||
@@ -0,0 +1,19 @@
|
||||
=== b5 1. 파드 배치 ===
|
||||
bff-5d97897676-nmlqs 1/1 Running kc-lab-1
|
||||
bff-5d97897676-zvfhp 1/1 Running kc-lab-2
|
||||
keycloak-0 1/1 Running kc-lab-2
|
||||
keycloak-1 1/1 Running kc-lab-1
|
||||
postgres-7b474b88c8-48lrr 1/1 Running kc-lab-2
|
||||
redis-f94bc6dbf-pjllr 1/1 Running kc-lab-2
|
||||
=== 2. Redis 안과 영속화 설정 ===
|
||||
PONG
|
||||
(위가 비면 키가 없다)
|
||||
save
|
||||
3600 1 300 100 60 10000
|
||||
appendonly
|
||||
yes
|
||||
=== 3. /data 가 볼륨인가 ===
|
||||
data=redis-data
|
||||
kube-api-access-nk4c6=
|
||||
data -> /data
|
||||
kube-api-access-nk4c6 -> /var/run/secrets/kubernetes.io/serviceaccount
|
||||
@@ -0,0 +1,23 @@
|
||||
=== b5 5-① health 그룹 셋 (정상 상태, TLS 대신 Host 헤더) ===
|
||||
/actuator/health -> {"status":"UP","groups":["liveness","readiness"],"components":{"db":{"status":"UP","details":{"database":"PostgreSQL","validationQuery":"isValid()"}},"diskSpace":{"status":"UP","details":{"total":20922114048,"free":15890649088,"threshold":10485760,"path":"/app/.","exists":true}},"livenessState":{"status":"UP"},"ping":{"status":"UP"},"readinessState":{"status":"UP"},"redis":{"status":"UP","details":{"version":"7.4.11"}},"ssl":{"status":"UP","details":{"validChains":[],"invalidChains":[]}}}}
|
||||
/actuator/health/readiness -> {"status":"UP"}
|
||||
/actuator/health/liveness -> {"status":"UP"}
|
||||
=== ② kubelet 이 보는 경로 ===
|
||||
/actuator/health/readiness
|
||||
=== 주입 1. Redis 를 0대로 ===
|
||||
15:52:37 정지
|
||||
deployment.apps/redis scaled
|
||||
pod/redis-f94bc6dbf-pjllr condition met
|
||||
=== 정지 뒤 health 그룹 셋 ===
|
||||
/actuator/health -> {"status":"DOWN","groups":["liveness","readiness"],"components":{"db":{"status":"UP","details":{"database":"PostgreSQL","validationQuery":"isValid()"}},"diskSpace":{"status":"UP","details":{"total":20922114048,"free":13710831616,"threshold":10485760,"path":"/app/.","exists":true}},"livenessState":{"status":"UP"},"ping":{"status":"UP"},"readinessState":{"status":"UP"},"redis":{"status":"DOWN","details":{"error":"org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis"}},"ssl":{"status":"UP","details":{"validChains":[],"invalidChains":[]}}}}
|
||||
/actuator/health/readiness -> {"status":"UP"}
|
||||
/actuator/health/liveness -> {"status":"UP"}
|
||||
=== 파드 상태 ===
|
||||
bff-5d97897676-nmlqs 1/1 Running kc-lab-1
|
||||
bff-5d97897676-zvfhp 1/1 Running kc-lab-2
|
||||
keycloak-0 1/1 Running kc-lab-2
|
||||
keycloak-1 1/1 Running kc-lab-1
|
||||
postgres-7b474b88c8-48lrr 1/1 Running kc-lab-2
|
||||
=== Service 엔드포인트 ===
|
||||
ADDR READY
|
||||
[10.42.1.51],[10.42.0.22] true,true
|
||||
@@ -0,0 +1,10 @@
|
||||
=== b5 되돌리기 ===
|
||||
deployment.apps/redis scaled
|
||||
deployment "redis" successfully rolled out
|
||||
/actuator/health -> "status":"UP"
|
||||
bff-5d97897676-nmlqs 1/1 Running
|
||||
bff-5d97897676-zvfhp 1/1 Running
|
||||
keycloak-0 1/1 Running
|
||||
keycloak-1 1/1 Running
|
||||
postgres-7b474b88c8-48lrr 1/1 Running
|
||||
redis-f94bc6dbf-s674z 1/1 Running
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
=== echo.yaml 이 무엇을 만드나 ===
|
||||
kind: Namespace
|
||||
name: header-lab
|
||||
kind: Deployment
|
||||
name: echo
|
||||
namespace: header-lab
|
||||
kind: Service
|
||||
name: echo
|
||||
namespace: header-lab
|
||||
kind: Ingress
|
||||
name: echo
|
||||
namespace: header-lab
|
||||
=== 적용 ===
|
||||
namespace/header-lab created
|
||||
deployment.apps/echo created
|
||||
service/echo created
|
||||
ingress.networking.k8s.io/echo created
|
||||
echo-cd47dccc6-nq62j 1/1 Running kc-lab-2
|
||||
echo-cd47dccc6-q46lk 1/1 Running kc-lab-1
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
=== b6 2. 공급자 목록 ===
|
||||
=== 문서가 미검증으로 둔 「조용히 빈 결과」 형태 ===
|
||||
No server specified. Use --server, or 'kcadm.sh config credentials'.
|
||||
command terminated with exit code 1
|
||||
(위가 비면 문서 말이 맞다. exit=0)
|
||||
=== 3. JWKS 를 TLS 없이 (Host 헤더로) ===
|
||||
{"keys":[{"kid":"HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg","kty":"RSA","alg":"RS256","use":"sig","x5c":["MIICsTCCAZkCBgGgrgllnjANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFrZXljbG9hay1wYXR0ZXJuczAeFw0yNjA5MTcwNjIyMjZaFw0zNjA5MTcwNjI0MDZaMBwxGjAYBgNVBAMMEWtleWNsb2FrLXBhdHRlcm5zMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
=== 4. RS256 만 센다 ===
|
||||
1
|
||||
=== kid 목록 ===
|
||||
{"keys":[{"kid":"HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg"
|
||||
{"kid":"5voCsAVhALEjGliTG9Z2bx6WSkHeAUFUXiYOYic-niI"
|
||||
@@ -0,0 +1,12 @@
|
||||
=== kcadm 세션이 왜 사라졌나 ===
|
||||
ls: cannot access '/opt/keycloak/.keycloak/kcadm.config': No such file or directory
|
||||
=== 다시 로그인 ===
|
||||
Logging into http://localhost:8080 as user admin of realm master
|
||||
=== b6 2. 공급자 목록 ===
|
||||
,{"id":"807e653f-deaf-41cd-bbaa-5b19eaf74a2a","name":"hmac-generated-hs512","providerId":"hmac-generated"
|
||||
,{"id":"27216d59-950c-4c8c-b0a8-e1d8108e0c0f","name":"aes-generated","providerId":"aes-generated"
|
||||
,{"id":"a09ec151-6c8c-4e55-84c0-f02781221b83","name":"rsa-generated","providerId":"rsa-generated"
|
||||
=== 문서가 미검증으로 둔 「조용히 빈 결과」 형태 ===
|
||||
[ {
|
||||
"id" : "d47b58ee-7c34-4be0-a3f3-30f49b4577c1",
|
||||
"name" : "rsa-enc-generated",
|
||||
@@ -0,0 +1,3 @@
|
||||
at=1397자
|
||||
kid=echo 에 그 토큰으로: 401
|
||||
토큰 없이: 200
|
||||
@@ -0,0 +1,9 @@
|
||||
=== echo 가 어느 발행자를 보나 ===
|
||||
{"name":"SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI"
|
||||
{"name":"SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI"
|
||||
|
||||
=== echo 로그에서 401 의 까닭 ===
|
||||
=== kid 를 따로 뽑아 본다 ===
|
||||
헤더 길이=111
|
||||
{"alg":"RS256","typ" : "JWT","kid" : "HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGgbase64: truncated input
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
=== echo 의 두 URI ===
|
||||
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=https://auth.hyeonworks.com/realms/keycloak-patterns
|
||||
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/certs
|
||||
=== echo 가 그 주소에 닿나 ===
|
||||
issuer=000
|
||||
command terminated with exit code 7
|
||||
=== JWT 헤더는 공백이 들어간 형태다 ===
|
||||
헤더: {"alg":"RS256","typ" : "JWT","kid" : "HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg"}
|
||||
문서 형태의 sed: []
|
||||
공백을 허용한 sed: [HKy0uQhg-vlQackK6-oj3hW6vKbDj-95Wlvdgl37cGg]
|
||||
BIN
Binary file not shown.
+14
@@ -0,0 +1,14 @@
|
||||
=== oauth2-proxy 파드 상태 ===
|
||||
oauth2-proxy-6c56c4c94f-2xthz 0/1 CrashLoopBackOff 4
|
||||
oauth2-proxy-6c56c4c94f-gkx8g 0/1 CrashLoopBackOff 5
|
||||
=== 그 Secret 이 있나 ===
|
||||
NAME TYPE DATA AGE
|
||||
oauth2-proxy-secrets Opaque 3 3m11s
|
||||
=== 왜 안 뜨나 ===
|
||||
[2026/09/17 06:45:22] [provider.go:55] Performing OIDC Discovery...
|
||||
[2026/09/17 06:45:22] [main.go:59] ERROR: Failed to initialise OAuth2 Proxy: error initialising provider: could not create provider data: error building OIDC ProviderVerifier: could not get verifier builder: error while discovery OIDC configuration: failed to discover OIDC configuration: error performing request: Get "https://auth.hyeonworks.com/realms/keycloak-patterns/.well-known/openid-configuration": dial tcp 100.83.212.4:443: connect: connection refused
|
||||
Events:
|
||||
Type Reason Age From Message
|
||||
---- ------ ---- ---- -------
|
||||
Normal Scheduled 4m44s default-scheduler Successfully assigned keycloak-lab/oauth2-proxy-6c56c4c94f-2xthz to kc-lab-2
|
||||
Normal Pulling 4m44s kubelet spec.containers{oauth2-proxy}: Pulling image "quay.io/oauth2-proxy/oauth2-proxy:v7.7.1"
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
=== c1 1. 앱 둘과 Ingress ===
|
||||
bff-5d97897676-nmlqs 1/1 Running
|
||||
bff-5d97897676-zvfhp 1/1 Running
|
||||
keycloak-0 1/1 Running
|
||||
keycloak-1 1/1 Running
|
||||
postgres-7b474b88c8-48lrr 1/1 Running
|
||||
redis-f94bc6dbf-s674z 1/1 Running
|
||||
header-lab echo app1.hyeonworks.com
|
||||
keycloak-lab bff app1.hyeonworks.com
|
||||
keycloak-lab keycloak auth.hyeonworks.com
|
||||
keycloak-lab oauth2-proxy app2.hyeonworks.com
|
||||
observability grafana app2.hyeonworks.com
|
||||
=== 2. kcadm 로그인 ===
|
||||
Logging into http://localhost:8080 as user admin of realm master
|
||||
=== 3-① realm 전체 로그아웃 ===
|
||||
=== 3-② 남은 세션 (문서가 미검증으로 둔 줄) ===
|
||||
6
|
||||
=== 4-① 자식 테이블부터 지운다 ===
|
||||
DELETE 1633
|
||||
DELETE 6
|
||||
=== 4-② 앱 세션도 비운다 ===
|
||||
OK
|
||||
=== 4-③ 롤아웃 ===
|
||||
statefulset.apps/keycloak restarted
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
=== 4-④ 두 저장소를 다시 센다 ===
|
||||
0
|
||||
(위가 비면 Redis 도 비었다)
|
||||
=== 문서가 적은 대로 kcadm 세션이 사라졌나 ===
|
||||
No server specified. Use --server, or 'kcadm.sh config credentials'.
|
||||
command terminated with exit code 1
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
=== c2 ① 응답을 통째로 (TLS 대신 Host 헤더) ===
|
||||
HTTP/1.1 302 Found
|
||||
Server: nginx/1.22.1
|
||||
Date: Thu, 17 Sep 2026 06:45:53 GMT
|
||||
Content-Length: 0
|
||||
Connection: keep-alive
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Expires: 0
|
||||
Location: http://app1.hyeonworks.com/oauth2/authorization/keycloak
|
||||
Pragma: no-cache
|
||||
Set-Cookie: XSRF-TOKEN=b750fc30-e57f-4895-a465-98cb1a103ec7; Path=/
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: DENY
|
||||
=== ② 후보 셋의 상태 코드 ===
|
||||
/logout/connect/back-channel/keycloak 302
|
||||
/backchannel-logout 302
|
||||
/oauth2/sign_out 302
|
||||
@@ -0,0 +1,12 @@
|
||||
=== d1 1~2 기준선 ===
|
||||
postgres-7b474b88c8-48lrr 1/1 Running kc-lab-2
|
||||
101
|
||||
6
|
||||
=== 5. 덤프 ===
|
||||
15:30:50 백업 시작
|
||||
15:30:50 백업 완료
|
||||
=== 6-① 크기와 줄 수 ===
|
||||
-rw-r--r-- 1 donghyeon donghyeon 976873 Sep 17 15:30 /tmp/keycloak-backup.sql
|
||||
8569 /tmp/keycloak-backup.sql
|
||||
=== 6-② 테이블 수 ===
|
||||
101
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
=== d1 주입 — 스키마를 통째로 지운다 ===
|
||||
15:31:02 파괴
|
||||
drop cascades to table cluster_event
|
||||
and 1 other object (see server log for list)
|
||||
DROP SCHEMA
|
||||
CREATE SCHEMA
|
||||
=== 주입 검증 ① 남은 테이블 (문서가 미검증으로 둔 형태) ===
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
=== ② 테이블에 직접 물어본다 ===
|
||||
LINE 1: select count(*) from realm
|
||||
^
|
||||
command terminated with exit code 1
|
||||
=== 밖에서는 (Host 헤더로) ===
|
||||
200
|
||||
=== 복구 ① ===
|
||||
15:31:02 복구 시작
|
||||
15:31:08 복구 완료
|
||||
=== ② 복구 로그의 오류 ===
|
||||
0
|
||||
ALTER TABLE
|
||||
ALTER TABLE
|
||||
ALTER TABLE
|
||||
=== 진짜 판정 — 주입 전과 견준다 ===
|
||||
101
|
||||
6
|
||||
@@ -0,0 +1,23 @@
|
||||
=== d2 2-① StatefulSet 의 태그 ===
|
||||
quay.io/keycloak/keycloak:26.7.0
|
||||
=== ② 파드가 실제로 돌리는 이미지 (고친 형태) ===
|
||||
bff-5d97897676-nmlqs keycloak-pattern-bff:lab true 0
|
||||
bff-5d97897676-zvfhp keycloak-pattern-bff:lab true 0
|
||||
keycloak-0 quay.io/keycloak/keycloak:26.7.0 true 0
|
||||
keycloak-1 quay.io/keycloak/keycloak:26.7.0 true 0
|
||||
=== 3. 마이그레이션 수 ===
|
||||
210
|
||||
=== 3-③ 마지막 다섯 줄 (문서가 미검증으로 둔 줄) ===
|
||||
id | author | orderexecuted | dateexecuted
|
||||
-------------------------------------------+----------+---------------+----------------------------
|
||||
26.7.0-cluster-event | keycloak | 210 | 2026-09-17 04:35:18.734357
|
||||
26.7.0-add-last-modified-timestamp-client | keycloak | 209 | 2026-09-17 04:35:18.703437
|
||||
26.7.0-add-timestamps-client | keycloak | 208 | 2026-09-17 04:35:18.698699
|
||||
26.7.0-login-failure-index | keycloak | 207 | 2026-09-17 04:35:18.69398
|
||||
26.7.0-login-failure-table | keycloak | 206 | 2026-09-17 04:35:18.658204
|
||||
(5 rows)
|
||||
|
||||
=== 4. 세션 ===
|
||||
6
|
||||
=== 6. 새 태그가 레지스트리에 있나 ===
|
||||
200
|
||||
@@ -0,0 +1,22 @@
|
||||
=== d2 주입 — 태그를 26.7.3 으로 ===
|
||||
15:32:15 정방향
|
||||
statefulset.apps/keycloak image updated
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
15:33:40 완료
|
||||
=== 판정 — 스키마가 움직였는가 ===
|
||||
210
|
||||
id | orderexecuted | dateexecuted
|
||||
-------------------------------------------+---------------+----------------------------
|
||||
26.7.0-cluster-event | 210 | 2026-09-17 04:35:18.734357
|
||||
26.7.0-add-last-modified-timestamp-client | 209 | 2026-09-17 04:35:18.703437
|
||||
26.7.0-add-timestamps-client | 208 | 2026-09-17 04:35:18.698699
|
||||
(3 rows)
|
||||
|
||||
=== 파드 이미지 ===
|
||||
NAME IMAGE READY RESTARTS
|
||||
keycloak-0 quay.io/keycloak/keycloak:26.7.3 true 0
|
||||
keycloak-1 quay.io/keycloak/keycloak:26.7.3 true 0
|
||||
=== 세션 ===
|
||||
6
|
||||
=== 밖에서 ===
|
||||
200
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
=== d2 롤백 — 26.7.0 으로 되돌린다 ===
|
||||
15:33:48 롤백
|
||||
statefulset.apps/keycloak image updated
|
||||
partitioned roll out complete: 2 new pods have been updated...
|
||||
15:34:55 완료
|
||||
NAME IMAGE READY RESTARTS
|
||||
keycloak-0 quay.io/keycloak/keycloak:26.7.0 true 0
|
||||
keycloak-1 quay.io/keycloak/keycloak:26.7.0 true 0
|
||||
210
|
||||
정문=200
|
||||
=== d2 선택 단계 — 역방향 26.0 으로 일부러 실패시킨다 ===
|
||||
15:34:55 역방향
|
||||
statefulset.apps/keycloak image updated
|
||||
NAME IMAGE STATUS READY RESTARTS
|
||||
keycloak-0 quay.io/keycloak/keycloak:26.7.0 Running true 0
|
||||
keycloak-1 quay.io/keycloak/keycloak:26.0 Running false 2
|
||||
--- 왜 실패했나 ---
|
||||
2026-09-17 06:34:48,994 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (production) mode
|
||||
2026-09-17 06:34:48,995 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: liquibase.exception.ValidationFailedException: Validation Failed:
|
||||
2026-09-17 06:34:48,995 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Validation Failed:
|
||||
2026-09-17 06:34:48,995 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.
|
||||
--- 그런데 서비스는 ---
|
||||
정문=200
|
||||
--- 실패한 기동이 스키마를 건드렸나 ---
|
||||
210
|
||||
|
||||
[exited with code 0]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user