- Move usage metrics aggregation to stream layer in edge openai handler - Refactor stream.go to relay usage metrics from node responses - Update grafana doc with new metric structure and dashboard notes - Remove completed G05 plan/code-review artifacts - Archive closed task artifacts
412 lines
20 KiB
Markdown
412 lines
20 KiB
Markdown
# OpenAI-compatible Usage – Grafana Query Guide
|
||
|
||
> **Purpose**: 이 문서는 운영자가 Prometheus metric을 Grafana 패널로 조회해 사용자별 OpenAI-compatible token 사용량, 사용 출처, cloud-equivalent cost, avoided-cost ROI 판단 기준을 볼 수 있도록 한다. Control Plane/Client dashboard, request-level ledger, live cloud pricing sync, billing/chargeback, 사용자별 제한 enforcement는 만들지 않는다.
|
||
|
||
---
|
||
|
||
## Metric 목록
|
||
|
||
### 1. `iop_openai_usage_tokens_total` (Counter)
|
||
|
||
Provider-reported OpenAI-compatible token usage by token type.
|
||
|
||
| Label | Value 예시 | 설명 |
|
||
|-------|-----------|------|
|
||
| `edge_id` | `edge-1` | Edge instance identity |
|
||
| `principal_ref` | `usr-abc123` | Principal foreign-key-like reference |
|
||
| `principal_alias` | `john@acme` | Human-readable alias |
|
||
| `token_ref` | `tok-xyz789` | Token identity (not a raw secret) |
|
||
| `model_group` | `gpt-4o` | Model group identifier |
|
||
| `endpoint` | `chat.completions`, `responses` | OpenAI-compatible route |
|
||
| `response_mode` | `passthrough`, `normalized` | Internal execution label; callers cannot set it via OpenAI metadata |
|
||
| `token_type` | `input`, `output`, `reasoning`, `cached_input` | Token type |
|
||
|
||
### 2. `iop_openai_requests_total` (Counter)
|
||
|
||
OpenAI-compatible requests processed by terminal status and usage source.
|
||
|
||
| Label | Value 예시 | 설명 |
|
||
|-------|-----------|------|
|
||
| `edge_id` | `edge-1` | Edge instance identity |
|
||
| `principal_ref` | `usr-abc123` | Principal reference |
|
||
| `principal_alias` | `john@acme` | Human-readable alias |
|
||
| `token_ref` | `tok-xyz789` | Token identity |
|
||
| `model_group` | `gpt-4o` | Model group identifier |
|
||
| `endpoint` | `chat.completions`, `responses` | OpenAI-compatible route |
|
||
| `response_mode` | `passthrough`, `normalized` | Internal execution label; callers cannot set it via OpenAI metadata |
|
||
| `status` | `success`, `error`, `cancel` | Terminal request status |
|
||
| `usage_source` | `provider_reported`, `unavailable` | Whether at least one token type was reported |
|
||
|
||
### 3. `iop_openai_reasoning_observed_total` (Counter)
|
||
|
||
Requests where reasoning text was observed but the provider did not report reasoning token usage.
|
||
Same labels as `iop_openai_requests_total` excluding `status` and `usage_source`: `edge_id`, `principal_ref`, `principal_alias`, `token_ref`, `model_group`, `endpoint`, `response_mode`.
|
||
|
||
### 4. `iop_openai_reasoning_chars_total` (Counter)
|
||
|
||
Observed reasoning text characters for requests without provider-reported reasoning tokens. The token estimate is emitted separately via `iop_openai_reasoning_estimated_tokens_total`; provider-reported `token_type="reasoning"` remains authoritative.
|
||
|
||
### 5. `iop_openai_reasoning_estimated_tokens_total` (Counter)
|
||
|
||
Estimated reasoning tokens for requests with observed reasoning text but without provider-reported reasoning token usage. Calculated as `ceil(chars / 4)` with `estimation_method="chars_div_4"`. This is an operator-grade observation estimate only, never billing-grade or chargeback-confirmed.
|
||
|
||
---
|
||
|
||
## Label Allowlist & Forbidden Labels
|
||
|
||
### 허용 label
|
||
|
||
```
|
||
edge_id, principal_ref, principal_alias, token_ref,
|
||
model_group, endpoint, response_mode, status,
|
||
token_type, usage_source, estimation_method
|
||
```
|
||
|
||
`estimation_method`는 `iop_openai_reasoning_estimated_tokens_total` 전용 보조 라벨이며, 그 외 counter에는 사용되지 않습니다.
|
||
|
||
### 금지 label
|
||
|
||
- `request_id`, `session_id` — request-level 상세는 후속 ledger/Loki 축에서 다룬다.
|
||
- Bearer token, provider API key, raw payload, raw prompt/response text — secret 누출 방지 (SDD S08).
|
||
- 그 외 임의 label — cardinality 폭발을 막는다.
|
||
|
||
---
|
||
|
||
## Principal / Token Attribution 전제
|
||
|
||
- `principal_ref`는 사용자/테넌트/외부 운영 시스템의 안정 참조값이다.
|
||
- `principal_alias`는 Grafana legend와 table에 보여줄 낮은 cardinality 별칭이다.
|
||
- `token_ref`는 raw bearer token이 아니라 앱/통합/용도별 token 참조값이다.
|
||
- 같은 `principal_ref` 아래 여러 `token_ref`를 둘 수 있다. 이 경우 `principal_ref` 기준 query는 사용자 합산, `token_ref` 기준 query는 앱/통합별 breakdown으로 본다.
|
||
- 운영 token 발급은 raw token을 tracked 파일에 남기지 않고 hash/reference만 기록하는 절차를 따른다.
|
||
|
||
관련 기준:
|
||
|
||
- `agent-contract/outer/openai-compatible-api.md`: OpenAI-compatible principal token auth 계약
|
||
- `agent-contract/inner/edge-config-runtime-refresh.md`: `openai.principal_tokens[]` config 계약
|
||
- `agent-ops/skills/project/openai-usage-token-issue/SKILL.md`: 운영 token 발급 절차
|
||
- `apps/edge/internal/openai/identity_metering_test.go`: 같은 principal의 여러 token resolution 테스트
|
||
- `packages/go/config/config_test.go`: 같은 principal의 여러 `principal_tokens[]` config load 테스트
|
||
|
||
---
|
||
|
||
## PromQL Examples
|
||
|
||
### 기본: 사용자별 사용량 (principal_alias 기준)
|
||
|
||
```promql
|
||
# 입력 토큰 합계
|
||
sum by (principal_alias) (iop_openai_usage_tokens_total{token_type="input"})
|
||
|
||
# 출력 토큰 합계
|
||
sum by (principal_alias) (iop_openai_usage_tokens_total{token_type="output"})
|
||
```
|
||
|
||
### principal_ref별 usage breakdown
|
||
|
||
```promql
|
||
# principal_ref, token_type별 aggregation
|
||
sum by (principal_ref, token_type) (iop_openai_usage_tokens_total)
|
||
```
|
||
|
||
### token_ref별 사용량
|
||
|
||
```promql
|
||
# token_ref별 input/output 합계
|
||
sum by (token_ref, token_type) (iop_openai_usage_tokens_total)
|
||
```
|
||
|
||
### 사용자 합산 + 앱/통합별 breakdown
|
||
|
||
```promql
|
||
# 같은 principal_ref의 전체 사용량
|
||
sum by (principal_ref, principal_alias, token_type) (
|
||
iop_openai_usage_tokens_total
|
||
)
|
||
|
||
# 같은 principal_ref 안에서 token_ref별 사용량
|
||
sum by (principal_ref, principal_alias, token_ref, token_type) (
|
||
iop_openai_usage_tokens_total
|
||
)
|
||
```
|
||
|
||
### model_group별 usage
|
||
|
||
```promql
|
||
# model_group, token_type별 aggregation
|
||
sum by (model_group, token_type) (iop_openai_usage_tokens_total)
|
||
```
|
||
|
||
### endpoint별 요청 수
|
||
|
||
```promql
|
||
# endpoint, status별 요청 수
|
||
sum by (endpoint, status) (iop_openai_requests_total)
|
||
```
|
||
|
||
### response_mode별 분석
|
||
|
||
`response_mode`는 handler 실행 경로에서 파생되는 내부 라벨이다. provider 라우트의 raw tunnel 패스스루는 `passthrough`, 정규화된 RunEvent 경로는 `normalized`로 기록된다. caller가 OpenAI metadata로 설정할 수 있는 값이 아니며 API selector가 아니다.
|
||
|
||
```promql
|
||
# response_mode별 성공 요청 수
|
||
sum by (response_mode, status) (iop_openai_requests_total{status="success"})
|
||
```
|
||
|
||
### usage origin breakdown
|
||
|
||
```promql
|
||
# "어디서 얼만큼 사용했는지"를 보는 table용 breakdown
|
||
sum by (principal_alias, token_ref, model_group, endpoint, response_mode, token_type) (
|
||
iop_openai_usage_tokens_total
|
||
)
|
||
```
|
||
|
||
### token_type별 사용량 전체
|
||
|
||
```promql
|
||
# 모든 token_type별 합계 (time range 그래프용)
|
||
sum by (token_type) (irate(iop_openai_usage_tokens_total[5m]))
|
||
```
|
||
|
||
### usage_source별 요청 coverage
|
||
|
||
```promql
|
||
# provider_reported vs unavailable 비율
|
||
sum by (usage_source) (iop_openai_requests_total)
|
||
```
|
||
|
||
### reasoning 보조 metric
|
||
|
||
provider가 reasoning token을 보고하지 않는 경우:
|
||
|
||
```promql
|
||
# reasoning text가 관찰된 요청 수 (provider token 미보고)
|
||
sum by (principal_alias) (iop_openai_reasoning_observed_total)
|
||
|
||
# reasoning text character 합계
|
||
sum by (principal_alias) (iop_openai_reasoning_chars_total)
|
||
|
||
# estimated reasoning tokens (provider가 token 수를 보고하지 않는 경우)
|
||
sum by (principal_alias, estimation_method) (iop_openai_reasoning_estimated_tokens_total)
|
||
```
|
||
|
||
> **주의**: `iop_openai_reasoning_observed_total` / `iop_openai_reasoning_chars_total` / `iop_openai_reasoning_estimated_tokens_total`는 provider-reported reasoning token이 있을 경우 emit되지 않는다. 즉, 이 metric들은 "reasoning text는 있으나 token count 보고를 안 하는 provider"만 커버한다. `iop_openai_reasoning_estimated_tokens_total`은 `estimation_method="chars_div_4"`로 ceil(chars/4) 추정을 제공하지만 billing-grade 정산값이 아니다.
|
||
|
||
---
|
||
|
||
## Dashboard Panel 후보
|
||
|
||
| 패널 | query | visualization |
|
||
|------|-------|---------------|
|
||
| 사용자별 token 사용량 (line) | `sum by (principal_alias, token_type) (irate(iop_openai_usage_tokens_total[5m]))` | Time series, legend=`{{principal_alias}} {{token_type}}` |
|
||
| 일별 usage origin (table) | `sum by (principal_alias, token_ref, model_group, endpoint, response_mode, token_type) (increase(iop_openai_usage_tokens_total[1d]))` | Table |
|
||
| model_group별 token 비율 (pie) | `sum by (model_group, token_type) (iop_openai_usage_tokens_total)` | Stat or bar chart |
|
||
| 요청 상태 분포 (table) | `sum by (endpoint, status, usage_source) (iop_openai_requests_total)` | Table |
|
||
| cloud-equivalent cost (stat/table) | token rollup query에 price scalar 또는 Grafana calculated field 적용 | Stat or Table |
|
||
| avoided-cost ROI summary (stat) | cloud-equivalent cost 합계, 필요 시 별도 infra cost field 차감 | Stat |
|
||
| reasoning 보조 지표 (singlestat) | `sum(iop_openai_reasoning_observed_total)` | Singlestat |
|
||
| estimated reasoning tokens (bar) | `sum by (estimation_method) (iop_openai_reasoning_estimated_tokens_total)` | Bar chart |
|
||
| estimated reasoning vs provider-reported (line) | `sum by (estimation_method) (iop_openai_reasoning_estimated_tokens_total)` vs `sum by (principal_alias) (iop_openai_usage_tokens_total{token_type="reasoning"})` | Time series |
|
||
|
||
> Grafana JSON dashboard import file은 본 scope에 포함되지 않는다. 위 PromQL을 바탕으로 패널을 수동 구성한다.
|
||
|
||
---
|
||
|
||
## daily / monthly Rollup
|
||
|
||
### 일일 토큰 합계
|
||
|
||
```promql
|
||
# 일일 token rollup (principal/token/model/endpoint/response_mode/token_type별)
|
||
sum by (principal_ref, principal_alias, token_ref, model_group, endpoint, response_mode, token_type) (
|
||
increase(iop_openai_usage_tokens_total[1d])
|
||
)
|
||
```
|
||
|
||
> Grafana dashboard에서 `by time` aggregation으로 대체 가능:
|
||
> ```promql
|
||
> # Grafana 범용 aggregation (PromQL 함수 아님)
|
||
> # time range를 1일로 설정 후 sum by (principal_alias, token_type)
|
||
> iop_openai_usage_tokens_total
|
||
> ```
|
||
|
||
### 월간 토큰 합계
|
||
|
||
```promql
|
||
# 최근 30일 token rollup. 달력 월은 Grafana time range를 월 단위로 잡고 $__range를 사용한다.
|
||
sum by (principal_ref, principal_alias, token_ref, model_group, endpoint, response_mode, token_type) (
|
||
increase(iop_openai_usage_tokens_total[30d])
|
||
)
|
||
```
|
||
|
||
> Grafana dashboard에서 범용 aggregation으로 대체 가능:
|
||
> ```promql
|
||
> # Grafana 범용 aggregation (PromQL 함수 아님)
|
||
> # time range를 30일로 설정 후 sum by (principal_alias, token_type)
|
||
> iop_openai_usage_tokens_total
|
||
> ```
|
||
|
||
### 일일/월간 rollup 활용 시나리오
|
||
|
||
- `principal_alias` 또는 `principal_ref`를 `by` clause에 추가해 사용자별 일일/월간 토큰 사용량을 산출한다.
|
||
- `token_ref`를 추가하면 같은 사용자 아래 앱/통합/용도별 사용량을 분해한다.
|
||
- `token_type`을 함께 group by하면 input/output/reasoning/cached_input을 구분한다.
|
||
- `model_group`, `endpoint`, `response_mode`를 추가하면 사용 위치와 응답 경로별 origin breakdown을 만든다.
|
||
|
||
---
|
||
|
||
## Cloud Price Baseline
|
||
|
||
가격은 런타임이 자동으로 가져오지 않는다. 운영자가 기준일과 기준 모델을 명시한 정적 baseline을 Grafana dashboard 변수, annotation, table panel, 또는 운영 문서에 둔다.
|
||
|
||
최소 필드:
|
||
|
||
| Field | 예시 | 설명 |
|
||
|-------|------|------|
|
||
| `cloud_provider` | `example-cloud` | 가격 기준 provider |
|
||
| `baseline_model` | `example-model` | 비교 기준 cloud model |
|
||
| `model_group` | `example-model` | IOP metric의 `model_group`과 매핑할 값 |
|
||
| `token_type` | `input`, `output`, `cached_input`, `reasoning` | 가격을 적용할 token type |
|
||
| `price_per_1m_tokens` | `1.00` | 1M tokens당 단가 |
|
||
| `currency` | `USD` | 통화 |
|
||
| `effective_date` | `2026-07-10` | 가격 기준일 |
|
||
| `source_note` | `operator baseline` | 운영자가 남기는 기준 설명 |
|
||
|
||
baseline 예시. 아래 숫자는 문서용 예시이며 최신 cloud 가격이 아니다.
|
||
|
||
| cloud_provider | baseline_model | model_group | token_type | price_per_1m_tokens | currency | effective_date |
|
||
|----------------|----------------|-------------|------------|----------------------|----------|----------------|
|
||
| example-cloud | example-model | example-model | input | 1.00 | USD | 2026-07-10 |
|
||
| example-cloud | example-model | example-model | output | 3.00 | USD | 2026-07-10 |
|
||
| example-cloud | example-model | example-model | cached_input | 0.50 | USD | 2026-07-10 |
|
||
|
||
`reasoning` token은 provider가 별도 단가를 제공하면 별도 baseline을 둔다. 별도 단가가 없으면 운영자가 `output`과 같은 단가로 볼지, report에서 `reasoning`을 제외할지 baseline에 명시한다.
|
||
|
||
> `iop_openai_reasoning_estimated_tokens_total`은 operator observation용 추정치이며, cloud-equivalent cost에 합산하거나 chargeback에 사용하지 않는다. billing-grade reasoning cost는 provider-reported `iop_openai_usage_tokens_total{token_type="reasoning"}`에 한한다.
|
||
|
||
---
|
||
|
||
## Cost Formula
|
||
|
||
기본 산식:
|
||
|
||
```text
|
||
cloud_equivalent_cost = (tokens / 1_000_000) * price_per_1m_tokens
|
||
daily_cloud_equivalent_cost = sum(cloud_equivalent_cost by day, principal/token/model/endpoint/token_type)
|
||
monthly_cloud_equivalent_cost = sum(cloud_equivalent_cost over selected month)
|
||
```
|
||
|
||
Prometheus metric 자체에는 price table이 없으므로 1차 표면에서는 다음 중 하나를 사용한다.
|
||
|
||
- Grafana table transformation으로 token rollup 결과에 static price column을 붙이고 calculated field를 만든다.
|
||
- model/token_type별 panel query에 운영자가 관리하는 scalar price를 곱한다.
|
||
- Prometheus recording rule을 운영자가 별도 관리한다. 이 repo는 recording rule 파일을 만들지 않는다.
|
||
|
||
PromQL scalar 예시:
|
||
|
||
```promql
|
||
# example-model input daily cloud-equivalent cost, USD
|
||
sum by (principal_alias, token_ref, model_group, endpoint) (
|
||
increase(iop_openai_usage_tokens_total{model_group="example-model", token_type="input"}[1d])
|
||
) / 1000000 * 1.00
|
||
|
||
# example-model output daily cloud-equivalent cost, USD
|
||
sum by (principal_alias, token_ref, model_group, endpoint) (
|
||
increase(iop_openai_usage_tokens_total{model_group="example-model", token_type="output"}[1d])
|
||
) / 1000000 * 3.00
|
||
|
||
# example-model cached input daily cloud-equivalent cost, USD
|
||
sum by (principal_alias, token_ref, model_group, endpoint) (
|
||
increase(iop_openai_usage_tokens_total{model_group="example-model", token_type="cached_input"}[1d])
|
||
) / 1000000 * 0.50
|
||
```
|
||
|
||
여러 token type을 합산할 때는 token type별 cost query를 Grafana transformation으로 더한다. 단일 query에서 서로 다른 가격을 자동 join하려면 별도 recording rule 또는 external price table이 필요하다.
|
||
|
||
---
|
||
|
||
## ROI / Avoided-Cost Summary
|
||
|
||
이 MVP의 ROI는 billing-grade 정산이 아니라 cloud-equivalent avoided cost다.
|
||
|
||
```text
|
||
cloud_equivalent_cost = cloud baseline으로 환산한 사용량 비용
|
||
avoided_cost = IOP/local/provider에서 처리한 사용량의 cloud_equivalent_cost
|
||
net_avoided_cost = cloud_equivalent_cost - separately_known_local_infra_cost
|
||
```
|
||
|
||
- local infra cost가 별도로 계상되지 않으면 `avoided_cost`만 표시한다.
|
||
- local infra cost를 운영자가 별도 산정해 Grafana에 넣을 수 있으면 `net_avoided_cost`를 보조 field로 둔다.
|
||
- 이 값은 실제 결제, chargeback, 조직별 비용 배부, full infra cost accounting 근거가 아니다.
|
||
- 최소 summary table column은 `date`, `principal_alias`, `token_ref`, `model_group`, `endpoint`, `tokens`, `currency`, `cloud_equivalent_cost`, `avoided_cost`다.
|
||
|
||
Grafana table 구성 예:
|
||
|
||
1. Query A: daily token rollup by `principal_alias`, `token_ref`, `model_group`, `endpoint`, `token_type`.
|
||
2. Transformation: baseline price table 또는 panel-level scalar를 token type별로 적용한다.
|
||
3. Calculated field: `tokens / 1000000 * price_per_1m_tokens`.
|
||
4. Group by: `date`, `principal_alias`, `token_ref`, `model_group`, `endpoint`.
|
||
5. Reduce: `cloud_equivalent_cost` 합계와 token 합계를 보여준다.
|
||
|
||
---
|
||
|
||
## Grafana Report 절차
|
||
|
||
1. Grafana time range를 `Today`, `Yesterday`, 최근 7일, 또는 이번 달로 설정한다.
|
||
2. `daily / monthly Rollup` query로 token usage table을 만든다.
|
||
3. `principal_ref`/`principal_alias` 기준 panel과 `token_ref` 기준 panel을 나란히 둔다.
|
||
4. `model_group`, `endpoint`, `response_mode`, `token_type` column을 유지해 usage origin을 확인한다.
|
||
5. 운영 price baseline의 `effective_date`, `baseline_model`, `currency`를 dashboard text 또는 table에 함께 표시한다.
|
||
6. token type별 cost formula를 적용해 cloud-equivalent cost를 계산한다.
|
||
7. daily/monthly `avoided_cost` summary stat을 추가한다.
|
||
8. `usage_source="unavailable"` 요청 비율과 reasoning 보조 metric을 함께 확인해 cost report coverage 위험을 판단한다.
|
||
|
||
---
|
||
|
||
## Limit Follow-up: 경계 명시
|
||
|
||
### 후속 Milestone으로 남기는 항목
|
||
|
||
- 사용자별 daily/monthly token **warn** 또는 **reject** enforcement는 이 Milestone의 범위가 아니며 후속 Milestone으로 Planned된다.
|
||
- 실제 결제, chargeback, 조직별 비용 배부, full infra cost accounting은 후속 범위다.
|
||
- live cloud pricing API 연동 또는 최신 가격 자동 동기화는 후속 범위다.
|
||
- request-level ledger / audit log는 Loki/queriable log축 후속 작업의 대상이다.
|
||
|
||
### 현재 문서가 제공하는 것
|
||
|
||
- `principal_ref`, `principal_alias`, `token_ref`, `model_group`, `endpoint`, `response_mode`, `token_type` 라벨 기반 daily/monthly rollup PromQL
|
||
- 같은 principal의 여러 token/app usage를 합산과 breakdown으로 함께 보는 기준
|
||
- 운영자가 관리하는 cloud price baseline 필드
|
||
- token type별 cloud-equivalent cost 산식과 query/report 예시
|
||
- avoided-cost 수준의 ROI summary 기준
|
||
- provider reasoning report 누락 시 `reasoning_observed_total` / `reasoning_chars_total`로 보조 확인, `reasoning_estimated_tokens_total`로 chars/4 token 추정치 제공 (billing-grade 아님)
|
||
|
||
이 rollup 기준은 후속 enforce Milestone에서 Prometheus query를 그대로 재사용할 수 있도록 설계되었다.
|
||
|
||
---
|
||
|
||
## Quick Reference: Label Values
|
||
|
||
| Label | 허용 값 |
|
||
|-------|---------|
|
||
| `endpoint` | `chat.completions`, `responses` |
|
||
| `status` | `success`, `error`, `cancel` |
|
||
| `usage_source` | `provider_reported`, `unavailable` |
|
||
| `token_type` | `input`, `output`, `reasoning`, `cached_input` |
|
||
| `response_mode` | `passthrough`, `normalized` |
|
||
| `estimation_method` | `chars_div_4` (특히 `iop_openai_reasoning_estimated_tokens_total` 전용) |
|
||
|
||
---
|
||
|
||
## Appendix: Grafana Scrape Target
|
||
|
||
Compose 관측 스택에서는 Prometheus가 내부 Docker DNS로 `control-plane:9093`을 scrape하고, Grafana datasource는 `http://prometheus:9090`을 사용한다. dev profile은 기존 native Edge endpoint를 바꾸지 않기 위해 `host.docker.internal:19101`도 scrape한다.
|
||
|
||
Host publish 기본 포트:
|
||
|
||
- local/test: Prometheus `19110`, Grafana `19120`, Control Plane metrics `19100`, Edge metrics `19092`
|
||
- dev: Prometheus `19111`, Grafana `19121`, Control Plane metrics `19103`, Edge metrics `19101`
|
||
- dev-corp compose: Prometheus `19112`, Grafana `19122`, Control Plane metrics `19104`, Edge metrics `19105`
|
||
|
||
이 관측 스택은 기존 테스트 사용자-facing endpoint를 변경하지 않는다. dev 기준 기존 UI/Control Plane/Edge OpenAI-compatible 접속점은 유지하며, Grafana/Prometheus/metrics 포트만 운영자용으로 추가한다. dev Grafana/Prometheus는 기본적으로 원격 runner 내부 또는 SSH 터널 접근 기준이다. dev-corp는 현재 접근 가능한 runner가 없을 때 문서 정의만 갱신하고 실제 compose 세팅은 별도 세션에서 수행한다.
|