kube-rs / kube

Rust Kubernetes client and controller runtime
https://kube.rs
Apache License 2.0
3.03k stars 314 forks source link

Add support for metrics API #492

Open deepu105 opened 3 years ago

deepu105 commented 3 years ago

Is there a way to use the metrics API for Kubernetes? In Go it is a separate package and I believe there is no Rust craete equivalent for that yet

https://kubernetes.io/docs/tasks/debug-application-cluster/resource-metrics-pipeline/

MikailBag commented 3 years ago

kube::Client and kube::Api can work with metrics API (as with any other API). If you are ready to work with untyped JSON, than you can use e.g.:

let gvk = GroupVersionKind::gvk("metrics.k8s.io", "v1beta1" /*IIRC*/, "nodemetrics");
let node_metrics: Api<DynamicObject> = Api::all_with(client.clone(), &gvk);
let metrics_list = node_metrics.list(...).await?;
// now metrics_list is essentially Vec<Json>
...

You may also want typed API (like the one you have for core or apps). But in fact, Kubernetes API typings are provided not by kube itself, but by the k8s-openapi crate.

That's why i think that k8s-openapi repository can be a better place for this issue.

clux commented 3 years ago

It's also possible that we can simplify how we implement Resource so that you can use Api<MyMetricType> as long as we can impl Resource for MyMetricType where DynamicType = GroupVersionKind in an easy way.

I think we could have a middle ground between completely untyped, and k8s-openapi.

deepu105 commented 3 years ago

Btw for context. I'm building a Kubernetes terminal dashboard and was trying to use this. Btw if any of you are interested, please consider contributing. I'm quite new to rust and this lib so any help is appreciated

https://github.com/kdash-rs/kdash

deepu105 commented 3 years ago

It's also possible that we can simplify how we implement Resource so that you can use Api<MyMetricType> as long as we can impl Resource for MyMetricType where DynamicType = GroupVersionKind in an easy way.

I think we could have a middle ground between completely untyped, and k8s-openapi.

That would be nice

theduke commented 3 years ago

There is a related (closed) issue in k8s-openapi: https://github.com/Arnavion/k8s-openapi/issues/76

Seems like they don't want to support this.

MikailBag commented 3 years ago

Seems like they don't want to support this.

K8s-openapi maintainer has recently merged my PR which adds support for taking spec from arbitrary URL. So ideally you should be able to take spec from a cluster with metrics-server enabled and get typings for metrics.k8s.io group.

The problem is, k8s-openapi seems to make many assumptions about REST operations, so code generation fails for aggregated apis.

As a next step, I'd try adding a parameter to k8s-openapi which completely skips client generation. I hope this will be enough to support non-builtin API groups.

theduke commented 3 years ago

FWIW, here is an implementation for pod metrics that works for me with Api:

#[derive(serde::Deserialize, Clone, Debug)]
pub struct PodMetricsContainer {
    pub name: String,
    pub usage: PodMetricsContainerUsage,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct PodMetricsContainerUsage {
    pub cpu: Quantity,
    pub memory: Quantity,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct PodMetrics {
    pub metadata: ObjectMeta,
    pub timestamp: String,
    pub window: String,
    pub containers: Vec<PodMetricsContainer>,
}

impl k8s_openapi::Resource for PodMetrics {
    const GROUP: &'static str = "metrics.k8s.io";
    const KIND: &'static str = "pod";
    const VERSION: &'static str = "v1beta1";
    const API_VERSION: &'static str = "metrics.k8s.io/v1beta1";
}

impl k8s_openapi::Metadata for PodMetrics {
    type Ty = ObjectMeta;

    fn metadata(&self) -> &Self::Ty {
        &self.metadata
    }

    fn metadata_mut(&mut self) -> &mut Self::Ty {
        &mut self.metadata
    }
}
Api::<PodMetrics>::namespaces(client.clone(), "default").get("test-pod").await
deepu105 commented 3 years ago

I ended up doing the below for Node metrics

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Usage {
    pub cpu: String,
    pub memory: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeMetrics {
  metadata: kube::api::ObjectMeta,
  usage: Usage,
  timestamp: String,
  window: String,
}

    let request = Request::new("/apis/metrics.k8s.io/v1beta1/nodes");
    client
      .clone()
      .request::<ObjectList<NodeMetrics>>(request.list(&ListParams::default()).unwrap())
      .await
deepu105 commented 3 years ago

May be we can just document the solution from @theduke and close the ticket

clux commented 3 years ago

Yeah, I think there are sufficiently short workarounds at the moment; create structs as above, impl kube::Resource in your source, or use it dynamically with an ApiResource.

Going to mark this as a wontfix for now. I think it would set a difficult precedent for us by trying to do every little peripheral thing in kubernetes ecosystems. I would rather encourage separate packages to help us with code-gen for non-core apis, and have us focus on as much of the generic/apimachinery-esque stuff as possible.

People should be able to find this solution/guidance by searching issues, but I think some kind of document classifying things you can do with kubernetes (in go world) and what the rust-counterparts require, would make sense as a follow-up action here.

deepu105 commented 3 years ago

Ya documentation sounds like a good solution as the current solutions mentioned here are good enough

On Mon, 21 Jun 2021, 8:24 pm Eirik A, @.***> wrote:

Yeah, I think there are sufficiently short workarounds at the moment; create structs as above, impl kube::Resource in your source, or use it dynamically with an ApiResource.

Going to mark this as a wontfix for now. I think it would set a difficult precedent for us by trying to do every little peripheral thing in kubernetes ecosystems. I would rather encourage separate packages to help us with code-gen for non-core apis, and have us focus on as much of the generic/apimachinery-esque stuff as possible.

People should be able to find this solution/guidance by searching issues, but I think some kind of document classifying things you can do with kubernetes (in go world) and what the rust-counterparts require, would make sense as a follow-up action here.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/clux/kube-rs/issues/492#issuecomment-865249846, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIOKF5FFZAAQ5L2HZ5POYDTT57VDANCNFSM4274AIQQ .

clux commented 3 years ago

We do actually grab the metrics structs in the new prototype k8s-pb repo. So we will have support for this once we get the protobuf issue #371 resolved. Absolutely no ETA on that though. It's a pretty big project.

kazk commented 3 years ago

Is there swagger.json for metrics? It has // +k8s:openapi-gen=true, but I don't know where the output is.

clux commented 3 years ago

Only reference to it i see was removed from the repo. Following the trail:

Not sure if that's even relevant.

clux commented 3 years ago

Maybe it's one of those structs that are only ever generated by the metrics-server and so we don't have it on disk. Maybe it needs to be run through https://github.com/kubernetes/kube-openapi ?

I have no idea here. There's very little documentation on this repo. But we might be able to get an answer in #sig-api-machinery or similar channel on the kubernetes slack.

goenning commented 2 years ago

I'm on version 0.15 of the k8s-openapi and there are a few new required properties on the Resource trait, this is what worked for me:

impl k8s_openapi::Resource for PodMetrics {
    const GROUP: &'static str = "metrics.k8s.io";
    const KIND: &'static str = "PodMetrics";
    const VERSION: &'static str = "v1beta1";
    const API_VERSION: &'static str = "metrics.k8s.io/v1beta1";
    const URL_PATH_SEGMENT: &'static str = "pods";

    type Scope = k8s_openapi::NamespaceResourceScope;
}

The rest is just like as mentioned by @theduke above.

imp commented 1 year ago

Fro the sake of reference while this is being sorted out - k8s-metrics crate