Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/test-results/evidence/issue-446/current-state-20261009.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# OpenSQL HA 관측 도입 전 현재 상태 — 2026-10-09

- 실행 ID: `ha446inventory20261009a`
- 수집 종료: 2026-10-09 04:38 KST (2026-10-08 19:38 UTC)
- 목적: 이전 시험 문서의 VM·배포·클러스터 상태를 현재 상태로 가정하지 않는다.
- 실행 위치: 로컬 `gcloud` 읽기 명령과 GCP VM 게스트의 읽기 전용 명령. VM 명칭·내부 주소·프로젝트 ID·계정·비밀은 기록 전에 제외했다.
- 성공 기준: 앱 2대·DB 3대·부하 VM·캐시 VM 실행, LB 2/2, 동일 배포 JAR, Patroni 리더 1·replica 2, etcd 멤버 3/3 건강, 프록시 A/B 실제 프로세스·6432 리스너 확인.

| 확인 위치·목적 | 명령 또는 읽기 방법 | 결과 요약 | 해석 |
| --- | --- | --- | --- |
| 로컬 GCP API · VM 목록 | `gcloud compute instances list --format=json` 후 역할·상태만 출력 | 앱 **2/2**, DB **3/3**, 부하 **1/1**, 공용 캐시 **1/1 RUNNING**. 기존 비관측 VM **1대 TERMINATED** | 게스트 내부 서비스 건강을 뜻하지 않는다. |
| 로컬 GCP API · LB | `gcloud compute backend-services get-health` 결과의 상태만 집계 | 내부 앱 LB 백엔드 **2/2 HEALTHY** | HA 쓰기 성공·DB 복제 상태를 뜻하지 않는다. |
| 앱 A/B · 배포 일치 | IAP SSH에서 `systemctl is-active docgrid`, 실행 JAR의 `sha256sum`, `curl localhost:8081/actuator/prometheus` | 서비스 **2/2 active**, JAR SHA-256 **두 VM 동일** (`8510908ce6f5454d0e6cd64fa5c4de3b2b0ddf5ee63602eb8fab4c0fc46297fb`), metrics HTTP **200/200** | JAR 비트 동일성은 확인. 현재 소스 커밋은 JAR만으로 역추정하지 않았다. |
| DB 3대 · Patroni | 각 노드 `GET /patroni`; node1 `GET /cluster` | node3 **primary**, node1·node2 **replica**, 모두 `running`, timeline **14**, 클러스터 역할 **leader 1·replica 2** | 역할과 REST 응답은 수집 시점 관측. 실제 장애 결과가 아니다. |
| DB 3대 · etcd | 각 노드 로컬 `GET /health`; 한 노드의 읽기 전용 `POST /v3/cluster/member/list` | 로컬 health **3/3 true**, 실행 멤버 **3개** | 정족수 정상 상태만 확인. etcd 장애를 주입하지 않았다. |
| DB node2·node3 · OpenProxy | 프로세스 목록과 TCP 6432 `LISTEN` 확인 | 각 노드 프로세스 **1개**, 6432 리스너 **1개**. node1 프록시 **0개** | 이름을 모르는 systemd 유닛의 `inactive`만으로 프록시 중단이라 판정하지 않았다. |
| 앱·DB · metrics endpoint | 앱 A/B loopback 8081, DB 3대 loopback 8008 | 앱 **2/2 HTTP 200**, Patroni **3/3 HTTP 200** | 관측 VM에서의 네트워크 접근은 별도 시험으로 판정한다. |

게스트 접근에는 **30분 자동 만료 OS Login 키**를 사용했다. 로컬 개인키는 명령 종료 시 삭제했다. 실행 중 상태가 바뀔 수 있으므로 이 표를 이후 장애 시험의 사전 점검으로 재사용하지 않는다.
41 changes: 41 additions & 0 deletions docs/test-results/evidence/issue-446/gateway-hardening-20261009.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Patroni 지표 경계 보강 — 2026-10-09

- 실행 ID: `ha446gateway20261009a`
- 확인 시각: 2026-10-09 약 04:45~05:00 KST. 각 명령의 정확한 초 단위 시각은 클라우드 감사 로그와 systemd journal에 남으며 이 비식별 요약에는 집계 구간만 기록한다.
- 목적: 관측 VM이 무인증 Patroni 관리 REST API에 접근하지 않으면서 DB 3대의 역할 지표를 계속 수집한다.
- 실행 위치: 로컬 독립 작업트리, GCP DB VM 3대, 관측 VM, 부하 VM, GCP 방화벽·LB API.
- 성공 기준: 게이트웨이 회귀 4/4, 각 DB의 `/metrics` 200·관리 GET/POST 거부, Prometheus 새 18008 active target 3/3, 관측 VM→8008 차단 3/3, 부하 VM→18008·앱 8081 차단, LB HEALTHY 2/2.
- 비밀·주소: 내부 IP와 프로젝트 ID, SSH 키, API 암호는 기록 전에 제외했다. SSH 개인키는 임시 디렉터리에서 실행 종료 시 삭제했고 공개키는 30분 만료로 등록했다.

## 발견과 수정 순서

| 순서·실행 위치 | 명령·방법 | 결과 요약 | 해석 |
| --- | --- | --- | --- |
| 1. DB 컨테이너 3대 | 실행 Patroni YAML의 `restapi` 항목을 컨테이너 내부에서 읽고 인증·TLS 키 존재 여부만 판정 | 노드 **3/3 모두 인증·TLS 항목 없음** | 직접 8008 scrape는 관측 VM에 무인증 관리 REST API의 네트워크 경로까지 제공한다. 비밀 원문은 출력하지 않았다. |
| 2. 로컬 첫 테스트 | `python3 -m unittest scripts/opensql/test_patroni_metrics_gateway.py -v` | **import 오류 1회** | 테스트 모듈 경로를 잘못 지정한 실행 오류. 코드는 아직 검증되지 않았다. |
| 3. 로컬 재실행 | `PYTHONPATH=scripts/opensql python3 -m unittest test_patroni_metrics_gateway -v` | 초기 **4/4 통과**, RFC1918 바인딩 조건 추가 후 최종 **5/5 통과** | 고정 upstream `GET /metrics`만 전달, 관리 GET 404·변경 메서드 405, upstream 오류 502·와일드카드 바인딩 거부를 검증했다. 로컬 소켓 바인딩이 필요한 시험이다. |
| 4. DB node1 첫 설치 | `gcloud compute scp` → `sudo install` → `systemctl enable --now` | **기동 실패 1회**, `216/GROUP` | 해당 DB OS에는 `nogroup`이 없었다. 테스트 실패를 숨기지 않고 OS의 계정 구성을 재확인했다. |
| 5. DB node1 수정 | 그룹 확인 후 systemd unit을 `DynamicUser=yes`로 바꿔 재시작 | 서비스 active, `/metrics` **200** | 공용 `nobody` 계정 경고도 제거하고 전용 임시 사용자로 실행했다. 재시작 직후 첫 curl 한 번은 기동 경합으로 실패했으나 다음 조회는 200이었다. Patroni·DB는 재시작하지 않았다. |
| 6. DB node2/3 설치 | 동일 코드·unit 배포, private IP에만 바인딩, systemd active 확인 | **2/2 active**, `/metrics` **200 2/2**, `/patroni` **404 2/2**, `POST /switchover` **405 2/2** | 새 포트에서 지표와 관리 경로가 분리됐다. node1도 수정 전·후 지표 200과 관리 GET 404·POST 405를 개별 확인했다. |
| 7. GCP 방화벽 | 관측 VM `/32` → DB 18008 allow 규칙 생성 | 생성 **1건 성공** | 기본 내부 허용과 별개로 명시적인 수집 예외를 만들었다. |
| 8. 관측 VM | DB node1/2/3의 새 18008에 `GET /metrics`, `GET /patroni` | 지표 **200 3/3**, 관리 조회 **404 3/3** | 관측 VM에서 실제 네트워크 경로가 열렸다. |
| 9. 관측 VM | Prometheus 대상 8008→18008 3곳 변경, Prometheus 컨테이너만 재시작, `/api/v1/targets?state=active` 조회 | active target **5/5 up**, DB 포트 **18008 3/3**, 앱 포트 **8081 2/2** | 이전 8008 시계열은 TSDB 조회에서 잠시 함께 보였으므로 단순 `up` 시계열 수가 아니라 현재 active target으로 판정했다. `patroni_primary=1` 1개·`0` 2개, `patroni_postgres_running=1` 3개도 새 포트에서 확인했다. |
| 10. GCP 방화벽 첫 정리 | 우리가 만든 관측 VM→DB 8008 allow 규칙 삭제 후 관측 VM에서 8008 TCP 연결 확인 | 삭제 **성공**, 하지만 **8008 OPEN 3/3** | 기존 `default-allow-internal`이 모든 내부 TCP를 허용했다. 허용 규칙 삭제만으로는 접근 차단이 되지 않는다는 실패 사례다. |
| 11. GCP 방화벽 보강 | 관측 VM `/32`→DB 8008 명시 DENY(우선순위 650); DB 18008·앱 8081은 필요한 관측 VM/LB 예외보다 낮은 우선순위의 전체 출처 DENY(우선순위 1000) | DENY **3개 생성 성공** | 앱 8081의 기존 LB health checker ALLOW 우선순위 900을 유지했다. 다른 VM의 기존 8008 정책까지 수정하지 않았다. |
| 12. 양쪽 VM 재검증 | 관측 VM→DB 8008/18008·앱 8081, 부하 VM→DB 18008·앱 8081·관측 9090 | 관측 VM: 8008 **CLOSED 3/3**, 18008 **200 3/3**, 앱 8081 **200 2/2**. 부하 VM: DB·앱 지표 **CLOSED 2/2**, 9090 **OPEN 1/1** | 목적별 허용·거부를 양쪽 출처에서 검증했다. 18008의 관리 POST는 **405 3/3**(node1 초기, node2/3 설치, 관측 VM node1 재확인). |
| 13. GCP LB API | `gcloud compute backend-services get-health` | 앱 A/B **HEALTHY 2/2** | 8081 거부 규칙이 LB의 health check를 끊지 않았다. |
| 14. 로컬 최종 회귀·DB 순차 재배포 | `PYTHONPATH=scripts/opensql python3 -m unittest test_verify_ha_prometheus_rw test_ha_load_telemetry test_sanitize_ha_k6_events test_patroni_metrics_gateway`; `bash -n`; `node --check`; `git diff --check`; 게이트웨이 코드만 DB 3대 재배포 | Python **22/22**, 나머지 **각 종료 0**; 재배포 후 DB `/metrics` **200 3/3**, Prometheus active target **5/5 up** | 와일드카드·특수 주소 바인딩을 거부하도록 제한하고 실제 실행 경로가 유지됨을 확인했다. |

