Created
July 27, 2017 12:15
-
-
Save rainder/ed3e28e49ba809d6964fcec5577cd172 to your computer and use it in GitHub Desktop.
kubernetes cluster backup script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
'use strict'; | |
/** | |
* | |
* Usage example | |
* | |
* To dump cluster configuration to the file use | |
* | |
* `node ./k8s-backup.js [--context=...] > dump.json` | |
* | |
* To restore use | |
* | |
* `kubectl apply [--context=...] -f dump.json` | |
*/ | |
const childProcess = require('child_process'); | |
const util = require('util'); | |
const exec = util.promisify(childProcess.exec); | |
const EXEC_OPTIONS = { maxBuffer: Infinity }; | |
const OBJECTS_TO_BACKUP = [ | |
'namespaces', | |
'limitranges', | |
'serviceaccounts', | |
'clusterrolebindings', | |
'clusterroles', | |
'rolebindings', | |
'roles', | |
'configmaps', | |
'secrets', | |
'storageclasses', | |
'services', | |
'ingresses', | |
'daemonsets', | |
'deployments', | |
'replicationcontrollers', | |
'statefulsets', | |
'horizontalpodautoscalers', | |
'poddisruptionbudgets', | |
// 'thirdpartyresources', | |
]; | |
return run().catch((err) => console.error(err.stack)); | |
/** | |
* | |
* @returns {Promise.<void>} | |
*/ | |
async function run() { | |
const command = [ | |
'kubectl', | |
'get', | |
OBJECTS_TO_BACKUP.join(','), | |
'--export=true', | |
'-o json', | |
'--all-namespaces', | |
...getArgs(), | |
].join(' '); | |
const json = await exec(command, EXEC_OPTIONS).then((result) => { | |
if (result.stderr) { | |
console.error(result.stderr); | |
process.exit(1); | |
} | |
return JSON.parse(result.stdout); | |
}); | |
cleanUp(json); | |
printStats(json); | |
const jsonString = JSON.stringify(json, 0, 2); | |
process.stdout.write(jsonString); | |
console.error(`\nBytes written: ${jsonString.length}`); | |
}; | |
/** | |
* | |
* @param json | |
*/ | |
function cleanUp(json) { | |
json.items = json.items.filter((item) => { | |
return item.metadata.namespace !== 'kube-system' && item.metadata.namespace !== 'kube-public'; | |
}); | |
json.items.forEach((item) => { | |
Reflect.deleteProperty(item, 'status'); | |
Reflect.deleteProperty(item.metadata, 'creationTimestamp'); | |
Reflect.deleteProperty(item.metadata, 'uid'); | |
Reflect.deleteProperty(item.metadata, 'resourceVersion'); | |
if (item.metadata.annotations) { | |
Reflect.deleteProperty(item.metadata.annotations, 'kubectl.kubernetes.io/last-applied-configuration'); | |
} | |
if (item.kind === 'Service') { | |
Reflect.deleteProperty(item.spec, 'clusterIP'); | |
} | |
}); | |
} | |
/** | |
* | |
* @param json | |
*/ | |
function printStats(json) { | |
const objects = new Map(); | |
console.error( | |
'Namespaces:', | |
Array.from(new Set(json.items.map(item => item.metadata.namespace))).filter(i => i).join(', '), | |
); | |
json.items.forEach(({kind}) => { | |
objects.set(kind, (objects.get(kind) || 0) + 1); | |
}); | |
console.error(''); | |
console.error(Array.from(objects.entries()).map(i => i.join(': ')).join('\n')); | |
} | |
/** | |
* | |
* @returns {Array} | |
*/ | |
function getArgs() { | |
const result = []; | |
const commands = { | |
'--context': (value) => result[result.length] = `--context=${value}`, | |
}; | |
process.argv.slice(2).forEach((arg) => { | |
const [key, value] = arg.split('='); | |
if (commands[key] === undefined) { | |
console.error(`Unknown argument specified: ${key}`); | |
process.exit(1); | |
} | |
commands[key](value); | |
}); | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment