Skip to content

Instantly share code, notes, and snippets.

@prehensile
Last active October 8, 2015 04:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prehensile/841cb7f0bb822ea902cd to your computer and use it in GitHub Desktop.
Save prehensile/841cb7f0bb822ea902cd to your computer and use it in GitHub Desktop.
Various Kubernetes / Google Container Engine tools
#!/usr/bin/env python
##
# kube-resources.py
# Collate and report Kubernetes pod usages vs. node limits.
#
# Assumes `kubectl` is installed and available.
#
# Author: Henry Cooke, me@prehensile.co.uk
# Version: 20150816
#
import json
import subprocess
import re
import math
def main():
# get pod & node data
pod_dict = get_pods()
node_dict = get_nodes()
# step through nodes hash
for node_name in node_dict:
# print node info
print "---\nNODE:\t%s\n---" % node_name
node = node_dict[node_name]
stat = node.get("status")
cap = stat.get("capacity")
cpu_capacity = 0
mem_capacity = 0
if cap:
cpu_capacity = parse_cpu( cap.get("cpu") )
mem_capacity = parse_mem( cap.get("memory") )
# print pods
pods = pod_dict.get( node_name )
if (pods is not None) and (len(pods)>0):
total_cpu, total_mem, rows = parse_pods( pods )
print_pods( rows )
print "---"
print "Memory allocated: %s (%2.2f%% of capacity)" % (
format_mem(total_mem,"Mi"),
(float(total_mem)/float(mem_capacity))*100.0
)
print "CPU allocated: %s (%2.2f%% of capacity)" % (
format_cpu(total_cpu,"m"),
(total_cpu/cpu_capacity)*100.0
)
# print node capacity
print "---"
print "Memory capacity: %s" % format_mem(mem_capacity,"Mi")
print "CPU capacity: %s" % format_cpu(cpu_capacity,"m")
print "---\n"
def get_nodes():
node_dict = {}
node_json = json.loads(
subprocess.check_output(
[ "kubectl", "get", "nodes", "-o", "json" ]
)
)
node_dict = {}
for node in node_json["items"]:
node_dict[ node["metadata"]["name"] ] = node
return node_dict
def get_pods():
pod_json = json.loads(
subprocess.check_output(
[ "kubectl", "get", "pods", "-o", "json", "--all-namespaces" ]
)
)
pod_dict = {}
for pod in pod_json["items"]:
spec = pod["spec"]
if "nodeName" in spec:
node_name = spec["nodeName"]
if node_name not in pod_dict:
pod_dict[node_name] = []
pod_dict[node_name].append(pod)
return pod_dict
def parse_container( container ):
container_name = container["name"]
res = container.get("resources")
cpu_limit = 0
mem_limit = 0
if res:
limits = res.get("limits")
if limits:
cpu_limit = parse_cpu( limits.get("cpu") )
mem_limit = parse_mem( limits.get("memory") )
return container_name, cpu_limit, mem_limit
def print_pods( rows ):
headers = [ "CONTAINER NAME", "NAMESPACE", "MEM LIMIT", "CPU LIMIT" ]
# calculate inital column widths
row_widths = [ len(col)+2 for col in headers ]
# step through rows, find max widths for columns
rows.insert( 0, headers )
for row in rows:
for i in range(len(row_widths)):
row_widths[i] = max( row_widths[i], len("%s"%row[i])+2 )
# generate format string, see https://docs.python.org/3/library/string.html#format-examples
fmt = '{:<%d}{:<%d}{:<%d}{:<%d}' % tuple(row_widths)
for row in rows:
print fmt.format(*row)
def parse_pods( pods ):
total_cpu = 0
total_mem = 0
rows = []
for pod in pods:
spec = pod["spec"]
m = pod["metadata"]
namespace = m["namespace"]
for container in spec["containers"]:
container_name, cpu_limit, mem_limit = parse_container( container )
total_cpu += cpu_limit
total_mem += mem_limit
rows.append( (container_name,namespace, format_mem(mem_limit,"Mi"), format_cpu(cpu_limit,"m")))
rows.append( ["","","---","---"] )
rows.append( ["","TOTALS",format_mem(total_mem,"Mi"),format_cpu(total_cpu,"m")] )
return total_cpu, total_mem, rows
def parse_cpu( cpu ):
""" Return CPU value in whole units """
if cpu is None:
return 0
if type(cpu) is int:
return cpu
g = re.match('(\d*)(\w*)',cpu).groups()
amt = int(g[0])
if len(g) > 1:
unit = g[1]
# TODO: add more possible unit types?
if unit == "m":
amt = float(amt) / 1000.0
return amt
def format_cpu( cpu, unit=None ):
if unit.lower() == "m":
# return CPU formatted in milliunits
return "%0.0fm" % (float(cpu) * 1000.0)
return cpu * 1000
def parse_mem( mem ):
""" Return mem value in bytes """
if mem is None:
return 0
if type(mem) is int:
return mem
g = re.match('(\d*)(\w*)',mem).groups()
amt = int(g[0])
if len(g) > 1:
unit = g[1]
# TODO: add more possible unit types?
if unit.lower() == "ki":
amt *= 1024
elif unit.lower() == "mi":
amt *= (1024 * 1024)
return amt
def format_mem( mem, unit=None ):
if unit.lower() == "ki":
# return mem formatted in kibibytes
return "%dKi" % (mem / 1024)
elif unit.lower() == "mi":
# return mem formatted in mebibytes
return "%dMi" % (mem / math.pow(1024,2) )
elif unit.lower() == "gi":
# return mem formatted in gibibytes
return "%dGi" % (mem / math.pow(1024,3) )
return mem
# entrypoint...
if __name__ == '__main__':
main()
#!/usr/bin/env bash
for MODULE in "$@"
do
kubectl rolling-update $MODULE --image=gcr.io/pastcards-1033/$MODULE
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment