threat-intel-ai-service를 자체 호스팅 k3s 클러스터에 얹힌 뒤 "이거 계속 켜놓아도 되나(리소스든 비용이든)"를 확인한 기록. 결론부터: Gemini API가 유일한 변동비 구성요소이고, 상시 백그라운드 루프가 없어서 방치해도 비용/리소스가 누적되지 않는 구조다.
<table header-row="true"><tr><td>구성요소</td><td>비용 여부</td><td>근거</td></tr><tr><td>Gemini API (chat + embedding)</td><td>유일한 변동비</td><td>사용량 기반</td></tr><tr><td>Docker Hub</td><td>무료</td><td>public 리포 — 저장 용량/pull 횟수 제한 없음</td></tr><tr><td>GitHub Actions</td><td>무료</td><td>public 리포는 Actions 실행 시간이 완전 무제한</td></tr><tr><td>GitHub 리포 호스팅</td><td>무료</td><td>public</td></tr><tr><td>k3s 클러스터, Qdrant, Kafka</td><td>무료(자체 호스팅)</td><td>본인 하드웨어(Multipass VM) 위에서 구동</td></tr></table>
kubectl exec -n c4i <kafka-pod> -- kafka-run-class kafka.tools.GetOffsetShell \
--broker-list localhost:9092 --topic target-tracking
# target-tracking:0:30
kubectl exec -n c4i <kafka-pod> -- kafka-consumer-groups \
--bootstrap-server localhost:9092 --describe --group threat-intel-ai-service
# CURRENT-OFFSET=30 LOG-END-OFFSET=30 LAG=0
토픽에 지금까지 쌊인 메시지가 총 30개, lag 0 — 지금까지의 임베딩 API 호출은 총 30번.
메시지 발행 주체인 target-tracking-service의 DroneSimulator.simulate(int rounds)는 @Scheduled가 아니라 컨트롤러 API를 호출해야만 실행되는 일회성 메서드다. 즉 아무도 시뮬레이터 API를 안 건드리면 Kafka에 새 메시지 자체가 안 생기고, consumer도 소비할 게 없어 대기 상태로 남는다. 상시로 이벤트를 찍어내며 Gemini를 계속 호출하는 백그라운드 루프는 이 시스템 어디에도 없다.
/chat, /ingest/doc도 요청이 와야만 Gemini를 호출하는 구조라, 이 서비스를 켜놓기만 하고 아무도 안 쓰면 Gemini 호출은 0에 수렴한다.
kubectl top pods -n c4i -l 'app in (threat-intel-ai-service,threat-intel-qdrant)'
<table header-row="true"><tr><td>Pod</td><td>CPU 사용/limit</td><td>메모리 사용/limit</td><td>RESTARTS</td></tr><tr><td>threat-intel-ai-service</td><td>6m/300m (2%)</td><td>138Mi/384Mi (36%)</td><td>0</td></tr><tr><td>threat-intel-qdrant</td><td>2m/300m (1%)</td><td>25Mi/384Mi (7%)</td><td>0</td></tr></table>
배포 직후(문서/이력 몇 건만 색인된 상태) 기준으로는 거의 idle 수준이고, 둘 다 재시작 없이 안정적으로 떠 있다. /health 엔드포인트가 liveness/readiness probe에 의해 10~15초 간격으로 계속 호출되는 게 로그에 찍히는데, 이건 Qdrant 연결 상태만 확인하는 저비용 로컬 호출이라 Gemini 사용량과는 무관하다.