폐쇄망 K8s에 VictoriaLogs 클러스터 구축하기: Helm으로 vlstorage·vlinsert·vlselect·vmauth 설치

VictoriaLogs 클러스터는 vlinsert(수집)·vlstorage(저장)·vlselect(쿼리) 와 진입점 vmauth 로 구성되며, 앞의 셋은 같은 바이너리의 역할 분리입니다. Helm 차트로 retention·PVC 크기·vlstorage replica·vmauth 네 가지만 정하면 대규모 로그 백엔드가 완성됩니다. 모든 적재·쿼리·vmui 접근은 vmauth(8427) 단일 진입점으로 통하며, 백엔드 포트는 외부에 직접 노출하지 않습니다. 이 글은 “OTel + VictoriaLogs 로그 스택” 시리즈 2편(백엔드편) 으로, 1편(개념편)이 “VictoriaLogs로 보낸다"고 전제했던 바로 그 백엔드를 실제로 세우는 글입니다. 백엔드를 먼저 세우고 수집기를 붙이는 순서이므로, 3편(OTel 설치편) 직전에 읽으면 좋습니다.

🧱 VictoriaLogs 클러스터는 무엇으로 구성되나 #

VictoriaLogs 클러스터는 3개 컴포넌트 + 프록시로 이뤄집니다. 핵심은 vlinsert·vlselect·vlstorage가 동일한 victoria-logs 바이너리이고, 시작 플래그(-storageNode 등)로 역할이 갈린다는 점입니다.

flowchart LR
    OTEL["OTel Gateway"] -->|"insert"| VMA["vmauth :8427"]
    VMA -->|"/insert/*"| VI["vlinsert"]
    VI --> VS["vlstorage<br/>StatefulSet + PVC"]
    GF["Grafana / vmui"] -->|"/select/*"| VMA
    VMA -->|"/select/*"| VSEL["vlselect"]
    VSEL --> VS
컴포넌트역할기본 포트배포 형태
vlinsert적재 요청을 받아 vlstorage들에 고르게 분산(샤딩)9481Deployment
vlstorage로그를 저장(PVC 보유)9491StatefulSet
vlselect쿼리를 모든 vlstorage에 fan-out 후 병합9471Deployment
vmauth적재→vlinsert, 쿼리→vlselect 라우팅·LB·인증8427Deployment

⚠️ 포트는 배포 모드에 따라 완전히 다릅니다. 공식·커뮤니티 예시 대부분은 single-node 기준이라 모든 기능이 포트 9428 하나에 통합돼 있습니다(적재·조회·vmui 전부 9428). 반면 클러스터 모드는 위 표처럼 컴포넌트별로 포트가 분리됩니다. 그래서 single-node 문서를 보고 클러스터에 9428로 적재를 시도하면 닿지 않습니다.

💡 적재는 vmauth(8427) 단일 진입점을 거치는 것이 표준입니다(인증·LB·라우팅). vmauth 없이 vlinsert직결(9481) 하는 것도 가능하지만, 그러면 인증·로드밸런싱을 직접 처리해야 합니다. 조회 역시 vmauth(8427) 경유가 표준이고 vlselect 직결은 9471입니다. 실제 포트·서비스명은 kubectl get svc -n <ns>로 최종 확인하세요(차트 nameOverride에 따라 이름이 달라집니다).

⚠️ vlinsert는 로그를 복제(replication)하지 않고 샤딩만 합니다. 저장 노드에 고르게 분산해 선형 확장은 쉽지만, 노드 장애 시 해당 샤드 데이터는 보호되지 않습니다. HA 복제가 필요하면 vlagent로 다중 클러스터에 replicate하는 별도 구성을 씁니다.


📦 폐쇄망 이미지 준비 #

필요한 이미지는 단 두 개victoria-logs(vlinsert/vlselect/vlstorage 공통 본체)와 vmauth입니다. 둘 다 Docker Hub에 있으니 사내 레지스트리로 미러한 뒤 values에서 덮어씁니다.

1docker pull docker.io/victoriametrics/victoria-logs:v1.5x.x
2docker pull docker.io/victoriametrics/vmauth:v1.1xx.x
3
4docker tag docker.io/victoriametrics/victoria-logs:v1.5x.x <사내레지스트리>/victoria-logs:v1.5x.x
5docker tag docker.io/victoriametrics/vmauth:v1.1xx.x        <사내레지스트리>/vmauth:v1.1xx.x
6
7docker push <사내레지스트리>/victoria-logs:v1.5x.x
8docker push <사내레지스트리>/vmauth:v1.1xx.x

⚠️ victoria-logsvmauth버전 라인이 다릅니다(victoria-logs는 v1.5x대, vmauth는 v1.1xx대). 차트가 요구하는 정확한 태그를 helm template ... | grep 'image:'로 추출해 누락·오타 없이 고정하세요. latest는 금지입니다. 차트 tgz도 helm pull 또는 GitHub release로 사내망에 반입합니다.


⚙️ values.yaml (클러스터, 대규모·보안 포함) #

대규모 기준 핵심 설정입니다. 차트는 oci://ghcr.io/victoriametrics/helm-charts/victoria-logs-cluster이며, 폐쇄망은 global.image.registry로 사내 레지스트리를 전역 지정합니다.

 1# === vlcluster-values.yaml ===
 2nameOverride: vlc            # 리소스 이름 63자 제한 회피 (공식 권장)
 3
 4# 이미지 전역 덮어쓰기 (폐쇄망)
 5global:
 6  image:
 7    registry: <사내레지스트리>
 8
 9vlstorage:
10  replicaCount: 3            # 대규모는 2~3+, 용량·IO 보고 증설
11  retentionPeriod: 30d       # 보존기간 (단위 h/d/w/y, 미지정 시 month, 최소 24h)
12  persistentVolume:
13    enabled: true
14    storageClassName: <사내-storageclass>   # 꼭 지정
15    size: 100Gi              # 산정은 아래 사이징 섹션 참고
16  resources:
17    requests: { cpu: "1", memory: 2Gi }
18    limits:   { cpu: "2", memory: 4Gi }
19  # 저장 노드는 노드/zone 분산 배치 권장
20  topologySpreadConstraints: []
21
22vlinsert:
23  replicaCount: 2
24  resources:
25    requests: { cpu: 200m, memory: 256Mi }
26    limits:   { cpu: "1", memory: 1Gi }
27
28vlselect:
29  replicaCount: 2
30  resources:
31    requests: { cpu: 200m, memory: 512Mi }
32    limits:   { cpu: "2", memory: 2Gi }
33
34vmauth:
35  enabled: true              # 진입점/LB/인증 (8427)
36  # 인증을 붙이려면 auth config를 Secret/extraArgs로 주입 (아래 보안 섹션)

💡 vmauth.enabled: true로 두면 차트가 vlinsert/vlselect 서비스를 backend discovery(discover_backend_ips)로 자동 구성합니다. vlstorage는 StatefulSet으로 떠서 파드당 PVC 1개({persistentVolume.name}-{podName})를 가집니다. HPA scaleDown은 데이터 유실 방지를 위해 기본 비활성입니다.


💾 vlstorage 사이징·retention은 어떻게 잡나 #

디스크 크기는 대략 “일일 압축 후 적재량 × retention일수 + 여유” 로 산정합니다. VictoriaLogs는 압축률이 높지만, 처음엔 보수적으로 잡고 vmui·메트릭으로 실제 증가율을 보며 조정하는 편이 안전합니다.

  • retention — 환경별 차등이 필요하면 중요 로그는 길게, 디버그는 짧게(고급은 multilevel 또는 별도 인스턴스). 기본은 단일 retentionPeriod.
  • PVC 확장 — 사후 확장 가능 여부는 StorageClass의 allowVolumeExpansion에 달려 있으니 미리 확인하세요.
  • 축소 불가 — StatefulSet PVC는 줄이기 어렵습니다.

💡 적재량을 모를 땐 작게 시작 → vmui에서 스트림별 볼륨 확인 → 증설이 정석입니다. 과대 산정보다 점진 증설이 PVC 특성에 맞습니다. 실제 네임스페이스·클러스터별 디스크 용량_size가 아니라 block_stats pipe로 산정합니다(저장이 폴더가 아니라 날짜 파티션 + 스트림 필드라 그렇습니다). 동작 확인된 쿼리와 “여러 클러스터에서 같은 이름 네임스페이스가 합쳐지는 함정"은 트러블슈팅편 — 로그 용량 산정을 참고하세요.


🔐 vmauth 인증·TLS #

외부(클러스터 간) 진입이라면 vmauth에 인증·TLS가 필수입니다. 내부 전용이라도 최소 인증을 권장합니다. 인증 토큰·비밀번호는 Secret으로 만들어 주입하고, 명령행 인자로 직접 넘기지 않습니다(프로세스 목록 노출 위험).

⚠️ vmauth url_map직접 커스텀한다면 두 함정을 주의하세요 — url_prefix 끝에 /insert·/select를 붙이면 경로가 중복되어 400이 나고, 포괄 규칙(/.*) 하나로 전부 vlinsert로 보내면 조회가 -select.disable에 걸립니다. 올바른 /insert/.*→vlinsert, /select/.*→vlselect 분리 설정은 트러블슈팅편 — vmauth 400 · select.disable을 참고하세요.

1kubectl create secret generic vmauth-auth \
2  --from-literal=token='<적재·쿼리용-토큰>' -n logging
  • TLS — 보통 vmauth에만 TLS를 적용하고 내부 컴포넌트는 평문으로 둡니다. vmauth의 http 리스너에 인증서 경로를 지정합니다.
  • 원칙 — 외부 노출은 vmauth만. vlinsert/vlselect/vlstorage는 외부에 직접 노출 금지(공식 보안 권장). 모든 외부 진입은 vmauth로 단일화해 인증·HTTPS를 적용합니다.

🚀 설치 #

1kubectl create namespace logging
2
3helm install vlc ./victoria-logs-cluster-<차트버전>.tgz \
4  -f vlcluster-values.yaml -n logging
5
6# 상태 확인
7kubectl -n logging get statefulset,deploy,svc,pvc
8kubectl -n logging get pods -o wide

vlstorage StatefulSet의 PVC가 Bound이고 파드가 Running인지 확인합니다. PVC가 Pending이면 대개 StorageClass 문제입니다.


🔎 vmui로 동작 확인 #

VictoriaLogs 내장 UI인 vmui로 Grafana 없이 즉시 확인할 수 있습니다.

1kubectl -n logging port-forward svc/vlc-victoria-logs-cluster-vmauth 8427
2# 브라우저: http://localhost:8427/select/vmui/

아직 수집기를 안 붙였으면 비어 있는 게 정상입니다. LogsQL 맛보기:

*
env:prod

⚠️ 실제 서비스명은 nameOverride에 따라 달라지므로 kubectl get svc -n logging으로 최종 확인하세요. 위 예시는 nameOverride: vlc 기준입니다.


🔗 수집기·Grafana 연결 지점 #

이 백엔드가 뜨면, 다음은 수집기(OTel)와 Grafana가 붙는 지점만 알면 됩니다. 모두 vmauth(8427) 단일 진입점을 씁니다.

연결 대상주소
OTel Gateway exporter logs_endpointhttp://vlc-victoria-logs-cluster-vmauth.logging.svc:8427/insert/opentelemetry/v1/logs
Grafana 데이터소스 URL (VictoriaLogs 플러그인)http://vlc-victoria-logs-cluster-vmauth.logging.svc:8427
vmuihttp://<vmauth>:8427/select/vmui/

수집기 설치는 OTel 설치편, Grafana 플러그인 연결은 VictoriaLogs 데이터소스 설치 글에서 이어집니다.


🧪 검증 / 트러블슈팅 #

1# 차트가 끌어오는 이미지가 사내 레지스트리로 바뀌었는지
2helm template x ./victoria-logs-cluster-<차트버전>.tgz -f vlcluster-values.yaml | grep 'image:' | sort -u
3
4# PVC 바인딩 문제 진단
5kubectl -n logging describe pvc
6
7# 저장 노드 로그
8kubectl -n logging logs sts/vlc-victoria-logs-cluster-vlstorage
증상원인해결
PVC PendingStorageClass 미지정·부재storageClassName 확인
이름 63자 초과 에러nameOverride 미설정nameOverride: vlc
ImagePullBackOff사내 레지스트리 미덮어씀global.image.registry 확인
vmui 접근 불가포트포워딩 대상 서비스명 오류kubectl get svc로 실제 이름 확인

📐 대규모 vs 소규모, 무엇이 다른가 #

규모에 따라 달라지는 점만 한곳에 모으면 다음과 같습니다. 이 글의 기본 전제는 대규모(클러스터 모드) 입니다.

구분대규모(클러스터, 기본)소규모/개인
차트victoria-logs-clustervictoria-logs-single
컴포넌트vlinsert/vlstorage/vlselect + vmauth단일 victoria-logs 1개
적재/조회 진입vmauth :8427victoria-logs :9428 직접
확장vlstorage replica 증설단일 노드, 커지면 cluster로 승격

💡 소규모는 victoria-logs-single 차트로 충분합니다. 단일 노드 인스턴스는 나중에 cluster의 vlstorage로 승격(마이그레이션)이 비교적 쉬우니, 작게 시작했다가 규모가 커지면 클러스터로 전환하면 됩니다.


❓ 자주 묻는 질문 #

Q. vlinsert/vlselect/vlstorage 이미지를 따로 받아야 하나요? 아닙니다. 전부 victoria-logs 한 이미지이고, 역할은 시작 플래그로 갈립니다. 받을 이미지는 victoria-logsvmauth 둘뿐입니다.

Q. 적재 주소가 뭔가요? vmauth 8427/insert/opentelemetry/v1/logs(OTLP) 입니다.

Q. 로그를 Grafana 없이 보고 싶어요. vmui(vmauth 8427/select/vmui/)로 바로 조회됩니다.

Q. 복제(replication)는 되나요? vlinsert는 복제하지 않고 샤딩만 합니다. HA 복제가 필요하면 vlagent로 다중 클러스터에 replicate하는 구성을 씁니다.

Q. retention을 환경별로 다르게 줄 수 있나요? 기본은 단일 retention입니다. 차등이 필요하면 multilevel 또는 별도 인스턴스(고급)로 분리합니다.

Q. PVC를 나중에 줄일 수 있나요? StatefulSet PVC는 축소가 어렵습니다. 점진 증설을 전제로 보수적으로 시작하세요.


🧭 시리즈: OTel + VictoriaLogs 로그 스택 #

OTel 트랙

Vector 트랙 (대안 수집기)

비교

대시보드 트랙

이 편의 한 줄 요약: “vlinsert·vlselect·vlstorage는 같은 이미지의 역할 분리이고, 진입은 vmauth 단일점이다.” 핵심 파라미터는 retentionPeriod·PVC size·vlstorage replicaCount·vmauth 넷이며, 백엔드 포트는 직접 노출하지 않고 PVC는 점진 증설을 전제로 잡습니다.


📚 참고 #