
Eco² vocabulary
- edge
- auth offload
- domain api
- task queue
- scan pipeline
- chat agent
- event bus
- cluster
- gitops
- autoscaling
- observability
- load test
- evaluation
Edge: ROUTE 53 · ALB · HTTPS 443 · internet-facing · external-dns · istio-ingressgateway · NodePort · eco2-gateway · VirtualService · x-canary · AuthorizationPolicy · ENVOY SIDECAR · kiali-serverAuth Offload: AuthorizationPolicy · action: CUSTOM · notPaths · envoyExtAuthzGrpc · failOpen: false · CheckRequest · x-user-id · BlacklistCache · BootstrapFromRedis · outbox:blacklist · blacklist.events · UsersServiceDomain API: VirtualService · x-user-id · /api/v1/scan · X-Idempotency-Key · job_id · stream_url · 202 ACCEPTED · Retry-After · ScanTask · UsersService · ImageService · ENVOY SIDECARTask Queue: outbox:blacklist · blacklist.events · RabbitmqCluster · scan.direct · reward.events · dlx · x-dead-letter-exchange · chat.process · AioPikaBroker · task_acks_late · apply_async · gevent · scan.vision · scan.rule · scan.answer · scan.reward · CELERY CHAIN · QueueLength · inspect ping · QUEUE SATURATIONScan Pipeline: ScanTask · scan.direct · reward.events · apply_async · gevent · scan.vision · scan.rule · scan.answer · scan.reward · CELERY CHAIN · RewardStep · item_class_list.yaml · situation_tags.yaml · LITE RAG · JsonRegulationRetriever · PipelineStage · waste_rag · XADD · domain: worker-ai · pipeline_duration · vision_stage_durationChat Agent: ImageService · chat.process · AioPikaBroker · create_chat_graph · route_by_intent · MULTI-INTENT FANOUT · waste_rag · recyclable_price · collection_point · image_generation · aggregator · thread_id · SyncableRedisSaver · AsyncPostgresSaver · LANGSMITH_TRACING · regenerateEvent Bus: job_id · stream_url · PipelineStage · XADD · scan:events:{shard} · XREADGROUP · XACK · XAUTOCLAIM · PendingReclaimer · STATE KV · scan:state:{job_id} · sse:events:{shard} · SSEBroadcastManager · Last-Event-ID · scan_sse_connections_active · ServiceMonitor · traceparentCluster: NodePort · kubeadm init · kubeadm join · vxlanMode · BGPConfiguration · module "vpc" · worker_ai · nodeSelector · domain: worker-ai · NoSchedule · 24-NODE CLUSTERGitOps: external-dns · x-canary · dev-root · ApplicationSet · sync-wave · selfHeal · ignoreDifferences · argocd-image-updater · update-strategy: digest · write-back-method · targetRevision · ci-services.ymlAutoscaling: ignoreDifferences · ScaledObject · QueueLength · cooldownPeriod · pollingInterval · fallback · maxReplicaCount · stabilizationWindowSeconds · HorizontalPodAutoscaler · scan_sse_connections_active · prometheus-adapterObservability: 24-NODE CLUSTER · prometheus-adapter · FLUENT BIT · Elasticsearch · Kibana · kube-prometheus-stack · AlertmanagerConfig · ServiceMonitor · JAEGER · OPENTELEMETRY · traceparent · kiali-server · LANGSMITH_TRACINGLoad Test: k6 · ramping-vus · thresholds · pipeline_duration · vision_stage_duration · poll_timeout · inspect ping · WORKER RESTART · POLLING TIMEOUT · QUEUE SATURATIONEvaluation: EvalConfig · eval_mode · eval_sample_rate · eval_cost_budget_daily_usd · EvalResult · EvalGrade · code_grader · llm_grader · CUSUM · regenerate · OpenAIBARSEvaluator
24개 노드가 실제로 어떻게 이어지는지, 흐름 하나씩 따라 봅니다.
kubeadm으로 구성한 자체 관리 Kubernetes입니다. 지도는 README의 다섯 레이어 안에 24개 물리 노드와 그 위의 워크로드를 놓고 실제 연결을 화살표로 이었습니다. 흐름을 고르면 그 경로만 번호와 함께 강조됩니다.
폐기물 사진을 식별해 배출 방법을 안내하고, 대화 중에는 장소 · 날씨 · 재활용 시세 · 웹 검색 도구와 이미지 생성을 써서 답합니다. 팀 프로젝트에서 클러스터 · 배포 기반으로 시작해 도메인 백엔드, 비동기 처리, 대화 에이전트와 검증으로 맡은 범위를 넓혔습니다.
대회 개발 이후 백엔드·운영 고도화까지의 참여 기간
서비스는 운영을 마쳤고, 동작 영상과 기술 보고서로 그 모습을 볼 수 있습니다.
Scan 요청 → 실시간 전달
사진 분석 요청이 작업이 되고, 진행 이벤트가 같은 브라우저로 돌아오는 길입니다.
브라우저DNS 조회: DNS 조회Route 53
Route 53 레코드로 이름만 찾습니다. 요청이 DNS를 지나가지는 않습니다.
브라우저데이터 흐름: HTTPS 443AWS ALB
ALB가 TLS를 끝냅니다.
AWS ALB데이터 흐름: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayEC2 instance target의 NodePort로 Istio ingress Envoy에 넘깁니다.
Istio ingress Envoy
k8s-ingress-gateway데이터 흐름: VirtualServiceScan APIk8s-api-scanScan API로 라우팅합니다. Scan API는 작업을 맡기고 job_id를 바로 돌려주며, 결과 조회에는 끝날 때까지 202로 답합니다.
Scan API
k8s-api-scan데이터 흐름: Celery 작업RabbitMQk8s-rabbitmqRabbitMQ에 Scan 작업을 넣습니다.
RabbitMQ
k8s-rabbitmq데이터 흐름: consumescan-workerk8s-worker-ai · k8s-worker-ai-2AI 풀의 scan-worker(Celery · gevent)가 받아 Vision → Rule → Answer → Reward를 실행합니다. 네 단계는 chain으로 이은 Celery task이며 노드가 아닙니다.
AI 풀
k8s-worker-ai · k8s-worker-ai-2데이터 흐름: HTTPSLLM APIscan · chat worker가 OpenAI · Google API를 호출합니다.
scan-worker
k8s-worker-ai · k8s-worker-ai-2데이터 흐름: XADD scan:eventsStreamsk8s-redis-streams진행 이벤트를 Streams shard 4개 중 하나에 기록합니다.
Streams
k8s-redis-streams데이터 흐름: XREADGROUPEvent Routerk8s-event-routerEvent Router가 consumer group으로 읽고, 처리한 뒤 XACK합니다. pending · reclaim으로 at-least-once 전달을 지킵니다.
Event Router
k8s-event-router데이터 흐름: SETEX stateState KVk8s-redis-streams같은 Redis 노드의 State KV에 최신 상태와 중복 처리 표시를 씁니다.
Event Router
k8s-event-router데이터 흐름: PUBLISHPub/Subk8s-redis-pubsubshard Pub/Sub의 job 채널로 실시간 전달합니다.
Pub/Sub
k8s-redis-pubsub데이터 흐름: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway는 프로세스마다 공유 listener 하나로 구독해, 연결된 브라우저마다 나눠 보냅니다.
SSE Gateway
k8s-sse-gateway데이터 흐름: SSE 스트림브라우저같은 ALB · ingress 경로로 열린 연결입니다. at-least-once이며 중복은 멱등하게 처리합니다.
State KV
k8s-redis-streams데이터 흐름: 재접속 복구SSE Gatewayk8s-sse-gatewayLast-Event-ID로 다시 붙으면 State KV와 보존된 Streams를 읽어 빠진 이벤트를 채웁니다.
Chat · 토큰과 저장
Chat 토큰은 Scan과 같은 이벤트 경로로 가고, checkpoint와 메시지는 서로 다른 워크로드가 저장합니다.
브라우저데이터 흐름: HTTPS 443AWS ALB
ALB가 TLS를 끝냅니다.
AWS ALB데이터 흐름: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayEC2 instance target의 NodePort로 Istio ingress Envoy에 넘깁니다.
Istio ingress Envoy
k8s-ingress-gateway데이터 흐름: VirtualServiceChat APIk8s-api-chatChat API로 라우팅합니다.
Chat API
k8s-api-chat데이터 흐름: Taskiq 작업RabbitMQk8s-rabbitmqChat 작업을 RabbitMQ에 넣습니다.
RabbitMQ
k8s-rabbitmq데이터 흐름: consumechat-workerk8s-worker-ai · k8s-worker-ai-2chat-worker(Taskiq · asyncio)가 LangGraph로 의도를 분류한 뒤, 필요하면 vision, 선택된 도구, aggregator, 필요하면 요약을 거쳐 답합니다. 요청마다 필요한 분기만 실행합니다.
AI 풀
k8s-worker-ai · k8s-worker-ai-2데이터 흐름: HTTPSLLM APIscan · chat worker가 OpenAI · Google API를 호출합니다.
chat-worker
k8s-worker-ai · k8s-worker-ai-2데이터 흐름: XADD chat:eventsStreamsk8s-redis-streams토큰과 단계 이벤트를 Streams shard 4개에 기록합니다. 이후는 Scan과 같은 전달 경로입니다.
Streams
k8s-redis-streams데이터 흐름: XREADGROUPEvent Routerk8s-event-routerEvent Router가 consumer group으로 읽고, 처리한 뒤 XACK합니다. pending · reclaim으로 at-least-once 전달을 지킵니다.
Event Router
k8s-event-router데이터 흐름: PUBLISHPub/Subk8s-redis-pubsubshard Pub/Sub의 job 채널로 실시간 전달합니다.
Pub/Sub
k8s-redis-pubsub데이터 흐름: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway는 프로세스마다 공유 listener 하나로 구독해, 연결된 브라우저마다 나눠 보냅니다.
SSE Gateway
k8s-sse-gateway데이터 흐름: SSE 스트림브라우저같은 ALB · ingress 경로로 열린 연결입니다. at-least-once이며 중복은 멱등하게 처리합니다.
chat-worker
k8s-worker-ai · k8s-worker-ai-2데이터 흐름: checkpointCachek8s-redis-cacheLangGraph checkpoint를 Redis Cache에 둡니다.
Cache
k8s-redis-cache데이터 흐름: checkpoint 읽기checkpoint-syncerk8s-worker-ai · k8s-worker-ai-2checkpoint-syncer가 Redis의 checkpoint를 읽습니다.
checkpoint-syncer
k8s-worker-ai · k8s-worker-ai-2데이터 흐름: PostgreSQL 동기화PostgreSQLk8s-postgresqlAsyncPostgresSaver로 PostgreSQL에 비동기 저장합니다.
Streams
k8s-redis-streams데이터 흐름: chat-persistence grouppersistence consumerk8s-api-chatChat 노드의 persistence consumer가 done 이벤트를 consumer group으로 읽습니다.
persistence consumer
k8s-api-chat데이터 흐름: 메시지 저장PostgreSQLk8s-postgresql대화 메시지를 PostgreSQL에 저장합니다. checkpoint-syncer와는 다른 워크로드입니다.
진입 · 인증
요청이 클러스터에 들어와 Domain API에 닿기까지의 동기 경로입니다. 정책이 걸린 경로만 인증을 먼저 거치고, 노드 사이 Pod 통신은 Calico VXLAN입니다.
브라우저DNS 조회: DNS 조회Route 53
Route 53 레코드로 이름만 찾습니다. 요청이 DNS를 지나가지는 않습니다.
브라우저데이터 흐름: HTTPS 443AWS ALB
ALB가 TLS를 끝냅니다.
AWS ALB데이터 흐름: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayEC2 instance target의 NodePort로 Istio ingress Envoy에 넘깁니다.
Istio ingress Envoy
k8s-ingress-gateway데이터 흐름: ext-authz · gRPC 50051ext-authzk8s-api-authCUSTOM 정책이 걸린 경로만 Go ext-authz에 먼저 묻습니다(timeout 2초, failOpen false). 로그인 · health · docs 같은 경로는 제외됩니다.
ext-authz
k8s-api-auth데이터 흐름: blacklist 조회blacklistk8s-redis-authRedis blacklist로 토큰을 확인합니다.
Istio ingress Envoy
k8s-ingress-gateway데이터 흐름: VirtualServiceChat APIk8s-api-chatChat API로 라우팅합니다.
Chat API
k8s-api-chat데이터 흐름: gRPCimages APIk8s-api-imageREADME에 적힌 chat → images 동기 호출입니다.
auth API
k8s-api-auth데이터 흐름: gRPCusers APIk8s-api-usersREADME에 적힌 auth → users 동기 호출입니다.
storage 풀 · 비동기 저장
인증 blacklist와 캐릭터 소유권은 RabbitMQ를 거쳐 storage 풀의 worker가 저장합니다.
blacklist
k8s-redis-auth데이터 흐름: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2auth-relay(README의 auth-Bus)가 Redis outbox를 읽습니다.
auth-relay
k8s-worker-storage · k8s-worker-storage-2데이터 흐름: blacklist.eventsRabbitMQk8s-rabbitmqRabbitMQ로 다시 발행합니다. 실패하면 재시도하고 DLQ로 보냅니다.
RabbitMQ
k8s-rabbitmq데이터 흐름: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2auth-worker가 블랙리스트 이벤트를 받습니다.
auth-worker
k8s-worker-storage · k8s-worker-storage-2데이터 흐름: blacklist 저장blacklistk8s-redis-authRedis blacklist에 저장합니다.
RabbitMQ
k8s-rabbitmq데이터 흐름: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2users-worker가 캐릭터 소유권 작업을 모아 받습니다.
users-worker
k8s-worker-storage · k8s-worker-storage-2데이터 흐름: UPSERTPostgreSQLk8s-postgresqlPostgreSQL에 반영합니다.
구성 · 확장 · 관측
Platform Layer는 요청이 지나가는 단계가 아니라, 다른 레이어를 배포 · 구성 · 확장 · 관측합니다. 노드는 Terraform이 만든 EC2에 Ansible로 kubeadm · Calico를 올렸고, CI는 Terraform을 검증만 하며 apply는 자동으로 하지 않습니다.
GitHub Actions · Docker Hub구성 · 확장: 이미지 · manifest revisionArgo CD image updater
k8s-masterArgo CD가 App-of-Apps · Sync Wave로 클러스터 구성을 맞춥니다. control-plane 배치는 image updater만 확인했습니다.
ALB Controller · ExternalDNS
k8s-master구성 · 확장: Ingress → ALB · DNS 레코드AWS 관리형ALB Controller와 ExternalDNS가 AWS 쪽 리소스를 구성합니다. 요청이 지나가는 길이 아닙니다.
Istiod
k8s-master구성 · 확장: xDS 구성Istio ingress Envoyk8s-ingress-gatewayIstiod가 Gateway · VirtualService · EnvoyFilter 설정을 xDS로 ingress Envoy와 각 API의 Envoy sidecar에 내려줍니다.
KEDA
k8s-monitoring구성 · 확장: Pod 수AI 풀k8s-worker-ai · k8s-worker-ai-2KEDA는 worker Pod 수를 조절합니다. 노드 수는 바뀌지 않습니다.
KEDA
k8s-monitoring구성 · 확장: Pod 수storage 풀k8s-worker-storage · k8s-worker-storage-2storage 풀의 worker Pod 수도 같은 방식으로 조절합니다.
Fluent Bit관측: 로그Elasticsearch
k8s-loggingFluent Bit는 모든 노드의 DaemonSet이며, 로그를 Elasticsearch로 보냅니다.
AI 풀
k8s-worker-ai · k8s-worker-ai-2관측: LLM 실행 추적LangSmithLLM 호출 추적은 외부 SaaS인 LangSmith로 갑니다.
모든 연결을 같은 굵기로 보여 줍니다. 흐름을 고르면 그 경로만 번호와 함께 강조됩니다.
- 실선 · 요청 · 작업 · 이벤트 · 저장이 흐르는 방향
- 점선 · DNS 조회, 요청이 지나가지 않음
- 파선 · 구성 · 확장, 데이터 경로가 아님
- 긴 점선 · 로그 · 실행 추적
- 굵은 검은 선 · 고른 흐름, 번호는 순서
- 상자 · 물리 노드, 머리말에 호스트 이름
- 안쪽 칩 · 그 노드에서 도는 워크로드
- 점선 틀 · 두 노드 스케줄링 풀
- 점선 상자 · 클러스터 밖, 노드 수에 넣지 않음
- 주황 테두리 · 모델이 판단하는 곳
- Control plane노드 1
- Domain API노드 8
- AI 풀노드 2
- storage 풀노드 2
- Data노드 5
- Platform노드 6
README의 다섯 레이어(띠)와 물리 그룹(노드 머리말의 색)은 같은 24개 노드를 다르게 묶습니다. State KV는 Streams 노드에 함께 있어 따로 세지 않았고, Route 53 · ALB와 클러스터 밖 서비스는 노드에 넣지 않았습니다. 풀은 스케줄링 범위이며, 모든 Pod가 두 노드에 다 있다는 뜻이 아닙니다.
24노드
24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform
1Control plane
role: control-planekube-apiserver · scheduler · controller-manager · etcd와 플랫폼 컨트롤러.
- k8s-master
8Domain API
domain: <서비스>도메인마다 노드 하나. 내부 호출은 gRPC입니다.
- k8s-api-auth
- k8s-api-users
- k8s-api-scan
- k8s-api-character
- k8s-api-location
- k8s-api-image
- k8s-api-chat
- k8s-api-info
4Execution worker
두 노드로 된 스케줄링 풀 두 개입니다. KEDA는 Pod 수를 조절하고, 노드 수는 그대로입니다.
storage 풀
domain: worker-storage- k8s-worker-storage
- k8s-worker-storage-2
AI 풀
domain: worker-ai- k8s-worker-ai
- k8s-worker-ai-2
5Data
Redis는 용도별로 네 노드에 나눴습니다. PostgreSQL 저장소는 EBS CSI · gp3입니다.
- k8s-postgresql
- k8s-redis-auth
- k8s-redis-streams
- k8s-redis-cache
- k8s-redis-pubsub
6Platform
메시지, 관측, 진입, 실시간 전달을 각자의 노드에 두었습니다.
- k8s-rabbitmq
- k8s-monitoring
- k8s-logging
- k8s-ingress-gateway
- k8s-sse-gateway
- k8s-event-router
- 모든 노드
- Fluent Bit · DaemonSet
- Calico
당시 구성 모델 · 프로바이더별
서비스가 종료되어, 지금 고를 수 있는 모델이 아니라 저장소에 구성된 모델입니다. 역할마다 따로 적었으며, 실행을 확인한 목록은 아닙니다.
OpenAI
Chat 기본 provider
Chat
openai/gpt-5.2기본
기본 모델은 gpt-5.2이고, 요청에 모델을 지정하면 그 모델을 씁니다.
Scan
gpt-5.2기본gpt-5.2-progpt-5.1gpt-5gpt-5-progpt-5-mini
13개 모델 매핑에 없는 모델은 거부합니다.
이미지 매핑
gpt-image-1.5
Responses 조율 모델 gpt-5.2와 별개입니다. 이미지 생성은 기본 설정에서 꺼져 있습니다.
평가
gpt-4o-mini기본
대화 평가의 LLM grader이며, Chat 모델과 별개입니다.
Google
Chat에서 Google을 고를 때
Chat
google/gemini-3-pro-previewgoogle/gemini-3-flash-preview
Google을 고르면 gemini-3-flash-preview가 기본입니다.
Scan
gemini-3-pro-previewgemini-3-flash-previewgemini-2.5-progemini-2.5-flashgemini-2.5-flash-litegemini-2.0-flashgemini-2.0-flash-lite
이미지 매핑
gemini-3-pro-image-preview
출처backend main d8840c7공개 커밋 September 29, 2026 · 확인 October 8, 2026