Skip to content

Commit 35342b3

Browse files
Merge branch 'master' into revk8s
2 parents 9bd9fc0 + 723d69c commit 35342b3

File tree

5 files changed

+594
-11
lines changed

5 files changed

+594
-11
lines changed

examples/top_pods.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const k8s = require('../dist/index');
2+
3+
const kc = new k8s.KubeConfig();
4+
kc.loadFromDefault();
5+
6+
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
7+
const metricsClient = new k8s.Metrics(kc);
8+
9+
k8s.topPods(k8sApi, metricsClient, "kube-system")
10+
.then((pods) => {
11+
12+
const podsColumns = pods.map((pod) => {
13+
return {
14+
"POD": pod.Pod.metadata.name,
15+
"CPU(cores)": pod.CPU.CurrentUsage,
16+
"MEMORY(bytes)": pod.Memory.CurrentUsage,
17+
}
18+
});
19+
console.log("TOP PODS")
20+
console.table(podsColumns)
21+
});
22+
23+
k8s.topPods(k8sApi, metricsClient, "kube-system")
24+
.then((pods) => {
25+
26+
const podsAndContainersColumns = pods.flatMap((pod) => {
27+
return pod.Containers.map(containerUsage => {
28+
return {
29+
"POD": pod.Pod.metadata.name,
30+
"NAME": containerUsage.Container,
31+
"CPU(cores)": containerUsage.CPUUsage.CurrentUsage,
32+
"MEMORY(bytes)": containerUsage.MemoryUsage.CurrentUsage,
33+
};
34+
})
35+
});
36+
37+
console.log("TOP CONTAINERS")
38+
console.table(podsAndContainersColumns)
39+
});

settings

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# limitations under the License.
1616

1717
# kubernetes-client/gen commit to use for code generation.
18-
export GEN_COMMIT=a3aef4de7a1d5dab72021aa282fffd8bc8a022ca
18+
export GEN_COMMIT=a3aef4d
1919

2020
# GitHub username/organization to clone kubernetes repo from.
2121
export USERNAME=kubernetes

src/top.ts

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
import { CoreV1Api, V1Node, V1Pod } from './gen/api';
2-
import { add, podsForNode, quantityToScalar, totalCPU, totalMemory } from './util';
1+
import { CoreV1Api, V1Node, V1Pod, V1PodList } from './gen/api';
2+
import { ContainerMetric, Metrics, PodMetric } from './metrics';
3+
import {
4+
add,
5+
podsForNode,
6+
quantityToScalar,
7+
ResourceStatus,
8+
totalCPU,
9+
totalCPUForContainer,
10+
totalMemory,
11+
totalMemoryForContainer,
12+
} from './util';
313

