#!/usr/bin/env python import argparse import os import subprocess import sys import uuid from tempfile import NamedTemporaryFile import yaml def main(): parser = argparse.ArgumentParser(description='Dead container rising.') parser.add_argument('pod', type=str, help='target pod name') parser.add_argument('-n', '--namespace', type=str, default='default', help='target namespace (default: default)') parser.add_argument('-c', '--container', type=str, default='', help='target container name') parser.add_argument('-k', '--keep', action="store_true", help='keep yaml') args = parser.parse_args() container_name = args.container kwargs = {} kwargs.setdefault('stdout', subprocess.PIPE) kwargs.setdefault('stderr', subprocess.STDOUT) kwargs.setdefault('encoding', 'utf8') kwargs.setdefault('universal_newlines', True) kwargs['env'] = os.environ.copy() command = ['kubectl', 'get', 'pods', '-n', args.namespace, args.pod, "--export=true", "-o", "yaml"] pipe = subprocess.Popen(command, **kwargs) output, _ = pipe.communicate() try: data = yaml.load(output) except yaml.YAMLError as exc: print(exc) if 'metadata' not in data: print("There is no pod") return data['metadata'].pop('ownerReferences', None) data['metadata'].pop('selfLink', None) name = "debug-" if 'generateName' in data['metadata']: name += data['metadata']['generateName'] name += str(uuid.uuid4())[:5] else: name += data['metadata']['name'] name += str(uuid.uuid4())[:5] data['metadata']['name'] = name data['metadata'].pop('generateName', None) if data['metadata'].get('labels'): data['metadata']['labels'].pop('pod-template-hash', None) if not data['spec'].get('initContainers'): data['spec']['initContainers'] = [] data['spec'].pop('nodeName', None) initcontainer = {} initcontainer['name'] = 'init-debugger' initcontainer['image'] = 'busybox' initcontainer['command'] = ['cp', '/bin/busybox', '/tmp/mydebug/busybox'] initcontainer['volumeMounts'] = [ {'name': 'mydebug', 'mountPath': '/tmp/mydebug/'}] data['spec']['initContainers'].append(initcontainer) real_command = '' for c in data['spec']['containers']: if container_name == '' or c['name'] == container_name: if 'command' in c: real_command = " ".join(c['command']) c['command'] = [ '/bin/busybox', 'sh', '-c', '/bin/busybox --install -s /tmp/mydebug/ && ' '/tmp/mydebug/sleep 86400'] if 'volumeMounts' not in c: c['volumeMounts'] = [] c['volumeMounts'].append( {'name': 'insert-busybox', 'mountPath': '/tmp/mydebug/'}) c['volumeMounts'].append( {'name': 'mydebug-busybox', 'mountPath': '/bin/busybox'}) c.pop('livenessProbe', None) c.pop('readinessProbe', None) if container_name == '': container_name = c['name'] break else: print("Error: can not found %s" % container_name) if 'volumes' not in data['spec']: data['spec']['volumes'] = [] for v in data['spec']['volumes']: if v.get('persistentVolumeClaim', None): v.pop('persistentVolumeClaim', None) v['emptyDir'] = {} data['spec']['volumes'].append( {'name': 'insert-busybox', 'emptyDir': {}}) data['spec']['volumes'].append( {'name': 'mydebug', 'hostPath': {'path': '/tmp/mydebug/'}}) data['spec']['volumes'].append( {'name': 'mydebug-busybox', 'hostPath': {'path': '/tmp/mydebug/busybox'}}) data.pop('status', None) file = NamedTemporaryFile(suffix='.yaml', delete=False) yamlfile = yaml.dump(data, None, canonical=True) file.write(yamlfile.encode('utf8')) file.close() command2 = ['kubectl', 'create', '-n', args.namespace, '-f', file.name] pipe = subprocess.Popen(command2, **kwargs) output, _ = pipe.communicate() if args.keep: print("Check this changed pod yaml:") print(file.name) else: os.unlink(file.name) print("To debug %s, wait some second and run:" % args.pod) print(" kubectl exec -ti %s -n %s " "-c %s -- /tmp/mydebug/sh " "-c \"PATH=\$PATH:/tmp/mydebug/ sh\"" % (name, args.namespace, container_name)) print("") print("If you want to run %s container's command" " then check below command" % args.pod) print(" " + real_command) print("") print("After finish debugging please delete debugging container:") print(" kubectl delete pods %s -n %s " % (name, args.namespace)) if __name__ == '__main__': sys.exit(main())