Skip to content

Commit f2e3794

Browse files
authored
Merge pull request #21 from JuliaComputing/tan/newapi
add custom metrics APIs (custom.metrics.k8s.io)
2 parents cae08cc + 7ac0523 commit f2e3794

12 files changed

+750
-5
lines changed

Metrics.md

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
Kubernetes Metrics and Custom Metrics APIs generalize consumption of metrics published by the cluster and applications running within it.
2+
3+
## Node and Pod Metrics
4+
5+
Kubernetes Pod and Node metrics are exposed like any other Kubernetes resources. Below is a sample interaction that illustrates how to fetch them using Kuber.jl:
6+
7+
```julia
8+
julia> using Kuber
9+
10+
julia> ctx = KuberContext()
11+
Kubernetes namespace default at http://localhost:8001
12+
13+
julia> Kuber.set_api_versions!(ctx; verbose=true)
14+
┌ Info: Core versions
15+
│ supported = "v1"
16+
└ preferred = "v1"
17+
...
18+
┌ Info: metrics.k8s.io (Metrics) versions
19+
│ supported = "v1beta1"
20+
└ preferred = "v1beta1"
21+
┌ Info: custom.metrics.k8s.io (CustomMetrics) versions
22+
│ supported = "v1beta1"
23+
└ preferred = "v1beta1"
24+
...
25+
26+
julia> # same as: list(ctx, :NodeMetrics; namespace=nothing)
27+
julia> result = get(ctx, :NodeMetrics)
28+
{
29+
"metadata": {
30+
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes"
31+
},
32+
"items": [
33+
{
34+
"timestamp": "2020-03-10T04:35:34Z",
35+
"metadata": {
36+
"creationTimestamp": "2020-03-10T04:35:47Z",
37+
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/tanlto",
38+
"name": "tanlto"
39+
},
40+
"usage": {
41+
"cpu": "608075001n",
42+
"memory": "11870920Ki"
43+
},
44+
"window": "30s"
45+
}
46+
]
47+
}
48+
49+
julia> result = get(ctx, :NodeMetrics, "tanlto")
50+
{
51+
"timestamp": "2020-03-10T04:35:34Z",
52+
"metadata": {
53+
"creationTimestamp": "2020-03-10T04:35:50Z",
54+
"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/tanlto",
55+
"name": "tanlto"
56+
},
57+
"usage": {
58+
"cpu": "608075001n",
59+
"memory": "11870920Ki"
60+
},
61+
"window": "30s"
62+
}
63+
64+
65+
julia> # same as: list(ctx, :PodMetrics; namespace=nothing)
66+
julia> result = get(ctx, :PodMetrics)
67+
{
68+
"metadata": {
69+
"selfLink": "/apis/metrics.k8s.io/v1beta1/pods"
70+
},
71+
"items": [
72+
{
73+
"timestamp": "2020-03-10T04:35:29Z",
74+
"metadata": {
75+
"creationTimestamp": "2020-03-10T04:36:00Z",
76+
"selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/elasticsearch-logging-0",
77+
"name": "elasticsearch-logging-0",
78+
"namespace": "kube-system"
79+
},
80+
"window": "30s",
81+
"containers": [
82+
{
83+
"usage": {
84+
"cpu": "6898860n",
85+
"memory": "1337780Ki"
86+
},
87+
"name": "elasticsearch-logging"
88+
}
89+
]
90+
},
91+
...
92+
{
93+
"timestamp": "2020-03-10T04:35:30Z",
94+
"metadata": {
95+
"creationTimestamp": "2020-03-10T04:36:00Z",
96+
"selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-controller-manager-tanlto",
97+
"name": "kube-controller-manager-tanlto",
98+
"namespace": "kube-system"
99+
},
100+
"window": "30s",
101+
"containers": [
102+
{
103+
"usage": {
104+
"cpu": "23127068n",
105+
"memory": "61468Ki"
106+
},
107+
"name": "kube-controller-manager"
108+
}
109+
]
110+
}
111+
]
112+
}
113+
114+
julia> result = get(ctx, :PodMetrics, "kube-proxy-7nczq")
115+
{
116+
"timestamp": "2020-03-10T04:35:57Z",
117+
"metadata": {
118+
"creationTimestamp": "2020-03-10T04:36:16Z",
119+
"selfLink": "/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-proxy-7nczq",
120+
"name": "kube-proxy-7nczq",
121+
"namespace": "kube-system"
122+
},
123+
"window": "30s",
124+
"containers": [
125+
{
126+
"usage": {
127+
"cpu": "533122n",
128+
"memory": "32028Ki"
129+
},
130+
"name": "kube-proxy"
131+
}
132+
]
133+
}
134+
```
135+
136+
## Custom Metrics
137+
138+
Since the custom metrics APIs take more than one parameters, unlike the rest of the Kubernetes APIs, it is not possible to generalize both `list` and `get` actions into the same `get` API in Kuber.jl (as is done for the other Kubernetes entities). Kuber.jl therefore exposes a `list` API that explicitly does listing. The `list` API works for both custom metrics and any other Kubernetes resource that supports listing. The older `get` API continues to work for listing resources other than custom metrics.
139+
140+
Kuber.jl attempts to genralize the custom metrics API to match the rest of Kubernetes format. That requires taking a composite metric name as a single string, with components separated by the `/` character. It matches the way Kubernetes API discovery exposes the endpoints. E.g.:
141+
142+
```
143+
{
144+
"kind": "APIResourceList",
145+
"apiVersion": "v1",
146+
"groupVersion": "custom.metrics.k8s.io/v1beta1",
147+
"resources": [
148+
{
149+
"name": "pods/prometheus_target_scrape_pool_reloads",
150+
"singularName": "",
151+
"namespaced": true,
152+
"kind": "MetricValueList",
153+
"verbs": [
154+
"get"
155+
]
156+
},
157+
{
158+
"name": "jobs.batch/kube_namespace_status_phase",
159+
"singularName": "",
160+
"namespaced": true,
161+
"kind": "MetricValueList",
162+
"verbs": [
163+
"get"
164+
]
165+
},
166+
{
167+
"name": "pods/node_memory_Inactive_anon_bytes",
168+
"singularName": "",
169+
"namespaced": true,
170+
"kind": "MetricValueList",
171+
"verbs": [
172+
"get"
173+
]
174+
},
175+
...
176+
]
177+
}
178+
```
179+
180+
The downside however is that it needs the API user to be cognizant of the formatting rule. Therefore Kuber.jl also exports helper methods specifically for custom metrics - `list_custom_metrics` `list_namespaced_custom_metrics`.
181+
182+
### Non-namespaced Custom Metrics
183+
184+
Retrieve the given metric for the given non-namespaced object (e.g. Node, PersistentVolume). Composite metric name is of the form `<objecttype>/<objectname>/<metricname>` Passing `*` for objectname would retrieve the given metric for all non-namespaced objects of the given type.
185+
186+
```julia
187+
julia> # same as: list(ctx, :MetricValue, "nodes/*/go_memstats_last_gc_time_seconds"; namespace=nothing)
188+
julia> list_custom_metrics(ctx, "nodes", "go_memstats_last_gc_time_seconds")
189+
{
190+
"kind": "MetricValueList",
191+
"metadata": {
192+
"selfLink": "/apis/custom.metrics.k8s.io/v1beta1/nodes/%2A/go_memstats_last_gc_time_seconds"
193+
},
194+
"apiVersion": "custom.metrics.k8s.io/v1beta1",
195+
"items": [
196+
{
197+
"timestamp": "2020-03-13T06:49:27Z",
198+
"value": "1584082154494m",
199+
"metricName": "go_memstats_last_gc_time_seconds",
200+
"describedObject": {
201+
"kind": "Node",
202+
"apiVersion": "/v1",
203+
"name": "tanlto"
204+
}
205+
}
206+
]
207+
}
208+
209+
julia> # same as: list(ctx, :MetricValue, "nodes/tanlto/go_memstats_last_gc_time_seconds"; namespace=nothing)
210+
julia> list_custom_metrics(ctx, "nodes", "tanlto", "go_memstats_last_gc_time_seconds")
211+
{
212+
"kind": "MetricValueList",
213+
"metadata": {
214+
"selfLink": "/apis/custom.metrics.k8s.io/v1beta1/nodes/tanlto/go_memstats_last_gc_time_seconds"
215+
},
216+
"apiVersion": "custom.metrics.k8s.io/v1beta1",
217+
"items": [
218+
{
219+
"timestamp": "2020-03-13T06:50:13Z",
220+
"value": "1584082185722m",
221+
"metricName": "go_memstats_last_gc_time_seconds",
222+
"describedObject": {
223+
"kind": "Node",
224+
"apiVersion": "/v1",
225+
"name": "tanlto"
226+
}
227+
}
228+
]
229+
}
230+
```
231+
232+
### Namespaced Custom Metrics
233+
234+
Retrieve the given metric (in composite form) which describes the given namespace. Composite form of metrics can be either "metric/<metricname>" to fetch metrics of all objects in the namespace, or `<objecttype>/<objectname>/<metricname>` to fetch metrics of the specified object type and name. Passing `*` for objectname would fetch metrics of all objects of the specified type in the namespace.
235+
236+
```julia
237+
julia> # same as: list(ctx, :MetricValue, "metrics/coredns_forward_request_duration_seconds_sum")
238+
julia> list_namespaced_custom_metrics(ctx, "coredns_forward_request_duration_seconds_sum")
239+
{
240+
"kind": "MetricValueList",
241+
"metadata": {
242+
"selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/metrics/coredns_forward_request_duration_seconds_sum"
243+
},
244+
"apiVersion": "custom.metrics.k8s.io/v1beta1",
245+
"items": [
246+
{
247+
"timestamp": "2020-03-13T06:40:17Z",
248+
"value": "23336m",
249+
"metricName": "coredns_forward_request_duration_seconds_sum",
250+
"describedObject": {
251+
"kind": "Namespace",
252+
"apiVersion": "/v1",
253+
"name": "kube-system"
254+
}
255+
}
256+
]
257+
}
258+
259+
260+
julia> # same as: list(ctx, :MetricValue, "pods/*/coredns_forward_request_duration_seconds_sum")
261+
julia> list_namespaced_custom_metrics(ctx, "pods", "coredns_forward_request_duration_seconds_sum")
262+
{
263+
"kind": "MetricValueList",
264+
"metadata": {
265+
"selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/pods/%2A/coredns_forward_request_duration_seconds_sum"
266+
},
267+
"apiVersion": "custom.metrics.k8s.io/v1beta1",
268+
"items": [
269+
{
270+
"timestamp": "2020-03-13T06:45:39Z",
271+
"value": "11452m",
272+
"metricName": "coredns_forward_request_duration_seconds_sum",
273+
"describedObject": {
274+
"kind": "Pod",
275+
"apiVersion": "/v1",
276+
"name": "coredns-6955765f44-66hlh",
277+
"namespace": "kube-system"
278+
}
279+
},
280+
{
281+
"timestamp": "2020-03-13T06:45:39Z",
282+
"value": "12338m",
283+
"metricName": "coredns_forward_request_duration_seconds_sum",
284+
"describedObject": {
285+
"kind": "Pod",
286+
"apiVersion": "/v1",
287+
"name": "coredns-6955765f44-n4nhj",
288+
"namespace": "kube-system"
289+
}
290+
}
291+
]
292+
}
293+
294+
julia> # same as: list(ctx, :MetricValue, "pods/coredns-6955765f44-n4nhj/coredns_forward_request_duration_seconds_sum")
295+
julia> list_namespaced_custom_metrics(ctx, "pods", "coredns-6955765f44-n4nhj", "coredns_forward_request_duration_seconds_sum")
296+
{
297+
"kind": "MetricValueList",
298+
"metadata": {
299+
"selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/kube-system/pods/coredns-6955765f44-n4nhj/coredns_forward_request_duration_seconds_sum"
300+
},
301+
"apiVersion": "custom.metrics.k8s.io/v1beta1",
302+
"items": [
303+
{
304+
"timestamp": "2020-03-13T06:47:01Z",
305+
"value": "12338m",
306+
"metricName": "coredns_forward_request_duration_seconds_sum",
307+
"describedObject": {
308+
"kind": "Pod",
309+
"apiVersion": "/v1",
310+
"name": "coredns-6955765f44-n4nhj",
311+
"namespace": "kube-system"
312+
}
313+
}
314+
]
315+
}
316+
```

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ An easy to use API to access Kubernetes clusters from Julia. The `Kuber.Kubernet
88

99
Most of the low level APIs fit into a common usage pattern. Kuber.jl makes it possible to use all of them with only a few intuitive verb based APIs. Verbs act on entities. Entities can be identified by names or selector patterns, or otherwise can apply to all entities of that class. Verbs can take additional parameters, e.g. when creating or updating entities.
1010

11-
A [tutorial](https://juliacomputing.com/blog/2018/12/15/kuber.html) on using Kuber.jl.
12-
1311
API and Entity naming convention follows the standard Kubernetes API and Model naming conventions.
1412

13+
Here are a few helpful resources:
14+
15+
- [Tutorial](https://juliacomputing.com/blog/2018/12/15/kuber.html) on using Kuber.jl.
16+
- [Article](Metrics.md) on using metrics and custom metrics with Kuber.jl
17+
18+
1519
### Entities:
1620

1721
Any Kubernetes entity supported. APIs identify an entity by symbol named as per Kubernetes naming convention.
@@ -29,6 +33,7 @@ Any Kubernetes entity supported. APIs identify an entity by symbol named as per
2933
Kubernetes APIs are mapped to these easy to use verbs, familiar to Julia users.
3034

3135
- `get`: list or fetch entities
36+
- `list`: list entities
3237
- `put!`: create entities
3338
- `update!`: update existing entities
3439
- `delete!`: delete existing entities
@@ -47,6 +52,7 @@ Other convenience methods:
4752

4853
- `kuber_type`: identify the Julia object corresponding to the Kubernetes specification
4954
- `kuber_obj`: instantiate a Julia object from for the supplied Kubernetes specification
55+
- Helper methods for [accessing metrics](Metrics.md)
5056

5157
### References:
5258
- API conventions: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md

0 commit comments

Comments
 (0)