refactor: organize infra/ into compute/network/security/data/platform
This commit is contained in:
171
infra/platform/anomaly-detect.md
Normal file
171
infra/platform/anomaly-detect.md
Normal file
@@ -0,0 +1,171 @@
|
||||
---
|
||||
title: anomaly-detect (VictoriaLogs + ollama 기반 이상 트래픽 감지)
|
||||
updated: 2026-04-08 agentic 재설계
|
||||
tags: [security, crowdsec, victorialogs, ollama, gemma, anomaly]
|
||||
---
|
||||
|
||||
> 코드: `gitea.inouter.com/kaffa/anomaly-detect` (private)
|
||||
> 아키텍처: OpenRouter agentic (Grok-4-fast) + VictoriaLogs tool + CrowdSec LAPI tool
|
||||
|
||||
# anomaly-detect
|
||||
|
||||
## 아키텍처
|
||||
|
||||
OpenRouter `x-ai/grok-4-fast`에 tool 2개(logsql_query, ban_ips)만 노출하는 agentic 구조. fallback 모델 `qwen/qwen3-235b-a22b-2507`.
|
||||
|
||||
설계 반복 및 모델 벤치마크 이력: [[2026-04-08-anomaly-detect-iterations|history]]
|
||||
|
||||
### 새 아키텍처
|
||||
|
||||
```
|
||||
systemd timer (5분)
|
||||
↓
|
||||
analyzer.py (Python oneshot)
|
||||
├─ OpenRouter → x-ai/grok-4-fast (tools=[logsql_query, ban_ips])
|
||||
├─ agent loop (max 10턴)
|
||||
│ ├─ tool: logsql_query(query, start, limit) — VictoriaLogs 자유 조회
|
||||
│ │ ※ 응답에서 사설망/Tailscale/RFC5737 IP 자동 제거 (서버측 guardrail)
|
||||
│ └─ tool: ban_ips(ips, reason, scenario) — CrowdSec LAPI batch POST
|
||||
│ ※ dedup 24h, MAX_BAN_PER_CYCLE cap, 사설망 거부
|
||||
├─ DRY_RUN=1 (기본): ban_ips가 "would ban" 로그만 찍고 실제 POST 안 함
|
||||
└─ dedup.json 갱신
|
||||
```
|
||||
|
||||
### 환경변수
|
||||
|
||||
| 변수 | 기본값 | 비고 |
|
||||
|------|--------|------|
|
||||
| `OPENROUTER_API_KEY` | (from `/etc/anomaly-detect/openrouter.env`) | Vault `secret/ai/openrouter` |
|
||||
| `OR_MODEL` | `x-ai/grok-4-fast` | 주 모델 |
|
||||
| `OR_FALLBACK_MODEL` | `qwen/qwen3-235b-a22b-2507` | OR 장애 시 재시도 |
|
||||
| `WINDOW_MIN` | 5 | 조사 윈도우 |
|
||||
| `MAX_TURNS` | 10 | agent loop 상한 |
|
||||
| `MAX_BAN_PER_CYCLE` | 2000 | 한 사이클 ban 상한 (대규모 DDoS 대비) |
|
||||
| `LAPI_BAN_CHUNK` | 500 | LAPI POST를 500건씩 쪼개 발송 (부분 실패 허용) |
|
||||
| `BAN_DURATION` | 4h | |
|
||||
| `DRY_RUN` | **1** | ⚠ 초기 안전장치 |
|
||||
|
||||
### 서버측 guardrail (중요)
|
||||
|
||||
LLM은 지시만 받고 강제할 수 없다. 따라서 `logsql_query`와 `ban_ips` 두 tool 모두 **파이썬 코드 레벨에서** 다음을 enforce:
|
||||
- `is_skippable_ip()`: `ipaddress.is_private` + Tailscale 100.64/10 + RFC5737 TEST-NET-2/3 포함
|
||||
- Python 3.9의 `ipaddress.ip_address('203.0.113.42').is_private == True` — 문서 IP도 자동 차단됨 (2026-04-08 벤치마크에서 확인)
|
||||
|
||||
LLM 프롬프트가 무시되어도 실수로 사설망이 ban되지 않음.
|
||||
|
||||
### Vault 위치
|
||||
|
||||
- OpenRouter key: `secret/ai/openrouter` (`API_KEY` 키)
|
||||
- 컨테이너 배포본: `/etc/anomaly-detect/openrouter.env` (mode 600, systemd `EnvironmentFile=`)
|
||||
|
||||
|
||||
### 운영 중 주의사항
|
||||
|
||||
- **injected 로그 잔재**: E2E 테스트 중 주입한 270 rows가 vlogs retention 기간 동안 남음. `sim_e2e` 마커 필드로 식별 가능. 다음 cycle에서 다시 탐지될 수 있으나 dedup 24h으로 재ban 차단됨.
|
||||
- **재테스트 시**: 테스트 후 반드시 `cscli decisions delete -s anomaly-detect/<scenario>` + `/var/lib/anomaly-detect/dedup.json` 업데이트 (해당 IP 추가하거나 리셋)
|
||||
|
||||
### 비용 모니터링
|
||||
|
||||
매 사이클 journalctl에 한 줄 요약 출력 (`48eb489` 이후):
|
||||
|
||||
```
|
||||
cycle usage: turns=5 prompt=9142 completion=2670 total=11812 cost=$0.001866
|
||||
```
|
||||
|
||||
집계 명령:
|
||||
|
||||
```bash
|
||||
# 오늘 누적
|
||||
ssh incus-hp2 "incus exec anomaly-detect -- bash -c '
|
||||
journalctl -u anomaly-detect.service --since today --no-pager |
|
||||
grep -oE \"cost=\\\$[0-9.]+\" |
|
||||
awk -F\\\$ \"{sum+=\\\$2} END {printf \\\"today: \\\$%.6f (%d cycles)\\n\\\", sum, NR}\"
|
||||
'"
|
||||
|
||||
# 사이클별 상세
|
||||
ssh incus-hp2 "incus exec anomaly-detect -- journalctl -u anomaly-detect.service --since today --no-pager | grep 'cycle usage'"
|
||||
```
|
||||
|
||||
**OpenRouter `/activity` API의 지연** (~2-3주)으로 실시간 비용 조회는 여기(journalctl) 경로를 써야 한다. dashboard는 https://openrouter.ai/activity 에서 UI 확인 가능 (더 빠름). management(provisioning) 키는 Vault `secret/ai/openrouter` → `PROVISIONING_KEY` 에 저장됨.
|
||||
|
||||
**월 비용 예상**: 평시 사이클당 ~$0.001-0.002, 5분 주기 × 288/일 × 30일 = **~$10-15/월**. DDoS 발생 시 사이클당 $0.01 수준 (massive_ddos 시나리오 기준)까지 튈 수 있으나 일시적.
|
||||
|
||||
[[crowdsec-safeline#~~ddos-detect (AI 행위 분석)~~ — 폐기 (2026-04-08)|폐기된 ddos-detect]] 후속. [[victorialogs|VictoriaLogs]]에 적재된 서울+오사카 APISIX access log를 5분마다 분석하여 봇/공격성 IP를 [[crowdsec-safeline|CrowdSec]]에 자동 ban으로 등록한다.
|
||||
|
||||
## 위치 / 사양
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| 호스트 | incus-hp2 |
|
||||
| 컨테이너 | `anomaly-detect` (default 프로젝트, Debian 13 trixie) |
|
||||
| IP | 10.100.2.164 |
|
||||
| 사양 | 1 vCPU, 512MB RAM, 5GB |
|
||||
| 설치 경로 | `/opt/anomaly-detect/{venv,analyzer.py}`, `/etc/anomaly-detect/lapi.yaml`, `/etc/anomaly-detect/openrouter.env`, `/var/lib/anomaly-detect/dedup.json` |
|
||||
| systemd | `anomaly-detect.service` (oneshot) + `anomaly-detect.timer` (`OnCalendar=*:0/5`, `Persistent=true`, `RandomizedDelaySec=20`) |
|
||||
|
||||
## 데이터 흐름
|
||||
|
||||
```
|
||||
[5분 주기 systemd timer]
|
||||
↓
|
||||
analyzer.py
|
||||
├─ 1) https://vl.inouter.com — LogsQL: program:apisix log_type:access 지난 5분
|
||||
├─ 2) per-IP 통계 게이트 (count/4xx/5xx/499/distinct paths)
|
||||
├─ 3) 후보 N개 (default max 5)
|
||||
├─ 4) 각 후보 → http://100.87.221.126:11434/api/generate (kaffa-macmini ollama)
|
||||
│ 모델: gemma4:e4b (Q4_K_M, 8.0B), format=json
|
||||
├─ 5) verdict=yes → CrowdSec LAPI alert POST
|
||||
│ http://10.253.100.240:8080/v1/alerts
|
||||
│ profiles.yaml의 default_ip_remediation이 자동 ban 생성
|
||||
└─ 6) dedup.json에 처리 IP + 타임스탬프 기록 (24h 내 재처리 안 함)
|
||||
```
|
||||
|
||||
## CrowdSec LAPI 등록
|
||||
|
||||
`anomaly-detect`라는 watcher machine을 jp1 crowdsec에 등록하고, credentials를 컨테이너 안 `/etc/anomaly-detect/lapi.yaml`에 저장:
|
||||
|
||||
```yaml
|
||||
url: http://10.253.100.240:8080
|
||||
login: anomaly-detect
|
||||
password: <vault: secret/apps/anomaly-detect>
|
||||
```
|
||||
|
||||
> [!warning] cscli machines add 함정
|
||||
> `cscli machines add NAME --auto`는 default로 `/etc/crowdsec/local_api_credentials.yaml`을 덮어씀 — 이건 jp1 crowdsec **daemon 자체의 LAPI 클라이언트 설정**이라 덮어쓰면 daemon이 새 password로 LAPI 인증을 시도하면서 동기화가 깨짐. 반드시 `--file <별도 경로>` 옵션을 줘야 한다. 만약 실수로 덮어썼다면 `cscli machines add <default-machine-name> --auto --force --file /etc/crowdsec/local_api_credentials.yaml`로 default machine 새 credentials 발급 후 `systemctl reload crowdsec`로 복구.
|
||||
|
||||
|
||||
## 운영 명령
|
||||
|
||||
```bash
|
||||
# 컨테이너 진입
|
||||
ssh incus-hp2 'incus exec anomaly-detect -- bash'
|
||||
|
||||
# 수동 1회 실행
|
||||
incus exec anomaly-detect -- /opt/anomaly-detect/venv/bin/python /opt/anomaly-detect/analyzer.py
|
||||
|
||||
# 상태
|
||||
incus exec anomaly-detect -- systemctl status anomaly-detect.timer
|
||||
incus exec anomaly-detect -- journalctl -u anomaly-detect.service --since "30 minutes ago"
|
||||
|
||||
# dedup 초기화 (모든 IP 재분석 허용)
|
||||
incus exec anomaly-detect -- sh -c 'echo "{}" > /var/lib/anomaly-detect/dedup.json'
|
||||
|
||||
# 게이트/모델/주기 변경 → /etc/systemd/system/anomaly-detect.service의 Environment=
|
||||
```
|
||||
|
||||
## 검증 (최초 배포)
|
||||
|
||||
- `cscli machines list` → `anomaly-detect` 등록 확인
|
||||
- `curl https://vl.inouter.com/select/logsql/query?query=program:apisix\&limit=1` 200 OK (컨테이너 내부)
|
||||
- `curl http://100.87.221.126:11434/api/tags` → `gemma4:e4b` 노출
|
||||
- `curl http://10.253.100.240:8080/v1/decisions` → 403 (인증 필요, 네트워크 OK)
|
||||
- 더미 IP `198.51.100.99`로 alert POST → 201 + decision 등록 → cleanup 확인 (smoke test)
|
||||
|
||||
|
||||
## 향후 작업
|
||||
|
||||
- [ ] **[Medium]** Discord webhook 알림 추가 (`secret/apps/discord` Vault에서 가져오기) + systemd `OnFailure=` drop-in
|
||||
- [ ] **[Low]** CrowdSec alert `origin`을 `"crowdsec"` → `"anomaly-detect"`로 태깅
|
||||
|
||||
|
||||
전임자 (`ddos-detect`, 1/2차 구현) 폐기 이력: [[2026-04-08-anomaly-detect-iterations|history]]
|
||||
100
infra/platform/brokkr.md
Normal file
100
infra/platform/brokkr.md
Normal file
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: Brokkr — 홈페이지 제작 에이전트
|
||||
updated: 2026-04-01
|
||||
tags: [infra, agent, incus, claude-code]
|
||||
---
|
||||
|
||||
## 개요
|
||||
|
||||
Brokkr는 홈페이지 제작 전담 에이전트. 북유럽 신화의 드워프 대장장이(토르의 묠니르 제작자)에서 이름을 따옴.
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| 위치 | incus-kr1, default 프로젝트 |
|
||||
| OS | Debian 13 (trixie) |
|
||||
| IP | 10.100.3.54 |
|
||||
| 접속 | `ssh root@10.100.3.54` (incus-kr1 경유) |
|
||||
| 역할 | 홈페이지/웹사이트 제작 에이전트 |
|
||||
|
||||
## 설치된 도구
|
||||
|
||||
| 도구 | 버전 |
|
||||
|------|------|
|
||||
| Claude Code | v2.1.87 |
|
||||
| Node.js | 22.22.2 |
|
||||
| bun | 1.3.11 |
|
||||
| git | 2.47.3 |
|
||||
| jq | 1.7.1 |
|
||||
| uv | 최신 |
|
||||
| tmux | 3.5a |
|
||||
| Python | 3.13.5 |
|
||||
| gcloud SDK | 563.0.0 |
|
||||
| socat | 1.8.0.3 |
|
||||
|
||||
## PATH 설정
|
||||
|
||||
`/root/.bashrc`에 추가됨:
|
||||
```
|
||||
export PATH=/root/.bun/bin:/opt/google-cloud-sdk/bin:/root/.local/bin:$PATH
|
||||
```
|
||||
bun은 `/usr/local/bin/bun`에도 심볼릭 링크.
|
||||
|
||||
## 설정
|
||||
|
||||
- SSH: root 키 인증 (kaffa@KaFFa-Mac-mini.lan)
|
||||
- tmux: dotfiles 기반 Dracula 테마, Debian 서버 환경 최적화 (`~/.tmux.conf`)
|
||||
- CLAUDE.md: 역할, 디자인 워크플로우, Figma/Stitch 사용법, 에셋 가이드 포함
|
||||
|
||||
## 실행 방법
|
||||
|
||||
```bash
|
||||
# tmux 세션으로 실행
|
||||
tmux new -d -s brokkr 'export PATH=/root/.bun/bin:/opt/google-cloud-sdk/bin:/root/.local/bin:$PATH && claude --channels plugin:discord@claude-plugins-official'
|
||||
|
||||
# 신뢰 확인 프롬프트 통과
|
||||
tmux send-keys -t brokkr Enter
|
||||
|
||||
# 상태 확인
|
||||
tmux capture-pane -t brokkr -p
|
||||
```
|
||||
|
||||
## MCP 서버
|
||||
|
||||
| MCP | 상태 | 용도 |
|
||||
|-----|------|------|
|
||||
| plugin:figma:figma | ✓ | Figma 디자인 읽기/쓰기 (OAuth, credentials.json에 토큰 저장) |
|
||||
| plugin:context7:context7 | ✓ | 라이브러리 문서 조회 |
|
||||
| plugin:playwright:playwright | ✓ | 브라우저 자동화 |
|
||||
| outline | ✓ | Outline Wiki 문서 CRUD (API 키: Vault `secret/apps/outline`, 키명 brokkr-api-key) |
|
||||
| stitch | ✓ | Google Stitch AI 디자인 (gcloud 인증 필요) |
|
||||
| claude.ai Google Calendar | ✓ | 캘린더 |
|
||||
| claude.ai Gmail | ✓ | 이메일 |
|
||||
| claude.ai Cloudflare | ✓ | Cloudflare Workers/R2 |
|
||||
|
||||
## Discord 연결
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| 봇 ID | 1488674138359857152 |
|
||||
| 봇 토큰 | Vault `secret/messaging/discord-brokkr` |
|
||||
| 채널 1 | 1488669324393578506 (brokkr 전용) |
|
||||
| 채널 2 | 1488679091514380450 |
|
||||
| 권한 | Send Messages, Read Message History, View Channels, Add Reactions |
|
||||
|
||||
## 담당 작업
|
||||
|
||||
- Ironclad 홈페이지 제작 (ironclad.it.com)
|
||||
- 기획서: https://outline.inouter.com/doc/ironclad-AlZo9my3KN
|
||||
- 기술 스택: Astro + Google Stitch + Tailwind CSS
|
||||
- 배포: cf-multisite (Gitea → R2 → Cloudflare Workers)
|
||||
|
||||
## 주의사항
|
||||
|
||||
- Figma OAuth 토큰은 `/root/.claude/.credentials.json`에 저장됨. 로컬 Mac keychain에서 복사한 토큰.
|
||||
- gcloud 인증은 로컬에서 복사한 application_default_credentials.json 사용
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [[infra-hosts]] — 인프라 호스트 전체
|
||||
- [[outline]] — Outline Wiki (기획서 위치)
|
||||
- [[heimdall]] — 헤임달 에이전트 (인프라 관리)
|
||||
147
infra/platform/helm-charts.md
Normal file
147
infra/platform/helm-charts.md
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: Helm 차트 관리 체계
|
||||
updated: 2026-04-13
|
||||
tags: [infra, k3s, helm, argocd, gitops]
|
||||
---
|
||||
|
||||
## 개요
|
||||
|
||||
K3s 클러스터의 모든 서비스를 Helm으로 관리. 자체 차트는 Gitea에 호스팅하고 ArgoCD로 GitOps 배포.
|
||||
|
||||
## 차트 저장소
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| Git 레포 | `gitea.inouter.com/kaffa/helm-charts` (private) |
|
||||
| Helm 레지스트리 | `gitea.inouter.com/api/packages/kaffa/helm` |
|
||||
| ArgoCD 레포 시크릿 | `repo-helm-charts` (argocd 네임스페이스) |
|
||||
|
||||
### BunnyCDN 캐시 바이패스
|
||||
|
||||
`iron-git` Pull Zone (ID 5584382)에 Edge Rule 적용:
|
||||
- 패턴: `*/api/packages/*`
|
||||
- ActionType: 3 (OverrideCacheTime), 값: 0
|
||||
- 차트 업로드 후 index.yaml 캐시 문제 방지
|
||||
|
||||
## 자체 차트 구조
|
||||
|
||||
```
|
||||
helm-charts/
|
||||
├── charts/
|
||||
│ ├── app/ # 범용 차트 (v0.4.0) — 단순 서비스용
|
||||
│ ├── kroki/ # 전용 차트 — Kroki + Mermaid
|
||||
│ ├── searxng/ # 전용 차트 — SearXNG + UA 패치 + TLS proxy CA
|
||||
│ ├── outline/ # 전용 차트 — Outline Wiki + Redis
|
||||
│ └── openmemory/ # 전용 차트 — MCP + UI + Qdrant
|
||||
└── values/ # app 차트용 서비스별 values
|
||||
├── juiceshop.yaml
|
||||
├── cfb-manager.yaml
|
||||
├── bunnycdn-mcp.yaml
|
||||
├── smtp-relay.yaml
|
||||
├── namecheap-api.yaml
|
||||
├── vultr-api.yaml
|
||||
├── pgcat.yaml # sidecar(monitor) 포함
|
||||
├── proxysql.yaml # Galera 설정 포함
|
||||
├── nas-proxy.yaml # external service (Synology NAS)
|
||||
└── vault-mcp.yaml # external service (Vault) + extraIngressRoutes
|
||||
```
|
||||
|
||||
### app 차트 기능 (v0.4.0)
|
||||
|
||||
- Deployment + Service + IngressRoute 기본 구성
|
||||
- `sidecars` — 사이드카 컨테이너 지원
|
||||
- `configMaps` — multiline ConfigMap 생성
|
||||
- `secrets` — Secret 생성
|
||||
- `external` — selector 없는 Service + EndpointSlice (외부 서비스 프록시)
|
||||
- `extraIngressRoutes` — 복수 도메인 IngressRoute
|
||||
- `probes` — liveness/readiness probe
|
||||
|
||||
## 전체 Helm 릴리스 목록
|
||||
|
||||
### 공식/외부 차트 (20개)
|
||||
|
||||
| 릴리스 | 네임스페이스 | 차트 |
|
||||
|--------|-------------|------|
|
||||
| apisix | apisix | apisix |
|
||||
| apisix-ingress-controller | apisix | apisix-ingress-controller |
|
||||
| argocd | argocd | argo-cd |
|
||||
| cert-manager | cert-manager | cert-manager |
|
||||
| external-secrets | external-secrets | external-secrets |
|
||||
| gitea | gitea | gitea |
|
||||
| longhorn | longhorn-system | longhorn |
|
||||
| metallb | metallb-system | metallb |
|
||||
| n8n | n8n | n8n |
|
||||
| nfs-provisioner | nfs-provisioner | nfs-subdir-external-provisioner |
|
||||
| nocodb | tools | zekker6/nocodb |
|
||||
| portainer | portainer | portainer |
|
||||
| reflector | kube-system | reflector |
|
||||
| safeline | safeline | safeline |
|
||||
| sftpgo | sftpgo | sftpgo |
|
||||
| sshpiper | sshpiper | sshpiper |
|
||||
| synology-iscsi | democratic-csi | democratic-csi |
|
||||
| teleport-cluster | teleport | teleport-cluster |
|
||||
| traefik | kube-system | traefik |
|
||||
| vector | logging | vector |
|
||||
| vlogs | logging | victoria-logs-single |
|
||||
| vm-stack | monitoring | victoria-metrics-k8s-stack |
|
||||
|
||||
### 자체 app 차트 (10개, ArgoCD 관리)
|
||||
|
||||
| 릴리스 | 네임스페이스 | 비고 |
|
||||
|--------|-------------|------|
|
||||
| juiceshop | juiceshop | |
|
||||
| cfb-manager | tools | SSH key 마운트 |
|
||||
| bunnycdn-mcp | mcp | IngressRoute: bunny.inouter.com |
|
||||
| smtp-relay | mail | Mailgun relay |
|
||||
| namecheap-api | api | |
|
||||
| vultr-api | api | |
|
||||
| pgcat | db | monitor sidecar 포함 |
|
||||
| proxysql | db | Galera hostgroup 설정 |
|
||||
| nas-proxy | tools | external → 192.168.9.100:5000 |
|
||||
| vault-mcp | tools | external → 10.253.101.58, hcv.inouter.com + vault-mcp.inouter.com |
|
||||
|
||||
### 전용 차트 (4개, ArgoCD 관리)
|
||||
|
||||
| 릴리스 | 네임스페이스 | 구성 |
|
||||
|--------|-------------|------|
|
||||
| kroki | kroki | kroki + mermaid sidecar |
|
||||
| searxng | searxng | UA 패치, TLS proxy CA, Google proxy |
|
||||
| outline | outline | outline + redis + PVC + IngressRoute |
|
||||
| openmemory | openmemory | MCP + UI + Qdrant + PVC 2개 |
|
||||
|
||||
### Operator 관리 (ArgoCD/Helm 외)
|
||||
|
||||
| 서비스 | 네임스페이스 | 관리 방식 |
|
||||
|--------|-------------|-----------|
|
||||
| rabbitmq-cluster-operator | rabbitmq-system | 직접 매니페스트 |
|
||||
| rabbitmq-server | mq | RabbitmqCluster CRD → Operator |
|
||||
|
||||
## ArgoCD 앱 목록
|
||||
|
||||
14개 Application, 모두 `automated + prune + selfHeal`:
|
||||
|
||||
```
|
||||
juiceshop, cfb-manager, bunnycdn-mcp, smtp-relay, namecheap-api, vultr-api,
|
||||
pgcat, proxysql, nas-proxy, vault-mcp, kroki, searxng, outline, openmemory
|
||||
```
|
||||
|
||||
### 주의사항
|
||||
|
||||
- **EndpointSlice는 ArgoCD 제외 대상** — `discovery.k8s.io` 그룹이 argocd-cm에서 제외됨. external service의 EndpointSlice는 수동 관리 필요
|
||||
- ArgoCD 앱 소스는 Gitea `helm-charts` 레포의 `charts/` 경로 참조
|
||||
|
||||
## 배포 워크플로우
|
||||
|
||||
```
|
||||
1. charts/ 또는 values/ 수정
|
||||
2. helm template 로 렌더링 확인
|
||||
3. git push → Gitea helm-charts
|
||||
4. ArgoCD 자동 sync (또는 hard refresh)
|
||||
5. 동작 확인
|
||||
```
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [[external-secrets]] — ESO + Vault 시크릿 동기화
|
||||
- [[k3s-ingress-architecture]] — Traefik/APISIX 인그레스 구조
|
||||
- [[cert-manager]] — TLS 인증서
|
||||
17
infra/platform/infra-forge.md
Normal file
17
infra/platform/infra-forge.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Forge 인프라 에이전트
|
||||
updated: 2026-03-12
|
||||
tags: [infra, agent, forge]
|
||||
---
|
||||
|
||||
## 지식 베이스
|
||||
|
||||
infra.yaml 지식 베이스 + enrichment(IP→네트워크/인스턴스 레이블) + LLM(gemini-2.5-flash)으로 종합 보고
|
||||
|
||||
## 메시지 타입
|
||||
|
||||
메시지: INFRA_REPORT(전체보고), INFRA_QUERY(특정질문)
|
||||
|
||||
## MCP 구조
|
||||
|
||||
구조는 server.py(초기화), config.py(설정), haproxy_client.py(Runtime API), ssh_ops.py(SSH), db.py(SQLite), tools/(domains, servers, health, monitoring, configuration, certificates)로 구성되어 있다. → [[infra-hosts]], [[apisix]]
|
||||
34
infra/platform/infra-tofu.md
Normal file
34
infra/platform/infra-tofu.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: 인프라 프로비저닝 (OpenTofu)
|
||||
updated: 2026-03-12
|
||||
---
|
||||
|
||||
## OpenTofu
|
||||
|
||||
OpenTofu v1.11.5 installed at /usr/local/bin/tofu
|
||||
|
||||
## Tofu API
|
||||
|
||||
Tofu API (infra-tool 컨테이너, incus-jp1): 포트 8080 (uvicorn --port 8080). 파일 /opt/infra-tool/tofu_router.py. 엔드포인트: GET /tofu/plan, GET /tofu/state, GET /tofu/output, POST /tofu/server(provider/region/plan/label), DELETE /tofu/server/{name}, GET /tofu/plans/{provider}. 접근: ssh kaffa@100.109.123.1 → incus exec infra-tool -- bash. TF 템플릿 경로: /opt/infra/templates/{linode,vultr,alicloud,zenlayer}.tf.tpl. 참고: [[infra-forge|Forge]] consumer.py는 아직 tofu API를 사용하지 않고 Linode/Vultr API를 직접 호출하는 구조임.
|
||||
|
||||
## Zenlayer BM 프로비저닝
|
||||
|
||||
Zenlayer BM 프로비저닝: 직접 API → OpenTofu 전환 완료 (2026-03-04)
|
||||
|
||||
## Zenlayer OS 이미지
|
||||
|
||||
Zenlayer BM OS 이미지 매핑: zl-debian12 → 'Debian 12.x 64bit' (catalog: debian), zl-ubuntu2204 → 'Ubuntu 22.04 64bit' (catalog: ubuntu), zl-centos7 → 'CentOS 7.4 64bit' (catalog: centos)
|
||||
|
||||
## 통일 워크플로
|
||||
|
||||
전 프로바이더(Linode/Vultr/Alicloud/Zenlayer) 통일된 TF 워크플로로 동작
|
||||
|
||||
## 트래픽 모니터링 TODO
|
||||
|
||||
TODO: 트래픽 전송량 모니터링 + 자동 차단 서비스 구현 필요
|
||||
- Linode: Cloud Firewall API로 outbound DROP 적용
|
||||
- Vultr: Firewall API로 deny all 적용
|
||||
- Alibaba: ModifyInstanceNetworkSpec API로 InternetMaxBandwidthOut=0 설정
|
||||
- 흐름: 주기적 전송량 모니터링 → 임계치 도달 → 방화벽/대역폭 차단 → 고객 Telegram 알림 → 고객 동의 시 해제
|
||||
- 3개 프로바이더 모두 서버 중지 없이 네트워크만 차단 가능
|
||||
- 별도 서비스 또는 기존 consumer-service에 모니터링 컨슈머 추가 방식 검토
|
||||
59
infra/platform/kaniko.md
Normal file
59
infra/platform/kaniko.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Kaniko - K8s 네이티브 컨테이너 이미지 빌드
|
||||
updated: 2026-04-12
|
||||
tags:
|
||||
- k8s
|
||||
- image-build
|
||||
- kaniko
|
||||
---
|
||||
|
||||
## 개요
|
||||
|
||||
Kaniko는 Google에서 만든 Kubernetes 네이티브 컨테이너 이미지 빌드 도구. Docker 데몬 없이 컨테이너 내부에서 Dockerfile을 빌드하고 레지스트리에 푸시할 수 있다.
|
||||
|
||||
- 프로젝트: [googlecontainertools/kaniko](https://github.com/GoogleContainerTools/kaniko)
|
||||
- 이미지: `gcr.io/kaniko-project/executor`
|
||||
|
||||
## 도입 배경
|
||||
|
||||
- K3s 클러스터에서 컨테이너 이미지를 빌드하기 위해 호스트(incus-kr1)에 Docker CE를 설치해 사용했으나, Kaniko 발견 후 Docker CE 제거 (2026-04-12)
|
||||
- Docker 데몬 불필요 → 호스트에 Docker 설치할 필요 없음
|
||||
- K8s Job/Pod으로 빌드 실행 가능
|
||||
|
||||
## 사용 방법
|
||||
|
||||
K8s Job으로 실행하는 기본 예시:
|
||||
|
||||
```yaml
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: kaniko-build
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: kaniko
|
||||
image: gcr.io/kaniko-project/executor:latest
|
||||
args:
|
||||
- "--dockerfile=Dockerfile"
|
||||
- "--context=git://github.com/user/repo.git"
|
||||
- "--destination=registry.example.com/image:tag"
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
## 컨텍스트 소스
|
||||
|
||||
- Git 저장소: `git://`
|
||||
- S3/GCS 버킷
|
||||
- 로컬 디렉토리 (PVC 마운트)
|
||||
- tar 파일
|
||||
|
||||
## 레지스트리 인증
|
||||
|
||||
- K8s Secret을 `/kaniko/.docker/config.json`에 마운트
|
||||
- 또는 `--registry-mirror`, `--insecure-registry` 플래그 사용
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [[infra-hosts]] - K3s 클러스터 구성
|
||||
133
infra/platform/outline.md
Normal file
133
infra/platform/outline.md
Normal file
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: Outline Wiki
|
||||
updated: 2026-04-08
|
||||
tags: [k3s, wiki, outline]
|
||||
---
|
||||
|
||||
## 개요
|
||||
|
||||
Outline은 팀 위키/문서 관리 플랫폼. K3s 클러스터에 배포.
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| URL | https://outline.inouter.com |
|
||||
| 네임스페이스 | outline |
|
||||
| 이미지 | `outlinewiki/outline:0.82.0` |
|
||||
| 인증 | Gitea OAuth2 (OIDC) |
|
||||
| 기본 언어 | 한국어 |
|
||||
|
||||
## 구성 요소
|
||||
|
||||
| 컴포넌트 | 설정 |
|
||||
|-----------|------|
|
||||
| DB | Patroni HA via OpenWrt HAProxy (`192.168.9.1:5432`), DB명: outline, 유저: outline |
|
||||
| Redis | outline-redis (outline 네임스페이스 내 전용) |
|
||||
| 파일 저장소 | 로컬 (Longhorn PVC 5Gi, `/var/lib/outline/data`) |
|
||||
| TLS (Traefik) | wildcard-inouter-tls (*.inouter.com) |
|
||||
| TLS (CDN) | Let's Encrypt via BunnyCDN |
|
||||
| CDN | BunnyCDN iron-kr 존 (ID 5555227, 쿠키 허용) |
|
||||
| DNS | outline.inouter.com CNAME → iron-kr.b-cdn.net (Cloudflare, proxied OFF) |
|
||||
| Ingress | Traefik IngressRoute (CRD) |
|
||||
|
||||
## 인증 (Gitea OAuth2)
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| OIDC Provider | Gitea (gitea.inouter.com) |
|
||||
| Client ID | cb804835-416c-4730-86b4-26d2c129b164 |
|
||||
| Redirect URI | https://outline.inouter.com/auth/oidc.callback |
|
||||
| OIDC Endpoints | authorize, access_token, userinfo (Gitea 표준) |
|
||||
| Client Secret | Vault `secret/apps/outline` 참조 |
|
||||
|
||||
## 시크릿
|
||||
|
||||
Kubernetes Secret: `outline-secrets` (outline 네임스페이스)
|
||||
- SECRET_KEY, UTILS_SECRET, DATABASE_URL, REDIS_URL
|
||||
- OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC 엔드포인트들
|
||||
|
||||
## pgcat 연동
|
||||
|
||||
현재 pgcat 미사용 (직접 PostgreSQL 접속). 필요 시 pgcat pool 추가 가능.
|
||||
|
||||
## MCP 연동
|
||||
|
||||
Outline MCP 서버 도입 시 헤임달이 직접 문서 CRUD 가능.
|
||||
- 참고: https://github.com/Vortiago/mcp-outline
|
||||
- heimdall `~/.claude.json` `/root` 프로젝트 mcpServers에 `outline` 항목 추가 (stdio, `uvx mcp-outline`, `OUTLINE_API_KEY`는 Vault `secret/apps/outline` brokkr-api-key, `OUTLINE_API_URL=https://outline.inouter.com`)
|
||||
- 새 컬렉션 `agent-qna` (id `c3ab34ab-fae4-4642-8f4e-12728e293e1b`) — 에이전트 간 장문 Q&A 교환 공간 (kappa↔heimdall이 tmux로 짧게 질문 → 답변은 여기에 작성)
|
||||
|
||||
DB endpoint는 OpenWrt HAProxy(`192.168.9.1:5432`) 경유. 과거 Patroni failover 사고 이력: [[2026-04-08-patroni-failover-incident|history]]
|
||||
|
||||
## Discord 통지 파이프라인
|
||||
|
||||
`agent-qna` 컬렉션에 새 문서가 만들어지면 heimdall Discord 채널(#heimdall, id `1488119168145555486`)에 자동 알림이 뜬다. 다른 컬렉션은 무시한다.
|
||||
|
||||
```
|
||||
Outline (documents.create webhook)
|
||||
→ n8n webhook (https://n8n.inouter.com/webhook/outline-to-discord)
|
||||
→ Code 노드 (collectionId 필터 + Discord embed 빌드)
|
||||
→ HTTP Request 노드 (Discord Bot API: POST /channels/{id}/messages)
|
||||
```
|
||||
|
||||
### 구성 요소 위치
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|-----|
|
||||
| n8n workflow id | `8P714i5oBs9HkZPK` |
|
||||
| n8n workflow 이름 | `outline-to-discord (heimdall)` |
|
||||
| n8n webhook path | `/webhook/outline-to-discord` (POST, responseMode=onReceived) |
|
||||
| n8n 노드 구성 | Webhook → Filter+Format(Code) → Discord POST(HTTP) |
|
||||
| Outline webhook id | `ede9327f-b09e-4f7e-ab56-c507d3d1b3a6` (`documents.create` 이벤트) |
|
||||
| Outline collection 필터 | `c3ab34ab-fae4-4642-8f4e-12728e293e1b` (agent-qna) — Code 노드 안에 하드코딩 |
|
||||
| Discord channel | guild `1469999069190557799` 의 `#heimdall` 채널 (id `1488119168145555486`) |
|
||||
| Discord bot | username `Heimdall` (id `1487694864232611922`) |
|
||||
|
||||
### 시크릿
|
||||
|
||||
| 비밀 | Vault 경로 |
|
||||
|------|-----------|
|
||||
| Discord bot token | `secret/apps/discord` → `bot_token` (현재는 n8n Code 노드에 하드코딩되어 있음 — Credentials로 분리하는 게 더 깔끔, 후속 작업) |
|
||||
| Discord channel/guild ID | `secret/apps/discord` → `heimdall_channel_id`, `heimdall_guild_id` |
|
||||
| n8n API key | `secret/apps/n8n` → `api_key` (label: `heimdall-automation`) |
|
||||
| n8n owner login | `secret/apps/n8n` → `email`(`kappa@inouter.com`), `password` |
|
||||
| Outline API token | `secret/apps/outline` → `brokkr-api-key` |
|
||||
|
||||
### 메시지 포맷 (Discord embed)
|
||||
|
||||
- title: `📝 <doc title>`
|
||||
- url: `https://outline.inouter.com<payload.model.url>`
|
||||
- description: 본문 앞 200자 (개행 → 공백)
|
||||
- author.name: `outline / agent-qna · <createdBy.name>`
|
||||
- color: `0x00bcd4` (cyan)
|
||||
- timestamp: `payload.model.createdAt`
|
||||
|
||||
### 트러블슈팅
|
||||
|
||||
증상별 점검 순서:
|
||||
|
||||
1. **알림이 아예 안 옴**
|
||||
- Outline UI 또는 API로 webhook subscription 활성 확인
|
||||
```bash
|
||||
curl -sS -X POST https://outline.inouter.com/api/webhookSubscriptions.list \
|
||||
-H "Authorization: Bearer $OL_TOKEN" -d '{}' | jq .
|
||||
```
|
||||
- n8n에서 workflow active 여부 확인 (`/api/v1/workflows/8P714i5oBs9HkZPK`)
|
||||
- n8n executions에 webhook 도달했는지 확인 (`/api/v1/executions?workflowId=8P714i5oBs9HkZPK&limit=10`)
|
||||
2. **n8n에 도달하나 Discord POST가 안 일어남**
|
||||
- 거의 항상 collectionId 필터 미스매치. Filter+Format Code 노드의 `out items: 0` 이면 정상 (필터된 것)
|
||||
- 필터를 통과해야 하는데 0 items면 payload.event 또는 payload.model.collectionId 구조 확인
|
||||
3. **n8n DB connection timeout**
|
||||
- n8n pod 재시작: `kubectl -n n8n delete pod -l app.kubernetes.io/name=n8n`
|
||||
- pgcat → 192.168.9.1:5432 (Patroni leader) 경로 확인
|
||||
4. **Discord 401/403**
|
||||
- bot token 재발급 필요 (`secret/apps/discord` 갱신, n8n Code 노드의 하드코딩도 함께 갱신)
|
||||
- bot이 채널에 access 권한 있는지: `GET /channels/{channel_id}` 200이면 OK
|
||||
5. **Outline → n8n 호출이 BunnyCDN 508**
|
||||
- 일시적. 재시도하면 풀린다. BunnyCDN edge의 `cdn-loopcount` 룰 (자세한 원인 불명, retry로 회피)
|
||||
|
||||
### 후속 작업 (선택)
|
||||
|
||||
- [ ] Discord bot token을 n8n Credentials로 분리 (현재 Code 노드에 하드코딩)
|
||||
- [ ] Outline signing secret 지원되면 HMAC 서명 검증 추가 (현재 미적용 — 같은 인프라 내부 호출이라 위험 낮음)
|
||||
- [ ] `documents.update` 이벤트도 추가 (현재 create만)
|
||||
- [ ] 다른 컬렉션 (예: incident postmortem)도 동일 패턴으로 통지 추가
|
||||
187
infra/platform/victorialogs.md
Normal file
187
infra/platform/victorialogs.md
Normal file
@@ -0,0 +1,187 @@
|
||||
---
|
||||
title: VictoriaLogs (K3s 로그 저장)
|
||||
updated: 2026-04-08 Grafana 통합
|
||||
tags: [k3s, logging, vector, observability, grafana]
|
||||
---
|
||||
|
||||
# VictoriaLogs
|
||||
|
||||
K3s 클러스터의 raw 로그 저장소. 메트릭은 [[victoriametrics-stack|VictoriaMetrics]], 로그는 VictoriaLogs로 분리. 같은 VM 팀 제품이라 운영 패턴 일치.
|
||||
|
||||
## 접속
|
||||
|
||||
| 항목 | 값 |
|
||||
|------|------|
|
||||
| Web UI | https://vl.inouter.com/select/vmui/ |
|
||||
| HTTP API | https://vl.inouter.com/ |
|
||||
| 클러스터 내부 | http://vlogs-victoria-logs-single-server.logging.svc.cluster.local:9428 |
|
||||
| 노출 방식 | LAN 직접 (Cloudflare DNS → k3s.inouter.com → MetalLB 192.168.9.53 → Traefik IngressRoute), BunnyCDN 우회 |
|
||||
| TLS | wildcard-inouter-tls (reflector로 logging ns에 자동 복제) |
|
||||
| 인증 | 없음 (LAN/Tailscale 안에서만 접근 가능) |
|
||||
|
||||
## 설치
|
||||
|
||||
```bash
|
||||
helm repo add vm https://victoriametrics.github.io/helm-charts/
|
||||
helm install vlogs vm/victoria-logs-single -n logging -f vlogs-values.yaml
|
||||
```
|
||||
|
||||
values 핵심:
|
||||
|
||||
```yaml
|
||||
server:
|
||||
retentionPeriod: 14d
|
||||
persistentVolume:
|
||||
enabled: true
|
||||
storageClassName: longhorn
|
||||
size: 50Gi
|
||||
resources:
|
||||
requests: { cpu: 100m, memory: 256Mi }
|
||||
limits: { cpu: 1000m, memory: 1Gi }
|
||||
```
|
||||
|
||||
- 단일 노드 (`victoria-logs-single`), 14일 보존, longhorn 50GiB PVC
|
||||
- 네임스페이스: `logging` (Vector와 같은 곳)
|
||||
|
||||
## Traefik IngressRoute
|
||||
|
||||
`logging` ns:
|
||||
|
||||
```yaml
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: vlogs
|
||||
namespace: logging
|
||||
spec:
|
||||
entryPoints: [websecure]
|
||||
routes:
|
||||
- match: Host(`vl.inouter.com`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: vlogs-victoria-logs-single-server
|
||||
port: 9428
|
||||
tls:
|
||||
secretName: wildcard-inouter-tls
|
||||
```
|
||||
|
||||
## 데이터 파이프라인
|
||||
|
||||
### APISIX 로그 (현재 가동 중)
|
||||
|
||||
```
|
||||
APISIX (apisix ns, 2 replica) stdout (nginx access log 형식)
|
||||
→ Vector daemonset (logging ns, 3 노드)
|
||||
- source: apisix_logs (kubernetes_logs, label=app.kubernetes.io/name=apisix)
|
||||
- transform: parse_apisix (정규식 파싱 → method/path/status/request_time/host/UA 등 구조화)
|
||||
- sink: vlogs (elasticsearch bulk API)
|
||||
→ VictoriaLogs (/insert/elasticsearch/_bulk)
|
||||
```
|
||||
|
||||
Vector helm values는 [[vector|vector]] 문서 또는 `helm get values vector -n logging` 참조.
|
||||
|
||||
### 다른 잠재 source
|
||||
|
||||
- Traefik 로그는 별도 sink로 [[crowdsec-safeline|CrowdSec]]에 전송 (vector의 다른 transform/sink). VictoriaLogs로는 안 보내고 있음. 필요하면 sink inputs에 `parse_traefik` 추가하면 됨.
|
||||
|
||||
## Grafana 통합
|
||||
|
||||
vm-stack의 Grafana(`monitoring/vm-stack-grafana`)에 등록되어 있음. Explore에서 data source를 `VictoriaLogs`로 선택하면 LogsQL 쿼리 가능.
|
||||
|
||||
### 등록 방법
|
||||
|
||||
두 단계로 구성:
|
||||
|
||||
1. **플러그인 설치** — vm-stack helm values의 `grafana.plugins`에 `victoriametrics-logs-datasource` 추가하고 `helm upgrade vm-stack`. Grafana 시작 시 자동 다운로드/설치 (현재 v0.26.3).
|
||||
|
||||
2. **datasource 등록** — `grafana.additionalDataSources`는 vm-stack chart 구조상 sub-chart로 전달이 안 되므로 무시됨. 대신 **sidecar ConfigMap 패턴** 사용:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: vlogs-grafana-datasource
|
||||
namespace: monitoring
|
||||
labels:
|
||||
grafana_datasource: "1" # ← grafana-sc-datasources sidecar가 자동 발견
|
||||
data:
|
||||
vlogs.yaml: |
|
||||
apiVersion: 1
|
||||
datasources:
|
||||
- name: VictoriaLogs
|
||||
type: victoriametrics-logs-datasource
|
||||
access: proxy
|
||||
url: http://vlogs-victoria-logs-single-server.logging.svc.cluster.local:9428
|
||||
isDefault: false
|
||||
editable: true
|
||||
```
|
||||
|
||||
`kubectl apply -f` 한 번이면 sidecar가 즉시 picks up하고 grafana가 hot reload (`Writing /etc/grafana/provisioning/datasources/vlogs.yaml`).
|
||||
|
||||
### 주의
|
||||
|
||||
- Grafana PVC가 ReadWriteOnce이므로 helm upgrade 시 새 pod이 다른 노드에 스케줄되면 Multi-Attach error → 기존 pod 수동 삭제 필요. (또는 Grafana Deployment의 strategy를 Recreate로 변경)
|
||||
- helm values의 `grafana.additionalDataSources`는 무시되지만 plugin 설치는 작동하므로, plugin 라인은 helm values에 두는 게 맞음.
|
||||
|
||||
## LogsQL 쿼리 예시
|
||||
|
||||
```logsql
|
||||
# 모든 APISIX 로그
|
||||
program:apisix
|
||||
|
||||
# 5xx 에러만
|
||||
program:apisix status:>=500
|
||||
|
||||
# 특정 path
|
||||
program:apisix path:/apisix/admin/routes
|
||||
|
||||
# 느린 요청 (1초 이상)
|
||||
program:apisix request_time:>1.0
|
||||
|
||||
# 특정 클라이언트 외부 IP (real_ip 적용 후 진짜 IP)
|
||||
program:apisix remote_addr:211.211.28.97
|
||||
|
||||
# 특정 호스트
|
||||
program:apisix host:juiceshop.keepanker.cv
|
||||
|
||||
# 특정 호스트의 4xx/5xx
|
||||
program:apisix host:juiceshop.keepanker.cv status:>=400
|
||||
|
||||
# 특정 노드 pod
|
||||
program:apisix _stream:{kubernetes.pod_name="apisix-f5764d796-kdj2x"}
|
||||
```
|
||||
|
||||
> [!info] 진짜 IP 추적
|
||||
> 2026-04-08 [[apisix#real_ip 설정 (2026-04-08 patch 반영)|APISIX real_ip patch]] 이후 `remote_addr`에 BunnyCDN edge가 전달한 진짜 외부 IP가 찍힘. `xff`/`xrip` 필드로 X-Forwarded-For/X-Real-IP 헤더 원본도 보존. 그 이전 로그는 K3s pod CIDR(10.42.x.x)만 찍혀 있음.
|
||||
|
||||
> [!warning] parse_apisix 정규식과 APISIX log format은 짝
|
||||
> APISIX의 `access_log_format`을 바꾸면 vector helm values의 `parse_apisix` 정규식도 같이 업데이트해야 함. 안 그러면 매치 실패해서 `log_type=raw`로 떨어지고 구조화 필드(method/status/path 등) 추출이 안 됨.
|
||||
|
||||
UI에서 직접 쿼리하거나 HTTP API:
|
||||
|
||||
```bash
|
||||
curl -s "https://vl.inouter.com/select/logsql/query?query=program:apisix+status:>=500&limit=20"
|
||||
```
|
||||
|
||||
## 운영 명령
|
||||
|
||||
```bash
|
||||
# 메트릭 (ingest 통계)
|
||||
curl -s https://vl.inouter.com/metrics | grep vl_rows_ingested_total
|
||||
|
||||
# 디스크 사용량
|
||||
kubectl exec -n logging vlogs-victoria-logs-single-server-0 -- du -sh /storage
|
||||
|
||||
# Vector 상태
|
||||
kubectl logs -n logging -l app.kubernetes.io/name=vector --tail=50
|
||||
|
||||
# Vector configmap 직접 보기
|
||||
kubectl get cm vector -n logging -o jsonpath='{.data.vector\.yaml}'
|
||||
```
|
||||
|
||||
## 향후 작업
|
||||
|
||||
- [x] Grafana data source 추가 (2026-04-08 완료, 위 "Grafana 통합" 섹션 참조)
|
||||
- [ ] CrowdSec와 통합 (APISIX 로그 → CrowdSec 시나리오)
|
||||
- [ ] AI 분석 컴포넌트 (CronJob 또는 streaming, 새 공격 패턴 자동 차단 룰 생성)
|
||||
- [ ] Traefik 로그도 VL로 동시 sink (현재는 CrowdSec only)
|
||||
Reference in New Issue
Block a user