feat: date range picker, split network into Ingress/Istio, fix NodeTable undefined instance
CI/CD / build-and-push (push) Successful in 1m29s
Details
CI/CD / build-and-push (push) Successful in 1m29s
Details
This commit is contained in:
parent
7a0b1841f9
commit
82635e0335
|
|
@ -35,8 +35,10 @@ config:
|
|||
QUERY_MEMORY: '(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100'
|
||||
QUERY_DISK: 'sum by (mountpoint,fstype)((1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|nfs",mountpoint!~"/boot.*"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay|nfs",mountpoint!~"/boot.*"}) * 100)'
|
||||
QUERY_NAS: '((node_filesystem_size_bytes{fstype=~"nfs", node=~".*(bastion).*"} - node_filesystem_free_bytes{fstype=~"nfs", node=~".*(bastion).*"}) / node_filesystem_size_bytes{fstype=~"nfs", node=~".*(bastion).*"}) * 100'
|
||||
QUERY_NET_RX: 'sum(rate(container_network_receive_bytes_total{namespace="ingress-nginx", pod=~"ingress-nginx-controller-.*"}[5m]))'
|
||||
QUERY_NET_TX: 'sum(rate(container_network_transmit_bytes_total{namespace="ingress-nginx", pod=~"ingress-nginx-controller-.*"}[5m]))'
|
||||
QUERY_INGRESS_RX: 'sum(rate(container_network_receive_bytes_total{namespace="ingress-nginx", pod=~"ingress-nginx-controller-.*"}[5m]))'
|
||||
QUERY_INGRESS_TX: 'sum(rate(container_network_transmit_bytes_total{namespace="ingress-nginx", pod=~"ingress-nginx-controller-.*"}[5m]))'
|
||||
QUERY_ISTIO_RX: 'sum(rate(istio_request_bytes_sum{reporter="destination"}[5m]))'
|
||||
QUERY_ISTIO_TX: 'sum(rate(istio_response_bytes_sum{reporter="destination"}[5m]))'
|
||||
|
||||
resources:
|
||||
requests:
|
||||
|
|
|
|||
2
plan.md
2
plan.md
|
|
@ -1776,7 +1776,7 @@ export default function Home() {
|
|||
|
||||
---
|
||||
|
||||
## STEP 11. 빌드 및 배포
|
||||
## STEP 11. 빌드 및 배포 ✅
|
||||
|
||||
### 11-1. 로컬 개발
|
||||
|
||||
|
|
|
|||
24
record.md
24
record.md
|
|
@ -1,3 +1,27 @@
|
|||
# 구현 기록 (plan.md 대비 변경사항)
|
||||
|
||||
## 변경 이력
|
||||
|
||||
### 2026-03-16
|
||||
|
||||
1. **Dockerfile 수정**: `COPY --from=builder /app/public ./public`에서 public 디렉토리가 존재하지 않아 빌드 실패. builder 단계에 `RUN mkdir -p public` 추가로 해결.
|
||||
|
||||
2. **next.config.js 수정**: `serverExternalPackages`는 Next.js 15+ 옵션. Next.js 14에서는 `experimental.serverComponentsExternalPackages`로 변경.
|
||||
|
||||
3. **ArgoCD 연동 방식 변경**: argocd CLI가 bastion에 미설치되어 있어, kubectl로 직접 Secret(repo 인증) + Application 리소스를 생성하는 방식으로 대체.
|
||||
|
||||
4. **API Route params 수정**: Next.js 14 App Router에서 동적 route의 `params`를 `Promise<{ type: string }>`으로 처리 (async params pattern).
|
||||
|
||||
5. **CI Harbor 로그인 실패 수정**: 비밀번호 `Ijinc123!@#$`의 특수문자(`!`, `$`)가 큰따옴표 안에서 shell에 의해 해석되는 문제. `echo "${{ env.REGISTRY_PASSWORD }}"` → `echo '${{ secrets.REGISTRY_PASSWORD }}'` (작은따옴표 + secrets 직접 참조)로 변경.
|
||||
|
||||
6. **CI env 블록 구조 변경**: workflow 레벨 `env`에서 secrets를 매핑하던 방식을 제거하고, 각 step에서 `secrets.XXX`를 직접 참조하도록 변경.
|
||||
|
||||
7. **SSR 클라이언트 에러 수정**: `echarts-for-react`, `html2canvas`, `jspdf`가 SSR 비호환 라이브러리라 클라이언트 에러 발생. `dynamic(() => import(...), { ssr: false })`로 변경하고, `html2canvas`/`jspdf`는 함수 내부에서 동적 import하도록 수정.
|
||||
|
||||
8. **Helm chart 버전 전략 변경**: plan.md에서는 고정 버전 `0.1.0`이었으나, ArgoCD가 동일 버전에서 변경을 감지하지 못하는 문제 발생. semver pre-release(`0.1.0-sha`)도 정식 버전보다 낮게 취급되어 `>0.0.0` range에서 감지 안 됨. 최종적으로 타임스탬프 기반 patch 버전(`0.1.YYYYMMDDHHMMSS`)으로 변경하여 매 빌드마다 고유한 정식 semver 생성.
|
||||
|
||||
9. **ArgoCD targetRevision 변경**: `0.1.0` 고정 → `>0.0.0` semver range로 변경하여 새 chart 버전 자동 감지. ArgoCD 기본 polling interval(~3분) 내에 자동 sync됨.
|
||||
|
||||
10. **Deployment 이미지 태그 변경**: `image.tag` values 고정 대신 `{{ .Values.image.tag | default .Chart.AppVersion }}`으로 변경. ArgoCD helm values에서 `image.tag` override 제거하여 chart의 `appVersion`(CI에서 `sha-xxxx`로 설정)을 자동 사용.
|
||||
|
||||
11. **.gitignore 추가**: plan.md에 없었으나 `.env`, `node_modules/`, `.next/` 등을 git에서 제외하기 위해 추가.
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@ import { NextRequest, NextResponse } from 'next/server';
|
|||
import { queryRange, QUERIES } from '@/lib/prometheus';
|
||||
import { calculateStats, detectPeaks, DataPoint } from '@/lib/analytics';
|
||||
|
||||
const QUERY_MAP: Record<string, string | string[]> = {
|
||||
const QUERY_MAP: Record<string, string> = {
|
||||
cpu: QUERIES.cpuUsage,
|
||||
memory: QUERIES.memoryUsage,
|
||||
disk: QUERIES.diskUsage,
|
||||
nas: QUERIES.nasUsage,
|
||||
network: [QUERIES.networkReceive, QUERIES.networkTransmit],
|
||||
};
|
||||
|
||||
const NETWORK_MAP: Record<string, { rx: string; tx: string }> = {
|
||||
ingress: { rx: QUERIES.ingressReceive, tx: QUERIES.ingressTransmit },
|
||||
istio: { rx: QUERIES.istioReceive, tx: QUERIES.istioTransmit },
|
||||
};
|
||||
|
||||
function parsePrometheusValues(values: [number, string][]): DataPoint[] {
|
||||
|
|
@ -26,46 +30,37 @@ export async function GET(
|
|||
const end = new Date();
|
||||
const start = new Date(end.getTime() - days * 24 * 60 * 60 * 1000);
|
||||
|
||||
const queries = QUERY_MAP[type];
|
||||
if (!queries) {
|
||||
try {
|
||||
const netQuery = NETWORK_MAP[type];
|
||||
if (netQuery) {
|
||||
const [rxResults, txResults] = await Promise.all([
|
||||
queryRange(netQuery.rx, start, end, step),
|
||||
queryRange(netQuery.tx, start, end, step),
|
||||
]);
|
||||
|
||||
const process = (results: typeof rxResults) => results.map((r) => {
|
||||
const dataPoints = parsePrometheusValues(r.values);
|
||||
return {
|
||||
instance: r.metric.instance || '',
|
||||
dataPoints,
|
||||
stats: calculateStats(dataPoints),
|
||||
peaks: detectPeaks(dataPoints),
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json({ type, period: { start, end, step }, receive: process(rxResults), transmit: process(txResults) });
|
||||
}
|
||||
|
||||
const query = QUERY_MAP[type];
|
||||
if (!query) {
|
||||
return NextResponse.json({ error: `Unknown metric type: ${type}` }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
if (type === 'network') {
|
||||
const [rxResults, txResults] = await Promise.all([
|
||||
queryRange(QUERIES.networkReceive, start, end, step),
|
||||
queryRange(QUERIES.networkTransmit, start, end, step),
|
||||
]);
|
||||
|
||||
const receive = rxResults.map((r) => {
|
||||
const dataPoints = parsePrometheusValues(r.values);
|
||||
return {
|
||||
instance: r.metric.instance,
|
||||
dataPoints,
|
||||
stats: calculateStats(dataPoints),
|
||||
peaks: detectPeaks(dataPoints),
|
||||
};
|
||||
});
|
||||
|
||||
const transmit = txResults.map((r) => {
|
||||
const dataPoints = parsePrometheusValues(r.values);
|
||||
return {
|
||||
instance: r.metric.instance,
|
||||
dataPoints,
|
||||
stats: calculateStats(dataPoints),
|
||||
peaks: detectPeaks(dataPoints),
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json({ type, period: { start, end, step }, receive, transmit });
|
||||
}
|
||||
|
||||
const results = await queryRange(queries as string, start, end, step);
|
||||
const results = await queryRange(query, start, end, step);
|
||||
const instances = results.map((r) => {
|
||||
const dataPoints = parsePrometheusValues(r.values);
|
||||
return {
|
||||
instance: r.metric.instance,
|
||||
instance: r.metric.instance || '',
|
||||
metric: r.metric,
|
||||
dataPoints,
|
||||
stats: calculateStats(dataPoints),
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ function processResults(results: { metric: Record<string, string>; values: [numb
|
|||
return results.map((r) => {
|
||||
const dataPoints = parseValues(r.values);
|
||||
return {
|
||||
instance: r.metric.instance,
|
||||
instance: r.metric.instance || '',
|
||||
metric: r.metric,
|
||||
dataPoints,
|
||||
stats: calculateStats(dataPoints),
|
||||
|
|
@ -22,34 +22,55 @@ function processResults(results: { metric: Record<string, string>; values: [numb
|
|||
|
||||
export async function GET(request: NextRequest) {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const days = parseInt(searchParams.get('days') || process.env.REPORT_RANGE_DAYS || '7');
|
||||
const startParam = searchParams.get('start');
|
||||
const endParam = searchParams.get('end');
|
||||
const step = searchParams.get('step') || process.env.REPORT_STEP || '5m';
|
||||
|
||||
const end = new Date();
|
||||
const start = new Date(end.getTime() - days * 24 * 60 * 60 * 1000);
|
||||
let end: Date;
|
||||
let start: Date;
|
||||
|
||||
if (startParam && endParam) {
|
||||
start = new Date(startParam);
|
||||
end = new Date(endParam);
|
||||
} else {
|
||||
const days = parseInt(searchParams.get('days') || process.env.REPORT_RANGE_DAYS || '7');
|
||||
end = new Date();
|
||||
start = new Date(end.getTime() - days * 24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
try {
|
||||
const [cpuData, memData, diskData, nasData, rxData, txData, nodes] = await Promise.all([
|
||||
const [
|
||||
cpuData, memData, diskData, nasData,
|
||||
ingressRxData, ingressTxData,
|
||||
istioRxData, istioTxData,
|
||||
nodes,
|
||||
] = await Promise.all([
|
||||
queryRange(QUERIES.cpuUsage, start, end, step),
|
||||
queryRange(QUERIES.memoryUsage, start, end, step),
|
||||
queryRange(QUERIES.diskUsage, start, end, step),
|
||||
queryRange(QUERIES.nasUsage, start, end, step).catch(() => []),
|
||||
queryRange(QUERIES.networkReceive, start, end, step),
|
||||
queryRange(QUERIES.networkTransmit, start, end, step),
|
||||
queryRange(QUERIES.ingressReceive, start, end, step).catch(() => []),
|
||||
queryRange(QUERIES.ingressTransmit, start, end, step).catch(() => []),
|
||||
queryRange(QUERIES.istioReceive, start, end, step).catch(() => []),
|
||||
queryRange(QUERIES.istioTransmit, start, end, step).catch(() => []),
|
||||
getNodes(),
|
||||
]);
|
||||
|
||||
return NextResponse.json({
|
||||
period: { start, end, days, step },
|
||||
period: { start, end, step },
|
||||
nodes,
|
||||
metrics: {
|
||||
cpu: processResults(cpuData),
|
||||
memory: processResults(memData),
|
||||
disk: processResults(diskData),
|
||||
nas: processResults(nasData),
|
||||
network: {
|
||||
receive: processResults(rxData),
|
||||
transmit: processResults(txData),
|
||||
ingress: {
|
||||
receive: processResults(ingressRxData),
|
||||
transmit: processResults(ingressTxData),
|
||||
},
|
||||
istio: {
|
||||
receive: processResults(istioRxData),
|
||||
transmit: processResults(istioTxData),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,9 +10,20 @@ import NodeTable from '@/components/report/NodeTable';
|
|||
import AlertSection from '@/components/report/AlertSection';
|
||||
import ErrorBoundary from '@/components/ErrorBoundary';
|
||||
|
||||
function getDefaultRange() {
|
||||
const end = new Date();
|
||||
const start = new Date(end.getTime() - 7 * 24 * 60 * 60 * 1000);
|
||||
return {
|
||||
start: start.toISOString().slice(0, 10),
|
||||
end: end.toISOString().slice(0, 10),
|
||||
};
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [days, setDays] = useState(7);
|
||||
const { data, isLoading, error } = useReport(days);
|
||||
const defaultRange = getDefaultRange();
|
||||
const [startDate, setStartDate] = useState(defaultRange.start);
|
||||
const [endDate, setEndDate] = useState(defaultRange.end);
|
||||
const { data, isLoading, error } = useReport(startDate, endDate);
|
||||
const reportRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleExportPdf = async () => {
|
||||
|
|
@ -38,7 +49,14 @@ export default function Home() {
|
|||
heightLeft -= pdf.internal.pageSize.getHeight();
|
||||
}
|
||||
|
||||
pdf.save(`infra-report-${days}d.pdf`);
|
||||
pdf.save(`infra-report-${startDate}_${endDate}.pdf`);
|
||||
};
|
||||
|
||||
const setPresetRange = (days: number) => {
|
||||
const end = new Date();
|
||||
const start = new Date(end.getTime() - days * 24 * 60 * 60 * 1000);
|
||||
setStartDate(start.toISOString().slice(0, 10));
|
||||
setEndDate(end.toISOString().slice(0, 10));
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
|
|
@ -68,26 +86,41 @@ export default function Home() {
|
|||
/>
|
||||
</ErrorBoundary>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<div className="flex items-center gap-4 flex-wrap">
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="date"
|
||||
value={startDate}
|
||||
onChange={(e) => setStartDate(e.target.value)}
|
||||
className="px-3 py-1.5 text-sm border rounded bg-white"
|
||||
/>
|
||||
<span className="text-gray-500">~</span>
|
||||
<input
|
||||
type="date"
|
||||
value={endDate}
|
||||
onChange={(e) => setEndDate(e.target.value)}
|
||||
className="px-3 py-1.5 text-sm border rounded bg-white"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
{[1, 3, 7, 14, 30].map((d) => (
|
||||
<button
|
||||
key={d}
|
||||
onClick={() => setDays(d)}
|
||||
className={`px-3 py-1 text-sm rounded ${
|
||||
days === d ? 'bg-blue-600 text-white' : 'bg-white text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
onClick={() => setPresetRange(d)}
|
||||
className="px-3 py-1.5 text-sm rounded bg-white text-gray-700 hover:bg-gray-50 border"
|
||||
>
|
||||
{d}일
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ErrorBoundary fallback="SummaryCards 오류">
|
||||
<SummaryCards
|
||||
cpu={data.metrics.cpu}
|
||||
memory={data.metrics.memory}
|
||||
disk={data.metrics.disk}
|
||||
network={data.metrics.network}
|
||||
ingress={data.metrics.ingress}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
|
||||
|
|
@ -107,8 +140,12 @@ export default function Home() {
|
|||
</ErrorBoundary>
|
||||
)}
|
||||
|
||||
<ErrorBoundary fallback="Network 차트 오류">
|
||||
<NetworkChart data={data.metrics.network} />
|
||||
<ErrorBoundary fallback="Ingress Network 차트 오류">
|
||||
<NetworkChart title="Ingress Network Traffic" data={data.metrics.ingress} />
|
||||
</ErrorBoundary>
|
||||
|
||||
<ErrorBoundary fallback="Istio Network 차트 오류">
|
||||
<NetworkChart title="Istio Network Traffic" data={data.metrics.istio} />
|
||||
</ErrorBoundary>
|
||||
|
||||
<ErrorBoundary fallback="NodeTable 오류">
|
||||
|
|
|
|||
|
|
@ -7,13 +7,22 @@ import { formatTimestamp, formatBytes } from '@/lib/formatters';
|
|||
const ReactECharts = dynamic(() => import('echarts-for-react').then(mod => mod), { ssr: false, loading: () => <div style={{height: 300}} /> });
|
||||
|
||||
interface NetworkChartProps {
|
||||
title?: string;
|
||||
data: NetworkMetrics;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
export default function NetworkChart({ data, height = 300 }: NetworkChartProps) {
|
||||
export default function NetworkChart({ title = 'Network Traffic', data, height = 300 }: NetworkChartProps) {
|
||||
if (!data.receive.length && !data.transmit.length) {
|
||||
return (
|
||||
<div className="bg-gray-50 border rounded-lg p-4 text-center text-gray-400 text-sm" style={{ height }}>
|
||||
{title} - 데이터 없음
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const rxSeries = data.receive.map((inst) => ({
|
||||
name: `RX ${inst.instance}`,
|
||||
name: `RX ${inst.instance || 'total'}`,
|
||||
type: 'line' as const,
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
|
|
@ -22,7 +31,7 @@ export default function NetworkChart({ data, height = 300 }: NetworkChartProps)
|
|||
}));
|
||||
|
||||
const txSeries = data.transmit.map((inst) => ({
|
||||
name: `TX ${inst.instance}`,
|
||||
name: `TX ${inst.instance || 'total'}`,
|
||||
type: 'line' as const,
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
|
|
@ -31,7 +40,7 @@ export default function NetworkChart({ data, height = 300 }: NetworkChartProps)
|
|||
}));
|
||||
|
||||
const option = {
|
||||
title: { text: 'Network Traffic', left: 'center', textStyle: { fontSize: 14 } },
|
||||
title: { text: title, left: 'center', textStyle: { fontSize: 14 } },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (params: any[]) => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ interface NodeTableProps {
|
|||
}
|
||||
|
||||
function findInstanceStats(instances: MetricInstance[], nodeName: string) {
|
||||
const inst = instances.find((i) => i.instance.includes(nodeName));
|
||||
const inst = instances.find((i) => i.instance && i.instance.includes(nodeName));
|
||||
return inst?.stats || null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ interface SummaryCardsProps {
|
|||
cpu: MetricInstance[];
|
||||
memory: MetricInstance[];
|
||||
disk: MetricInstance[];
|
||||
network: NetworkMetrics;
|
||||
ingress: NetworkMetrics;
|
||||
}
|
||||
|
||||
interface CardData {
|
||||
|
|
@ -26,13 +26,13 @@ function getClusterStats(instances: MetricInstance[]): { avg: number; max: numbe
|
|||
return { avg, max, min };
|
||||
}
|
||||
|
||||
export default function SummaryCards({ cpu, memory, disk, network }: SummaryCardsProps) {
|
||||
export default function SummaryCards({ cpu, memory, disk, ingress }: SummaryCardsProps) {
|
||||
const cpuStats = getClusterStats(cpu);
|
||||
const memStats = getClusterStats(memory);
|
||||
const diskStats = getClusterStats(disk);
|
||||
|
||||
const netRxAvg = network.receive.reduce((sum, i) => sum + i.stats.avg, 0);
|
||||
const netTxAvg = network.transmit.reduce((sum, i) => sum + i.stats.avg, 0);
|
||||
const netRxAvg = ingress.receive.reduce((sum, i) => sum + i.stats.avg, 0);
|
||||
const netTxAvg = ingress.transmit.reduce((sum, i) => sum + i.stats.avg, 0);
|
||||
|
||||
const cards: CardData[] = [
|
||||
{
|
||||
|
|
@ -57,7 +57,7 @@ export default function SummaryCards({ cpu, memory, disk, network }: SummaryCard
|
|||
color: diskStats.max > 90 ? 'border-red-500' : diskStats.max > 70 ? 'border-yellow-500' : 'border-green-500',
|
||||
},
|
||||
{
|
||||
label: 'Network',
|
||||
label: 'Ingress',
|
||||
avg: `RX ${formatBytesPerSec(netRxAvg)}`,
|
||||
max: `TX ${formatBytesPerSec(netTxAvg)}`,
|
||||
min: '',
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import { useQuery } from '@tanstack/react-query';
|
|||
import axios from 'axios';
|
||||
import type { ReportData } from '@/types/metrics';
|
||||
|
||||
export function useReport(days: number = 7) {
|
||||
export function useReport(start: string, end: string) {
|
||||
return useQuery<ReportData>({
|
||||
queryKey: ['report', days],
|
||||
queryKey: ['report', start, end],
|
||||
queryFn: async () => {
|
||||
const res = await axios.get(`/api/report?days=${days}`);
|
||||
const res = await axios.get(`/api/report?start=${start}&end=${end}`);
|
||||
return res.data;
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -48,8 +48,12 @@ export const QUERIES = {
|
|||
|| 'sum by (mountpoint,fstype)((1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|nfs",mountpoint!~"/boot.*"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay|nfs",mountpoint!~"/boot.*"}) * 100)',
|
||||
nasUsage: process.env.QUERY_NAS
|
||||
|| '((node_filesystem_size_bytes{fstype=~"nfs", node=~".*(bastion).*"} - node_filesystem_free_bytes{fstype=~"nfs", node=~".*(bastion).*"}) / node_filesystem_size_bytes{fstype=~"nfs", node=~".*(bastion).*"}) * 100',
|
||||
networkReceive: process.env.QUERY_NET_RX
|
||||
ingressReceive: process.env.QUERY_INGRESS_RX
|
||||
|| 'sum(rate(container_network_receive_bytes_total{namespace="ingress-nginx", pod=~"ingress-nginx-controller-.*"}[5m]))',
|
||||
networkTransmit: process.env.QUERY_NET_TX
|
||||
ingressTransmit: process.env.QUERY_INGRESS_TX
|
||||
|| 'sum(rate(container_network_transmit_bytes_total{namespace="ingress-nginx", pod=~"ingress-nginx-controller-.*"}[5m]))',
|
||||
istioReceive: process.env.QUERY_ISTIO_RX
|
||||
|| 'sum(rate(istio_request_bytes_sum{reporter="destination"}[5m]))',
|
||||
istioTransmit: process.env.QUERY_ISTIO_TX
|
||||
|| 'sum(rate(istio_response_bytes_sum{reporter="destination"}[5m]))',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ export interface ReportData {
|
|||
memory: MetricInstance[];
|
||||
disk: MetricInstance[];
|
||||
nas: MetricInstance[];
|
||||
network: NetworkMetrics;
|
||||
ingress: NetworkMetrics;
|
||||
istio: NetworkMetrics;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue