mirror of https://github.com/k3s-io/k3s
List resource QoS tier of each container when describing pods; Re-order resource table
parent
6e76f1aef7
commit
22a794cc22
|
@ -31,6 +31,7 @@ import (
|
|||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/fieldpath"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
qosutil "k8s.io/kubernetes/pkg/kubelet/qos/util"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
@ -714,6 +715,14 @@ func describeContainers(pod *api.Pod, out io.Writer) {
|
|||
fmt.Fprintf(out, " Image:\t%s\n", container.Image)
|
||||
fmt.Fprintf(out, " Image ID:\t%s\n", status.ImageID)
|
||||
|
||||
resourceToQoS := qosutil.GetQoS(&container)
|
||||
if len(resourceToQoS) > 0 {
|
||||
fmt.Fprintf(out, " QoS Tier:\n")
|
||||
}
|
||||
for resource, qos := range resourceToQoS {
|
||||
fmt.Fprintf(out, " %s:\t%s\n", resource, qos)
|
||||
}
|
||||
|
||||
if len(container.Resources.Limits) > 0 {
|
||||
fmt.Fprintf(out, " Limits:\n")
|
||||
}
|
||||
|
@ -1180,8 +1189,8 @@ func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string) (str
|
|||
func describeNodeResource(pods []*api.Pod, node *api.Node, out io.Writer) {
|
||||
nonTerminatedPods := filterTerminatedPods(pods)
|
||||
fmt.Fprintf(out, "Non-terminated Pods:\t(%d in total)\n", len(nonTerminatedPods))
|
||||
fmt.Fprint(out, " Namespace\tName\t\tCPU Requests\tMemory Requests\tCPU Limits\tMemory Limits\n")
|
||||
fmt.Fprint(out, " ─────────\t────\t\t────────────\t───────────────\t──────────\t─────────────\n")
|
||||
fmt.Fprint(out, " Namespace\tName\t\tCPU Requests\tCPU Limits\tMemory Requests\tMemory Limits\n")
|
||||
fmt.Fprint(out, " ─────────\t────\t\t────────────\t──────────\t───────────────\t─────────────\n")
|
||||
totalMilliCPUReq := int64(0)
|
||||
totalMemoryReq := int64(0)
|
||||
fractionPodCPUReq := float64(0)
|
||||
|
@ -1216,13 +1225,13 @@ func describeNodeResource(pods []*api.Pod, node *api.Node, out io.Writer) {
|
|||
fractionPodCPULimit = float64(podTotalMilliCPULimit) / float64(node.Status.Capacity.Cpu().MilliValue()) * 100
|
||||
fractionPodMemoryLimit = float64(podTotalMemoryLimit) / float64(node.Status.Capacity.Memory().Value()) * 100
|
||||
fmt.Fprintf(out, " %s\t%s\t\t%dm (%d%%)\t%dKi (%d%%)\t%dm (%d%%)\t%dKi (%d%%)\n", pod.Namespace, pod.Name,
|
||||
podTotalMilliCPUReq, int64(fractionPodCPUReq), podTotalMemoryReq/1000, int64(fractionPodMemoryReq), podTotalMilliCPULimit, int64(fractionPodCPULimit), podTotalMemoryLimit/1000, int64(fractionPodMemoryLimit))
|
||||
podTotalMilliCPUReq, int64(fractionPodCPUReq), podTotalMilliCPULimit, int64(fractionPodCPULimit), podTotalMemoryReq/1000, int64(fractionPodMemoryReq), podTotalMemoryLimit/1000, int64(fractionPodMemoryLimit))
|
||||
}
|
||||
fmt.Fprint(out, "Allocated resources:\n CPU Requests\tMemory Requests\tCPU Limits\tMemory Limits\n")
|
||||
fmt.Fprint(out, " ────────────\t───────────────\t──────────\t─────────────\n")
|
||||
fmt.Fprint(out, "Allocated resources:\n CPU Requests\tCPU Limits\tMemory Requests\tMemory Limits\n")
|
||||
fmt.Fprint(out, " ────────────\t──────────\t───────────────\t─────────────\n")
|
||||
fractionTotalCPUReq = float64(totalMilliCPUReq) / float64(node.Status.Capacity.Cpu().MilliValue()) * 100
|
||||
fractionTotalMemoryReq = float64(totalMemoryReq) / float64(node.Status.Capacity.Memory().Value()) * 100
|
||||
fmt.Fprintf(out, " %dm (%d%%)\t%dKi (%d%%)\t%dm\t%dKi\n", totalMilliCPUReq, int64(fractionTotalCPUReq), totalMemoryReq/1000, int64(fractionTotalMemoryReq), totalMilliCPULimit, totalMemoryLimit/1000)
|
||||
fmt.Fprintf(out, " %dm (%d%%)\t%dm\t%dKi (%d%%)\t%dKi\n", totalMilliCPUReq, int64(fractionTotalCPUReq), totalMilliCPULimit, totalMemoryReq/1000, int64(fractionTotalMemoryReq), totalMemoryLimit/1000)
|
||||
}
|
||||
|
||||
func filterTerminatedPods(pods []*api.Pod) []*api.Pod {
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
const (
|
||||
Guaranteed = "Guaranteed"
|
||||
Burstable = "Burstable"
|
||||
BestEffort = "Best-Effort"
|
||||
)
|
||||
|
||||
// isResourceGuaranteed returns true if the container's resource requirements are Guaranteed.
|
||||
func isResourceGuaranteed(container *api.Container, resource api.ResourceName) bool {
|
||||
// A container resource is guaranteed if its request == limit.
|
||||
// If request == limit, the user is very confident of resource consumption.
|
||||
req, hasReq := container.Resources.Requests[resource]
|
||||
limit, hasLimit := container.Resources.Limits[resource]
|
||||
if !hasReq || !hasLimit {
|
||||
return false
|
||||
}
|
||||
return req.Value() == limit.Value() && req.Value() != 0
|
||||
}
|
||||
|
||||
// isResourceBestEffort returns true if the container's resource requirements are best-effort.
|
||||
func isResourceBestEffort(container *api.Container, resource api.ResourceName) bool {
|
||||
// A container resource is best-effort if its request is unspecified or 0.
|
||||
// If a request is specified, then the user expects some kind of resource guarantee.
|
||||
req, hasReq := container.Resources.Requests[resource]
|
||||
return !hasReq || req.Value() == 0
|
||||
}
|
||||
|
||||
// GetQos returns a mapping of resource name to QoS class of a container
|
||||
func GetQoS(container *api.Container) map[api.ResourceName]string {
|
||||
resourceToQoS := map[api.ResourceName]string{}
|
||||
for resource := range allResources(container) {
|
||||
switch {
|
||||
case isResourceGuaranteed(container, resource):
|
||||
resourceToQoS[resource] = Guaranteed
|
||||
case isResourceBestEffort(container, resource):
|
||||
resourceToQoS[resource] = BestEffort
|
||||
default:
|
||||
resourceToQoS[resource] = Burstable
|
||||
}
|
||||
}
|
||||
return resourceToQoS
|
||||
}
|
||||
|
||||
// allResources returns a set of resources the container has
|
||||
func allResources(container *api.Container) map[api.ResourceName]bool {
|
||||
resources := map[api.ResourceName]bool{}
|
||||
for resource := range container.Resources.Requests {
|
||||
resources[resource] = true
|
||||
}
|
||||
for resource := range container.Resources.Limits {
|
||||
resources[resource] = true
|
||||
}
|
||||
return resources
|
||||
}
|
Loading…
Reference in New Issue