개요 — 무엇을 하나
서비스 카탈로그(/service/catalog)는 각 서버에서 실제로 돌아가는 데몬성 서비스(nginx·MySQL·Redis·Docker 등)를 버전 원장에서 자동으로 도출해 운영 카탈로그로 만드는 화면입니다. 수작업으로 서비스 목록을 채워 넣는 대신, Instances ▸ 버전 관리에서 이미 수집한 소프트웨어 원장(infr_instance_software)을 [분석 및 빌드] 한 번으로 infr_service 테이블에 승격시킵니다.
핵심 3요소:
- 자동 구성(Analysis & Build) — 버전 원장의 데몬 소프트웨어 →
infr_service멱등 upsert.UNIQUE(instance_id, software_key)로 중복 없이 몇 번을 눌러도 안전합니다. - 라이브니스(liveness) — 지금 어디서 살아있는지. 기본은 프로브가 채운 런타임 상태(
proc_up/svc_registered/listen_ports), 추가로 온디맨드 라이브 테스트(등록된 서비스 id 에 한해 앱이 직접 TCP/HTTP 접속). - 의존성 · 설정값 — 서비스 간
depends_on그래프 편집(구 Dependencies 메뉴 통합)과, 그 서비스 엔진에 해당하는 서버 파라미터 조회.
카탈로그는 논리 서비스 도달성(헬스체크)만 봅니다. 물리 포트 오픈/노출 스캔은 Security ▸ Firewall의 소관입니다. 이 화면은 자산 대장(Assets ▸ Instances)을 참조해 서비스를 만들 뿐, 임의 호스트를 스캔하지 않습니다.
언제 쓰나
- 새 서버를 편입한 뒤 그 위에서 무엇이 돌고 있는지 서비스 단위로 표준화하고 싶을 때.
- nginx·DB·캐시 같은 데몬이 지금 살아있는지(가동/등록/설치) 한눈에 확인하고, 필요하면 라이브 응답을 즉석에서 찔러 보고 싶을 때.
- 서비스 간 의존 관계(예: 웹 → 같은 호스트 DB·Redis)를 그려 장애 파급을 이해하고 싶을 때.
- AI 튜닝·점검 근거로 특정 서비스의 설정 스냅샷(nginx.conf·my.cnf 등)을 빠르게 열어 보고 싶을 때.
화면 구성
상단에 KPI 스트립(서비스 총계 · 가동 · 주의 · 중단 · 미확인)과 [분석 및 빌드] 버튼, 그 아래 2탭 콘솔이 있습니다.
탭 ① 인스턴스 (Instances)
인스턴스별 카드. 각 카드는 그 호스트의 데몬성 소프트웨어 요약과 등록 서비스 수를 보여줍니다.
| 지표 | 의미 | 산출 |
|---|---|---|
| 데몬 소프트웨어 | 버전 원장에서 is_daemon=1 또는 카탈로그 매핑 키에 해당하는 행 수 |
infr_instance_software |
| 가동(running) | 그 중 proc_up=1 인 수 |
프로세스가 지금 떠 있음 |
| 등록(registered) | svc_registered=1 이지만 proc_up≠1 인 수 |
서비스 등록됐으나 미가동 |
| 서비스 | 이 인스턴스로 구성된 infr_service 행 수 |
COUNT(*) GROUP BY instance_id |
카드의 [빠른 설정] 버튼은 그 인스턴스만 대상으로 [분석 및 빌드]를 실행합니다. **[서비스 보기]**는 탭 ②로 점프합니다. 데몬성 소프트웨어가 하나도 없으면 "[ver]에서 확장 프로브 import 필요" 안내가 뜹니다.
탭 ② 서비스 (Services)
infr_service 카드 목록(인스턴스 정렬 → kind → 이름). 카드마다:
- presence 배지 — 가동(running) / 등록(registered) / 설치(binary) 중 하나.
- 상태(status) — up / degraded / down / unknown.
- 헤더 tier 라벨과 출처(source) 라벨(자동 구성
buildvs 수동manual). - 최근 점검 · 응답(latency) — 마지막 체크 시각과 라이브 응답 ms.
- 카드 하단 액션 —
[테스트]·[설정값]·[의존성], 편집/삭제는 그 위 우측행.
사용법
1) 버전 원장 준비 (선행 조건)
카탈로그는 버전 원장을 원천으로 삼습니다. 먼저 Instances ▸ 버전 관리 [ver]에서 확장 런타임 프로브(infr_version_probe.cjs)의 JSON 을 import 하세요. 이 프로브가 is_daemon/proc_up/svc_registered/listen_ports(마이그레이션 000718 컬럼)를 채워야 라이브니스가 의미를 가집니다.
# 대상 호스트에서 확장 런타임 프로브 실행 → 출력 JSON 을 [ver] ▸ JSON import 에 붙여넣기
node infr_version_probe.cjs
2) [분석 및 빌드] 실행
상단 [전체 분석·구성](모든 인스턴스) 또는 인스턴스 카드의 [빠른 설정](한 인스턴스)을 누릅니다. 서버는 버전 원장에서 ServiceCatalogMap에 매핑된 데몬 키만 골라 infr_service 로 upsert 합니다.
- 멱등 —
instance_id + software_key로 기존 행을 찾아 갱신, 없으면 신규 생성. 여러 번 눌러도 중복이 생기지 않습니다. - 빌드가 관리하는 필드(매 빌드 갱신):
kind·host·port·protocol·check_type·proc_up·svc_registered·listen_ports·status·last_check_at·source='build'. - 수동 편집 보존 —
tier·depends_on·note·project_id는 빌드가 건드리지 않습니다. 한 번 분류·의존성 지정을 해 두면 재빌드해도 유지됩니다. - 반환:
신규 N · 갱신 M 서비스.
빌드 시 상태는 원장 런타임에서 파생됩니다:
proc_up=1 → status = up
svc_registered=1 → status = degraded
그 외 → status = unknown
어떤 소프트웨어가 서비스로 승격되나?
ServiceCatalogMap::MAP에 있는 key 만 승격됩니다. 여기 없는 소프트웨어(툴·바이너리)는 [ver] 원장엔 남지만 서비스가 되지 않습니다. 또 빌드는 그 시점의 원장 행만 승격합니다 — 나중에 버전 JSON 을 import 했다면 [분석 및 빌드]를 다시 눌러야 잡힙니다.
3) 포트 결정 규칙
빌드가 채우는 포트는 다음 우선순위로 결정됩니다(ServiceCatalogMap::resolvePort):
- 원장의 리슨 포트(CSV)가 있고 그 안에 맵 기본 포트가 포함되면 → 기본 포트.
- 리슨 포트가 있지만 기본 포트가 없으면 → 첫 번째 리슨 포트.
- 리슨 포트가 없으면 → 맵 기본 포트.
4) 온디맨드 라이브 테스트
서비스 카드의 **[테스트]**를 누르면 앱이 그 서비스의 host:port로 직접 접속을 시도합니다.
- 프로토콜이 http/https 이거나 check_type=http →
Http::get(TLS 검증 off, 타임아웃 = 정책값). HTTP 상태코드가 0 초과 500 미만이면 성공. - 그 외 →
fsockopen으로 TCP 접속(포트 필수). - 결과는
infr_service_check(source=live)에 이력으로 기록됩니다. - 성공 시에만 서비스의
status=up·latency_ms를 갱신합니다. 미도달은 graceful — 상태를 down 으로 바꾸지 않고 프로브 런타임 상태를 존중합니다.
라이브 테스트는 이미 등록된 서비스 id 로만 실행됩니다. 사용자가 임의 host/port 를 넘길 수 없어 SSRF(서버측 요청 위조)를 원천 차단합니다.
test엔드포인트는 요청 body 의id로infr_service를 조회할 뿐, 주소를 받지 않습니다.
5) 의존성 편집
카드의 **[의존성]**은 이 서비스가 의존하는 다른 서비스 id 배열(depends_on)을 편집합니다(구 Dependencies 독립 메뉴를 여기로 통합). 같은 호스트의 DB·캐시가 흔한 후보로 추천됩니다. 저장 시 서버는 자기 자신 제외 · 실재하는 서비스 id 만 · 정수화 · 중복 제거로 정제합니다.
6) 설정값(config) 조회
카드의 **[설정값]**은 이 서비스의 인스턴스에서 해당 엔진의 서버 파라미터(infr_instance_param)를 끌어와 엔진별로 묶어 보여줍니다(읽기 전용). 매핑은 ServiceCatalogMap::PARAM_ENGINES 가 결정합니다.
| reason | 의미 |
|---|---|
ok |
설정값을 정상 로드 |
no_instance |
서비스에 연결된 인스턴스 없음 → 편집에서 인스턴스 지정 |
no_key |
수동 등록이라 software_key 없음 → [빠른 설정]으로 구성하면 매핑 |
unmapped |
서버 파라미터 스냅샷 대상 아님(예: Redis·MongoDB·Memcached) |
none |
매핑은 되나 수집된 파라미터가 아직 없음 → [param] 프로브 실행 |
각 파라미터에 실무 가이드(paramdoc 언어팩)가 있으면 (i) 아이콘으로 표시되며, 클릭 시 무엇인가 · 성능 영향 · 이럴 땐 이렇게 · 현재 값 설명이 뜹니다. AI 튜닝 질의의 근거로 활용하세요.
7) 수동 서비스 추가·편집
버전 원장에 없는 서비스(예: 외부 AI 엔드포인트·메일·DNS)는 **[서비스 추가]**로 직접 만들 수 있습니다. 저장 시 검증되는 필드:
| 필드 | 규칙 |
|---|---|
| name | 필수, 최대 160자 |
| kind | web·database·vpn·proxy·cache·ftp·ai_endpoint·mail·dns·queue·search·container·other |
| instance_id / project_id / group_id | 실재 참조(각각 infr_instance·infr_project·infr_asset_group) |
| host | 최대 191자 |
| port | 1–65535 |
| protocol | http·https·tcp·udp·grpc·other |
| tier | t0·t1·t2·t3 (t0=미션크리티컬) |
| check_type | http·tcp·ping·none |
| is_monitored | boolean |
데이터 소스
| 테이블 / 맵 | 역할 | 마이그레이션 |
|---|---|---|
infr_service |
운영 서비스 정본. UNIQUE(instance_id, software_key) |
000716 |
infr_instance_software |
버전 원장(빌드의 원천). 런타임 축 is_daemon/proc_up/svc_registered/listen_ports |
000641 + 000718 |
infr_instance |
SSH OS 인스턴스(host/alias/hostname 원천) | 000600 |
infr_instance_param |
설정값 조회 대상(엔진별 서버 파라미터) | 000710 |
infr_service_check |
라이브 테스트 이력(source=live) | 000717 |
infr_asset_group |
카테고리 그룹(서비스 분류 축) | 000714 |
infr_project |
프로젝트 연결(수동 편집 필드) | 000715 |
App\Support\ServiceCatalogMap |
software_key → kind·포트·프로토콜·파라미터 엔진 SOT | — |
ServiceCatalogMap::MAP (승격 대상 = kind · 기본포트 · 프로토콜)
| software_key | kind | 기본 포트 | protocol |
|---|---|---|---|
| nginx / apache / caddy | web | 443 | https |
| tomcat | web | 8080 | http |
| haproxy / traefik | proxy | 443 | https |
| ftp | ftp | 21 | tcp |
| php (php-fpm) | other | 9000 | tcp |
| mysql | database | 3306 | tcp |
| postgresql | database | 5432 | tcp |
| mongodb | database | 27017 | tcp |
| redis | cache | 6379 | tcp |
| memcached | cache | 11211 | tcp |
| elasticsearch | search | 9200 | http |
| rabbitmq | queue | 5672 | tcp |
| kafka | queue | 9092 | tcp |
| jenkins | other | 8080 | http |
| docker / containerd | container | (없음) | tcp |
| kubelet | container | 10250 | https |
| wireguard | vpn | 51820 | udp |
| openssh | other | 22 | tcp |
| node_exporter | other | 9100 | http |
| grafana_agent | other | 12345 | http |
임계값 (Operations Policy)
라이브니스 판정 임계는 Administration ▸ 운영 정책의 OpsPolicy::catalogThresholds()에서 옵니다.
| 키 | 기본값 | 의미 |
|---|---|---|
catalog_stale_min |
1440 (1일) | 프로브 상태가 N분 초과 오래되면 카드에 "오래됨(stale)" 표기 |
catalog_live_timeout_ms |
2000 | 온디맨드 라이브 테스트 접속 타임아웃(ms, 최소 200) |
권한
- 조회(index/live/config/test) — 로그인(레벨 ≥ 1,
infr.auth그룹). demo(1) 사용자도 카탈로그를 보고 라이브 테스트를 실행할 수 있습니다. - 쓰기(build/save/delete/deps) — 레벨 ≥ 2(staff=5·admin=10). 컨트롤러가
infr_user_level >= 2를 self-gate 로 재확인하며, 실패 시 403(catalog.err.forbidden). - 감사 — 빌드·저장·삭제·의존성 변경은 전량
infr_audit_log에 기록됩니다(service.build/service.create/service.update/service.delete/service.deps).
문제해결 · FAQ
Q. [분석 및 빌드]를 눌러도 "신규 0 · 갱신 0"만 나옵니다.
버전 원장에 매핑 대상 데몬이 없기 때문입니다. Instances ▸ [ver]에서 확장 프로브 JSON 을 import 했는지, 그리고 is_daemon/리슨 포트가 채워졌는지 확인하세요. ServiceCatalogMap::MAP에 없는 소프트웨어는 승격되지 않습니다.
Q. 서비스가 모두 "미확인(unknown)"입니다.
proc_up·svc_registered가 비어 있으면 상태를 판정할 수 없습니다. 이는 확장 런타임 프로브(000718 컬럼)가 아직 원장을 채우지 않은 경우입니다. [테스트]로 라이브 응답을 확인하거나 확장 프로브를 다시 import 하세요.
Q. [테스트]가 계속 "응답 없음 — 미도달"입니다.
앱 서버에서 그 host:port 로 실제 네트워크 도달이 되는지 확인하세요(방화벽·내부망 경로). 미도달은 의도적으로 상태를 down 으로 바꾸지 않고 프로브 상태를 유지합니다. HTTP 서비스인데 5xx 를 반환하면 실패로 처리됩니다(http_5xx).
Q. 재빌드하면 내가 지정한 tier·의존성이 지워지나요?
아니요. 빌드는 tier·depends_on·note·project_id를 보존합니다. kind·port·라이브니스 등 자동 관리 필드만 갱신합니다.
Q. [설정값]이 "unmapped"라고 나옵니다.
Redis·MongoDB·Memcached 등은 서버 파라미터 스냅샷 대상이 아닙니다(PARAM_ENGINES에 없음). nginx·mysql·postgres·php·haproxy·docker·kafka·elasticsearch·vsftpd(ftp)·jenkins 만 설정값 조회를 지원합니다.
Q. Endpoints·Dependencies 메뉴가 안 보입니다. 카탈로그로 통합됐습니다. 논리 도달성 = 카탈로그 라이브니스, 의존성 = 카드의 [의존성] 편집입니다.
관련 항목
- Instances ▸ 버전 관리 — 카탈로그의 원천이 되는 소프트웨어 버전 원장.
- Instances ▸ 서버 파라미터 — [설정값]이 읽어 오는 엔진별 설정 스냅샷.
- Assets ▸ Instances — 인스턴스 자산 대장(host·alias 원천).
- Service ▸ Overview — 카탈로그 서비스로 라이브 보드를 큐레이션.
- Service ▸ Projects — 서비스를 프로젝트에 연결(web/db 참조).
- Administration ▸ 운영 정책 — stale·라이브 타임아웃 임계 조정.