## 경계와 남은 한계

```text
관측 VM ──▶ DB :18008 ── GET /metrics ──▶ 127.0.0.1:8008 Patroni
│ └─ 최대 1MiB·2초 timeout, 실패 시 502
└─X─▶ DB :8008 (명시적인 출처별 DENY)

부하 VM ──X─▶ DB :18008 / 앱 :8081
부하 VM ─────▶ 관측 VM :9090 (Remote Write)
LB health checker ─────▶ 앱 :8081 (기존 허용 유지)
```

이 결과는 **관측 VM에서 Patroni 관리 포트로 가는 경로**를 차단했다는 뜻이다. 기존 `default-allow-internal`은 여전히 다른 내부 VM에 넓은 포트를 허용할 수 있다. 이 PR은 OpenSQL 운영망 전체의 REST 인증·TLS·세그먼테이션을 정비하지 않는다. 게이트웨이 역시 DB 호스트에 새 systemd 서비스 3개를 남기며, Patroni 재기동 후 지표 응답과 systemd 자동 재시작은 이번에는 따로 장애 주입하지 않았다. Prometheus·Grafana VM과 부하·앱·DB VM은 모두 중지하지 않았다.
21 changes: 21 additions & 0 deletions docs/test-results/evidence/issue-446/local-regression-20261009.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# k6 계측 코드 로컬 회귀 — 2026-10-09

- 실행 ID: `ha446local20261009a`
- 기록 시각: 2026-10-09 04:38 KST
- 목적: JSONL 안전 게이트를 유지하면서 결과별 Counter와 원격 최종 합계 대조기를 추가한다.
- 실행 위치: 최신 `develop`에서 만든 독립 `test/446` 작업트리. 기존 작업 폴더의 수정·미추적 파일은 건드리지 않았다.
- 성공 기준: 관련 Python suite **17/17**, Bash·JS 구문 검사, diff whitespace 검사 통과. 원격 DB 장애 성능은 이 로컬 시험의 대상이 아니다.

| 순서·명령 | 결과 요약 | 해석 |
| --- | --- | --- |
| 초기 `python3 -m unittest scripts/opensql/test_verify_ha_prometheus_rw.py scripts/opensql/test_ha_load_telemetry.py` | **9개 탐색 중 1개 import 오류**, 나머지 8개 통과 | 테스트 코드 실패가 아니라 루트 기준 직접 모듈명 호출에서 `scripts/opensql`이 import 경로에 없었다. 실패 시도를 지우지 않는다. |
| `python3 -m unittest discover -s scripts/opensql -p 'test_verify_ha_prometheus_rw.py'` | **6/6 통과** | 원장 이벤트 검증, 502 보존, 사설 수신 주소, 마지막 Counter, 누락 판정 확인. 네트워크는 mock이다. |
| `python3 -m unittest discover -s scripts/opensql -p 'test_ha_load_telemetry.py'` | **8/8 통과** | 새 태그 없는 Counter가 기존 JSONL 요약을 깨지 않음. 태그가 붙은 임의 지표를 허용하도록 게이트를 완화하지 않았다. |
| `python3 -m unittest discover -s scripts/opensql -p 'test_sanitize_ha_k6_events.py'` | **3/3 통과** | 원장 안전 이벤트 필드 검증의 기존 회귀 조건을 유지했다. |
| `bash -n scripts/opensql/run_ha_probe_k6.sh` | 종료 코드 **0** | 셸 구문 확인. 실제 부하 실행은 아니다. |
| `node --check scripts/opensql/ha_probe_load.js` | 종료 코드 **0** | JavaScript 구문 확인. k6 런타임 검사는 별도 수행. |
| `git diff --check` | 종료 코드 **0** | 변경 파일의 공백 오류 없음. |
| 부하 VM k6 2.3.0 `k6 inspect` 첫 시도 | 종료 코드 **107**, 필수 `HA_*` 값 없음 | `inspect`는 전달한 프로세스 환경 변수를 스크립트에 넣지 않았다. HTTP 요청은 발생하지 않았다. |
| 부하 VM `k6 inspect -e HA_RUN_ID=... -e HA_TARGET_URL=... -e HA_JWT=dummy -e HA_SUMMARY_FILE=... ha_probe_load.js` | 종료 코드 **0**, 구조 JSON 생성 | 합성값으로 실제 설치된 k6 런타임 파싱을 확인. 토큰이나 HTTP 요청을 사용하지 않았다. |

현재 부하 VM에서 읽은 기존 후보 JWT 파일 **1개는 만료 전·0600 조건을 충족하지 않았다**. 따라서 수정된 전체 HA probe를 실제 앱 쓰기로 재실행하지 않았다. 원격 전송 자체는 [별도 합성 시험](remote-write-ha446rw20261009a.md)에서 확인했다.
28 changes: 28 additions & 0 deletions docs/test-results/evidence/issue-446/observer-security-20261009.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 관측 VM 구성·접근 경계 — 2026-10-09

- 실행 ID: `ha446observer20261009a`
- 초기 구성 확인: 2026-10-09 04:44 KST. 이후 접근 경계를 보강했으며, **이 문서의 8008 허용 상태를 최종 상태로 읽으면 안 된다.**
- 목적: 앱/DB 장애와 분리된 관측 경로를 만들되 관리 포트를 외부 인터넷에 공개하지 않는다.
- 실행 위치: GCP API, 신규 관측 VM, 부하 VM, 앱 A VM.
- 성공 기준: 관측 VM RUNNING, Prometheus/Grafana 실행, 수집 대상 5/5 UP, k6만 9090 접근, Grafana 인증·loopback, 외부 포트 차단.