414
export class ResourceUsage {
515
constructor(
@@ -9,6 +19,14 @@ export class ResourceUsage {
919
) {}
1020
}
1121

22+
export class CurrentResourceUsage {
23+
constructor(
24+
public readonly CurrentUsage: number | BigInt,
25+
public readonly RequestTotal: number | BigInt,
26+
public readonly LimitTotal: number | BigInt,
27+
) {}
28+
}
29+
1230
export class NodeStatus {
1331
constructor(
1432
public readonly Node: V1Node,
@@ -17,6 +35,23 @@ export class NodeStatus {
1735
) {}
1836
}
1937

38+
export class ContainerStatus {
39+
constructor(
40+
public readonly Container: string,
41+
public readonly CPUUsage: CurrentResourceUsage,
42+
public readonly MemoryUsage: CurrentResourceUsage,
43+
) {}
44+
}
45+
46+
export class PodStatus {
47+
constructor(
48+
public readonly Pod: V1Pod,
49+
public readonly CPU: CurrentResourceUsage,
50+
public readonly Memory: CurrentResourceUsage,
51+
public readonly Containers: ContainerStatus[],
52+
) {}
53+
}
54+
2055
export async function topNodes(api: CoreV1Api): Promise<NodeStatus[]> {
2156
// TODO: Support metrics APIs in the client and this library
2257
const nodes = await api.listNode();
@@ -46,3 +81,87 @@ export async function topNodes(api: CoreV1Api): Promise<NodeStatus[]> {
4681
}
4782
return result;
4883
}
84+
85+
// Returns the current pod CPU/Memory usage including the CPU/Memory usage of each container
86+
export async function topPods(api: CoreV1Api, metrics: Metrics, namespace?: string): Promise<PodStatus[]> {
87+
// Figure out which pod list endpoint to call
88+
const getPodList = async (): Promise<V1PodList> => {
89+
if (namespace) {
90+
return (await api.listNamespacedPod(namespace)).body;
91+
}
92+
return (await api.listPodForAllNamespaces()).body;
93+
};
94+
95+
const [podMetrics, podList] = await Promise.all([metrics.getPodMetrics(namespace), getPodList()]);
96+
97+
// Create a map of pod names to their metric usage
98+
// to make it easier to look up when we need it later
99+
const podMetricsMap = podMetrics.items.reduce((accum, next) => {
100+
accum.set(next.metadata.name, next);
101+
return accum;
102+
}, new Map<string, PodMetric>());
103+
104+
const result: PodStatus[] = [];
105+
for (const pod of podList.items) {
106+
const podMetric = podMetricsMap.get(pod.metadata!.name!);
107+
108+
const containerStatuses: ContainerStatus[] = [];
109+
let currentPodCPU: number | bigint = 0;
110+
let currentPodMem: number | bigint = 0;
111+
let podRequestsCPU: number | bigint = 0;
112+
let podLimitsCPU: number | bigint = 0;
113+
let podRequestsMem: number | bigint = 0;
114+
let podLimitsMem: number | bigint = 0;
115+
116+
pod.spec!.containers.forEach((container) => {
117+
// get the the container CPU/Memory container.resources.requests/limits
118+
const containerCpuTotal = totalCPUForContainer(container);
119+
const containerMemTotal = totalMemoryForContainer(container);
120+
121+
// sum each container's CPU/Memory container.resources.requests/limits
122+
// to get the pod's overall requests/limits
123+
podRequestsCPU = add(podRequestsCPU, containerCpuTotal.request);
124+
podLimitsCPU = add(podLimitsCPU, containerCpuTotal.limit);
125+
126+
podRequestsMem = add(podLimitsMem, containerMemTotal.request);
127+
podLimitsMem = add(podLimitsMem, containerMemTotal.limit);
128+
129+
// Find the container metrics by container.name
130+
// if both the pod and container metrics exist
131+
const containerMetrics =
132+
podMetric !== undefined
133+
? podMetric.containers.find((c) => c.name === container.name)
134+
: undefined;
135+
136+
// Store the current usage of each container
137+
// Sum each container to get the overall pod usage
138+
if (containerMetrics !== undefined) {
139+
const currentContainerCPUUsage = quantityToScalar(containerMetrics.usage.cpu);
140+
const currentContainerMemUsage = quantityToScalar(containerMetrics.usage.memory);
141+
142+
currentPodCPU = add(currentPodCPU, currentContainerCPUUsage);
143+
currentPodMem = add(currentPodMem, currentContainerMemUsage);
144+
145+
const containerCpuUsage = new CurrentResourceUsage(
146+
currentContainerCPUUsage,
147+
containerCpuTotal.request,
148+
containerCpuTotal.limit,
149+
);
150+
const containerMemUsage = new CurrentResourceUsage(
151+
currentContainerMemUsage,
152+
containerMemTotal.request,
153+
containerMemTotal.limit,
154+
);
155+
156+
containerStatuses.push(
157+
new ContainerStatus(containerMetrics.name, containerCpuUsage, containerMemUsage),
158+
);
159+
}
160+
});
161+
162+
const podCpuUsage = new CurrentResourceUsage(currentPodCPU, podRequestsCPU, podLimitsCPU);
163+
const podMemUsage = new CurrentResourceUsage(currentPodMem, podRequestsMem, podLimitsMem);
164+
result.push(new PodStatus(pod, podCpuUsage, podMemUsage, containerStatuses));
165+
}
166+
return result;
167+
}

0 commit comments

Comments
 (0)