| 작업·명령/방법 | 결과 요약 | 해석 |
| --- | --- | --- |
| `gcloud compute firewall-rules create` — 관측 태그 DENY ingress 우선순위 800, IAP SSH·부하 VM 9090 ALLOW 우선순위 700 | 규칙 **3개 생성** | 외부 IP는 패키지 설치 outbound용이다. 우선순위가 높은 허용 경로 외의 신규 유입을 거부한다. |
| `gcloud compute instances create` — Debian 12, `e2-standard-2`, 균형 디스크 30GB, 서비스 계정 없음 | 관측 VM **1대 RUNNING**, 부착 디스크 **1개**, 서비스 계정 **0개** | VM 실행·디스크 보관에 추가 과금된다. 클러스터 장애 대상과 별도 VM이다. |
| `gcloud compute firewall-rules create` — 관측 VM `/32`에서 앱 8081·DB 8008, 부하 VM `/32`에서 관측 9090 | 세 규칙 **3/3 생성** | Patroni의 관리 API도 같은 8008에 있으므로 출처를 관측 VM 단일 내부 IP로만 제한했다. |
| 게스트 `apt-get install docker.io`, 공식 이미지 `prom/prometheus:v3.5.5`, `grafana/grafana:13.2.3` | Docker 설치 **성공**, 컨테이너 **2/2 running** | Prometheus retention **7일·15GB**, scrape 간격 **5초**, timeout **2초**. |
| 관측 VM Prometheus `query=up` | 앱 **2/2 UP**, Patroni **3/3 UP** | 각 metrics endpoint에서 실제 수집됨. `UP=1`만으로 DB의 쓰기 정합성은 증명하지 않는다. |
| Prometheus `patroni_primary`, `patroni_postgres_running` | `patroni_primary`: **1값 1개·0값 2개**; `patroni_postgres_running`: **1값 3개** | 단순 포트 열림이 아니라 역할·실행 메트릭도 수집됨. |
| Grafana `/api/datasources/uid/ha-prometheus` | 인증 없이 **401**, 보호된 관리자 인증 후 **200**, Prometheus 데이터소스 확인 | Grafana 3000은 **127.0.0.1에만** 바인딩. 관리자 암호는 관측 VM의 읽기 제한 파일에만 있고 문서·로그로 전송하지 않았다. |
| 부하 VM → 관측 VM `GET /-/ready`; 앱 A → 같은 주소 | 부하 VM **HTTP 200**, 앱 A **연결 불가** | 허용/비허용 원본 VM에서 경계를 각각 시험했다. |
| 로컬 외부 위치 → 관측 VM 공인 IP TCP 22·3000·9090 | 각 포트 **연결 불가 (3/3)** | IAP SSH는 별도 경로로 성공했다. 공인 IP가 있어도 관리 포트는 외부에서 열리지 않았다. |
| DB node1 Patroni 실행 설정 탐색 | 실행 프로세스 인자에서 YAML 후보 **1개** 발견 후 호스트 `sudo cat` 읽기 시도 | 호스트에서 읽기 **실패**, REST 쓰기 API의 인증·TLS 설정 **미판정** | `GET /metrics` 성공만으로 변경 API의 인증을 단정할 수 없다. 관리 API에 변이 요청을 보내지는 않았다. |

기존 앱 8081 규칙은 GCP 내부 LB health check에 사용되며 출처 CIDR 두 개가 기존대로 남아 있다. 이를 관측 VM `/32` 하나로 바꾸면 LB 2/2 상태를 깨므로 **관측 VM과 LB health checker만 예외로 허용**한다. Patroni 8008은 방화벽이 URL 경로를 구분하지 못해 관측 VM에서 지표뿐 아니라 관리 API에도 네트워크상 도달할 수 있다. 이번 점검에서는 변경 API의 인증 구성을 판정하지 못했다. 프로젝트에는 정지된 과거 VM 태그를 대상으로 한 공인 3000 허용 규칙도 존재한다. 현재 실행 VM에는 적용되지 않았으며 이번 범위에서 타인의 과거 규칙을 변경하지 않았다. 향후 해당 VM을 재시작할 때 별도 감사가 필요하다.

관측 VM을 계속 RUNNING으로 두면 **VM 계산 자원·30GB 디스크·사용 중 외부 IPv4** 비용이 지속되며 이미지 다운로드 등의 네트워크 요금도 발생할 수 있다. 외부 IPv4는 패키지·이미지 설치용 outbound를 위해 붙였고 모든 일반 inbound는 차단했다. 정확한 청구액은 계정의 SKU·할인·실제 사용량에 달려 있어 여기서 확정하지 않는다. 관측이 끝나면 VM 중지 여부를 사용자가 결정해야 하며, 중지 후에도 디스크 비용은 남는다. [Google Cloud VM 요금](https://cloud.google.com/products/compute/pricing), [디스크 요금](https://cloud.google.com/compute/disks-image-pricing), [네트워크·외부 IPv4 요금](https://cloud.google.com/vpc/network-pricing). 이번 작업에서는 VM·컨테이너를 내리지 않았다.

## 뒤이은 보안 정정

호스트에서 읽히지 않던 실행 YAML은 **DB 컨테이너 내부**에서 다시 확인했다. 세 노드 모두 Patroni `restapi`에 인증·TLS 항목이 없었다. 초기의 관측 VM→8008 `/32` 허용은 관리 REST API에 대한 네트워크 접근도 열었으므로 최종 정책으로 부적절했다. 지표 전용 18008 게이트웨이를 설치하고 Prometheus active target 5/5를 확인한 뒤, 우리가 만든 8008 허용 규칙을 삭제했다. 그러나 기존 `default-allow-internal` 규칙 때문에 관측 VM→8008 연결이 여전히 **3/3 OPEN**인 실패 결과가 나왔다. 이후 관측 VM 출처의 DB 8008을 더 높은 우선순위로 명시적으로 거부했고, 최종 재검증에서는 **3/3 CLOSED**였다. 전체 변경·시험·남는 VPC 내부 위험은 [별도 보강 로그](gateway-hardening-20261009.md)에 보존한다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# k6 Remote Write 합성 전송 — `ha446rw20261009a`

- 실제 이벤트 시각: 2026-10-09 **04:33:20.645–04:33:20.646 KST** (2026-10-08 19:33:20 UTC)
- 실행 위치: GCP 내부 부하 VM → GCP 내부 관측 VM.
- 목적: 실제 DB를 쓰지 않고 k6 2.3.0의 JSONL·Prometheus Remote Write 동시 출력과 마지막 카운터 대조를 확인한다.
- 성공 기준: 합성 `sent`·`acknowledged` **각 1건**, Prometheus `201` Counter **1건**, 나머지 **0건**, JSONL 태그 **0건**, 대조 일치.

| 순서·방법 | 관측 결과 | 해석 |
| --- | --- | --- |
| 합성 k6 JS에서 태그 없는 `ha_outcome_201` Counter 1회와 안전 이벤트 두 줄 생성, `--out json=... --out experimental-prometheus-rw` 동시 실행 | k6 종료 코드 **0**, 이벤트 **2건**, JSONL 지표 Point **5건** | 실제 HTTP·DB 쓰기는 실행하지 않은 전송 경로 시험이다. |
| `K6_PROMETHEUS_RW_LABELS=run_id=ha446rw20261009a`, `K6_PROMETHEUS_RW_STALE_MARKERS=true` | JSONL에서 태그가 붙은 Point **0건**, `ha_outcome_201` Point **1건** | Remote Write 전용 라벨이 기존 JSONL 증거의 태그 금지 규칙에 섞이지 않았다. |
| `HA_PROM_RW_URL=<관측 VM 사설 주소>/api/v1/write python3 verify_ha_prometheus_rw.py verify --events ... --run-id ha446rw20261009a` | 예상 `201=1`, 관측 `201=1`, `500=0`, `503=0`, 기타 실패=0, 불명=0. **첫 조회에서 일치** | 마지막 Prometheus 카운터와 클라이언트 원장 합계가 같다. 중간 전송 시각의 공백은 이 검증으로 판정할 수 없다. |

안전한 원본 이벤트·지표·대조 JSON은 부하 VM의 사용자 전용 `ha-observer-446/` 폴더에 실행 ID별 파일로 남겼다. 저장소에는 내부 주소가 들어갈 수 있는 원본 지표 파일을 넣지 않았다. **실제 HA probe HTTP 쓰기, 실패율·지연, 요청 ID의 DB 대조, 장애 전환은 이번 합성 시험에서 미실행**이다.
Loading
Loading