PCEtLXtzdWJ0ZW1wbGF0ZSBjb21tb24vaGVhZGVyX2NvbW1vbn0tLT4JPCEtLXtpZiAkX0dFVFsnbW9kJ10gPT0gJ3ZpZXd0aHJlYWQnICYmICFlbXB0eSgkX0dbJ3RpZCddKX0tLT4KCTxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy5xaWRhbzEyMy5jb20vYmJzL3RocmVhZC17JF9HWyd0aWQnXX0tMS0xLmh0bWwiIC8+Cgk8IS0te2Vsc2VpZiAkX0dFVFsnbW9kJ10gPT0gJ2ZvcnVtZGlzcGxheScgJiYgIWVtcHR5KCRfR1snZmlkJ10pfS0tPgoJPGxpbmsgcmVsPSJjYW5vbmljYWwiIGhyZWY9Imh0dHBzOi8vd3d3LnFpZGFvMTIzLmNvbS9iYnMvZm9ydW0teyRfR1snZmlkJ119LTEuaHRtbCIgLz4KCTwhLS17ZWxzZWlmICRfR0VUWydtb2QnXSA9PSAnZ3VpZGUnfS0tPgoJPGxpbmsgcmVsPSJjYW5vbmljYWwiIGhyZWY9Imh0dHBzOi8vd3d3LnFpZGFvMTIzLmNvbS9iYnMvZ3VpZGUvIiAvPgoJPCEtLXtlbHNlaWYgJF9HWydiYXNlc2NyaXB0J10gPT0gJ2ZvcnVtJyAmJiAoZW1wdHkoJF9HRVRbJ21vZCddKSB8fCAkX0dFVFsnbW9kJ10gPT0gJ2luZGV4Jyl9LS0+Cgk8bGluayByZWw9ImNhbm9uaWNhbCIgaHJlZj0iaHR0cHM6Ly93d3cucWlkYW8xMjMuY29tL2Jicy8iIC8+Cgk8IS0tey9pZn0tLT4KCXJgbmB0PG1ldGEgbmFtZT0iYXBwbGljYXRpb24tbmFtZSIgY29udGVudD0iJF9HWydzZXR0aW5nJ11bJ2JibmFtZSddIiAvPgoJPG1ldGEgbmFtZT0ibXNhcHBsaWNhdGlvbi10b29sdGlwIiBjb250ZW50PSIkX0dbJ3NldHRpbmcnXVsnYmJuYW1lJ10iIC8+Cgk8IS0te2lmICRfR1snc2V0dGluZyddWydwb3J0YWxzdGF0dXMnXX0tLT48bWV0YSBuYW1lPSJtc2FwcGxpY2F0aW9uLXRhc2siIGNvbnRlbnQ9Im5hbWU9JF9HWydzZXR0aW5nJ11bJ25hdnMnXVsxXVsnbmF2bmFtZSddO2FjdGlvbi11cmk9e2VjaG8gIWVtcHR5KCRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ3BvcnRhbCddKSA/ICRfR1snc2NoZW1lJ10uJzovLycuJF9HWydzZXR0aW5nJ11bJ2RvbWFpbiddWydhcHAnXVsncG9ydGFsJ10gOiAkX0dbc2l0ZXVybF0uJ3BvcnRhbC5waHAnfTtpY29uLXVyaT17JF9HW3NpdGV1cmxdfXtJTUdESVJ9L3BvcnRhbC5pY28iIC8+PCEtLXsvaWZ9LS0+Cgk8bWV0YSBuYW1lPSJtc2FwcGxpY2F0aW9uLXRhc2siIGNvbnRlbnQ9Im5hbWU9JF9HWydzZXR0aW5nJ11bJ25hdnMnXVsyXVsnbmF2bmFtZSddO2FjdGlvbi11cmk9e2VjaG8gIWVtcHR5KCRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2ZvcnVtJ10pID8gJF9HWydzY2hlbWUnXS4nOi8vJy4kX0dbJ3NldHRpbmcnXVsnZG9tYWluJ11bJ2FwcCddWydmb3J1bSddIDogJF9HW3NpdGV1cmxdLidmb3J1bS5waHAnfTtpY29uLXVyaT17JF9HW3NpdGV1cmxdfXtJTUdESVJ9L2Jicy5pY28iIC8+Cgk8IS0te2lmICRfR1snc2V0dGluZyddWydncm91cHN0YXR1cyddfS0tPjxtZXRhIG5hbWU9Im1zYXBwbGljYXRpb24tdGFzayIgY29udGVudD0ibmFtZT0kX0dbJ3NldHRpbmcnXVsnbmF2cyddWzNdWyduYXZuYW1lJ107YWN0aW9uLXVyaT17ZWNobyAhZW1wdHkoJF9HWydzZXR0aW5nJ11bJ2RvbWFpbiddWydhcHAnXVsnZ3JvdXAnXSkgPyAkX0dbJ3NjaGVtZSddLic6Ly8nLiRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2dyb3VwJ10gOiAkX0dbc2l0ZXVybF0uJ2dyb3VwLnBocCd9O2ljb24tdXJpPXskX0dbc2l0ZXVybF19e0lNR0RJUn0vZ3JvdXAuaWNvIiAvPjwhLS17L2lmfS0tPgoJPCEtLXtpZiBoZWxwZXJfYWNjZXNzOjpjaGVja19tb2R1bGUoJ2ZlZWQnKX0tLT48bWV0YSBuYW1lPSJtc2FwcGxpY2F0aW9uLXRhc2siIGNvbnRlbnQ9Im5hbWU9JF9HWydzZXR0aW5nJ11bJ25hdnMnXVs0XVsnbmF2bmFtZSddO2FjdGlvbi11cmk9e2VjaG8gIWVtcHR5KCRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2hvbWUnXSkgPyAkX0dbJ3NjaGVtZSddLic6Ly8nLiRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2hvbWUnXSA6ICRfR1tzaXRldXJsXS4naG9tZS5waHAnfTtpY29uLXVyaT17JF9HW3NpdGV1cmxdfXtJTUdESVJ9L2hvbWUuaWNvIiAvPjwhLS17L2lmfS0tPgoJPCEtLXtpZiAkX0dbJ2Jhc2VzY3JpcHQnXSA9PSAnZm9ydW0nICYmICRfR1snc2V0dGluZyddWydhcmNoaXZlciddfS0tPgoJCTxsaW5rIHJlbD0iYXJjaGl2ZXMiIHRpdGxlPSIkX0dbJ3NldHRpbmcnXVsnYmJuYW1lJ10iIGhyZWY9InskX0dbc2l0ZXVybF19YXJjaGl2ZXIvIiAvPgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmICFlbXB0eSgkcnNzaGVhZCl9LS0+JHJzc2hlYWQ8IS0tey9pZn0tLT4KCTwhLS17aWYgd2lkdGhhdXRvKCl9LS0+CgkJPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBpZD0iY3NzX3dpZHRoYXV0byIgdHlwZT0idGV4dC9jc3MiIGhyZWY9J3skX0dbJ3NldHRpbmcnXVsnY3NzcGF0aCddfXtTVFlMRUlEfV93aWR0aGF1dG8uY3NzP3tWRVJIQVNIfScgLz4KCQk8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+SFRNTE5PREUuY2xhc3NOYW1lICs9ICcgd2lkdGhhdXRvJzwvc2NyaXB0PgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmICRfR1snYmFzZXNjcmlwdCddID09ICdmb3J1bScgfHwgJF9HWydiYXNlc2NyaXB0J10gPT0gJ2dyb3VwJ30tLT4KCQk8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSJ7JF9HW3NldHRpbmddW2pzcGF0aF19Zm9ydW0uanM/e1ZFUkhBU0h9Ij48L3NjcmlwdD4KCTwhLS17ZWxzZWlmICRfR1snYmFzZXNjcmlwdCddID09ICdob21lJ30tLT4KCQk8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCIgc3JjPSJ7JF9HW3NldHRpbmddW2pzcGF0aF19aG9tZS5qcz97VkVSSEFTSH0iPjwvc2NyaXB0PgoJPCEtLXtlbHNlaWYgJF9HWydiYXNlc2NyaXB0J10gPT0gJ3BvcnRhbCd9LS0+CgkJPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiIHNyYz0ieyRfR1tzZXR0aW5nXVtqc3BhdGhdfXBvcnRhbC5qcz97VkVSSEFTSH0iPjwvc2NyaXB0PgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmICRfR1snYmFzZXNjcmlwdCddICE9ICdwb3J0YWwnICYmICRfR0VUWydkaXknXSA9PSAneWVzJyAmJiBjaGVja19kaXlfcGVybSgkdG9waWMpfS0tPgoJCTxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9InskX0dbc2V0dGluZ11banNwYXRoXX1wb3J0YWwuanM/e1ZFUkhBU0h9Ij48L3NjcmlwdD4KCTwhLS17L2lmfS0tPgoJPCEtLXtpZiAkX0dFVFsnZGl5J10gPT0gJ3llcycgJiYgY2hlY2tfZGl5X3Blcm0oJHRvcGljKX0tLT4KCQk8bGluayByZWw9InN0eWxlc2hlZXQiIHR5cGU9InRleHQvY3NzIiBpZD0iZGl5X2NvbW1vbiIgaHJlZj0ieyRfR1snc2V0dGluZyddWydjc3NwYXRoJ119e1NUWUxFSUR9X2Nzc19kaXkuY3NzP3tWRVJIQVNIfSIgLz4KCTwhLS17L2lmfS0tPgo8L2hlYWQ+Cgo8Ym9keSBpZD0ibnZfeyRfR1tiYXNlc2NyaXB0XX0iIGNsYXNzPSJwZ197Q1VSTU9EVUxFfXtpZiAkX0dbJ2Jhc2VzY3JpcHQnXSA9PT0gJ3BvcnRhbCcgJiYgQ1VSTU9EVUxFID09PSAnbGlzdCcgJiYgIWVtcHR5KCRjYXQpfSB7JGNhdFsnYm9keWNzcyddfXsvaWZ9IiBvbmtleWRvd249ImlmKGV2ZW50LmtleUNvZGU9PTI3KSByZXR1cm4gZmFsc2U7Ij4KCTxkaXYgaWQ9ImFwcGVuZF9wYXJlbnQiPjwvZGl2PjxkaXYgaWQ9ImFqYXh3YWl0aWQiPjwvZGl2PgoJPCEtLXtpZiAkX0dFVFsnZGl5J10gPT0gJ3llcycgJiYgY2hlY2tfZGl5X3Blcm0oJHRvcGljKX0tLT4KCQk8IS0te3RlbXBsYXRlIGNvbW1vbi9oZWFkZXJfZGl5fS0tPgoJPCEtLXsvaWZ9LS0+Cgk8IS0te2lmIGNoZWNrX2RpeV9wZXJtKCR0b3BpYyl9LS0+CgkJPCEtLXt0ZW1wbGF0ZSBjb21tb24vaGVhZGVyX2RpeW5hdn0tLT4KCTwhLS17L2lmfS0tPgoJPCEtLXtpZiBDVVJNT0RVTEUgPT0gJ3RvcGljJyAmJiAkdG9waWMgJiYgZW1wdHkoJHRvcGljWyd1c2VoZWFkZXInXSkgJiYgY2hlY2tfZGl5X3Blcm0oJHRvcGljKX0tLT4KCQkkZGl5bmF2Cgk8IS0tey9pZn0tLT4KCTwhLS17aWYgZW1wdHkoJHRvcGljKSB8fCAkdG9waWNbJ3VzZWhlYWRlciddfS0tPgoJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ21vYmlsZSddWydhbGxvd21vYmlsZSddICYmICghJF9HWydzZXR0aW5nJ11bJ2NhY2hlaW5kZXhsaWZlJ10gJiYgISRfR1snc2V0dGluZyddWydjYWNoZXRocmVhZG9uJ10gfHwgJF9HWyd1aWQnXSkgJiYgKCRfR0VUWydkaXknXSAhPSAneWVzJyB8fCAhJF9HRVRbJ2luYWpheCddKSAmJiAoJF9HWydtb2JpbGUnXSAhPSAnJyAmJiAkX0dbJ2Nvb2tpZSddWydtb2JpbGUnXSA9PSAnJyAmJiAkX0dFVFsnbW9iaWxlJ10gIT0gJ25vJyl9LS0+CgkJCTxkaXYgY2xhc3M9InhpMSBibSBibV9jIj4KCQkJICAgIHtsYW5nIHlvdXJfbW9iaWxlX2Jyb3dzZXJ9PGEgaHJlZj0ieyRfR1snc2l0ZXVybCddfWZvcnVtLnBocD9tb2JpbGU9eWVzIj57bGFuZyBnb190b19tb2JpbGV9PC9hPiA8c3BhbiBjbGFzcz0ieGcxIj58PC9zcGFuPiA8YSBocmVmPSIkX0dbJ3NldHRpbmcnXVsnbW9iaWxlJ11bJ25vbW9iaWxldXJsJ10iPntsYW5nIHRvX2JlX2NvbnRpbnVlfTwvYT4KCQkJPC9kaXY+CgkJPCEtLXsvaWZ9LS0+CgkJPCEtLXtpZiAhZW1wdHkoJF9HWydzZXR0aW5nJ11bJ3Nob3J0Y3V0J10pICYmICRfR1snbWVtYmVyJ11bY3JlZGl0c10gPj0gJF9HWydzZXR0aW5nJ11bJ3Nob3J0Y3V0J119LS0+CgkJCTxkaXYgaWQ9InNob3J0Y3V0Ij4KCQkJCTxzcGFuPjxhIGhyZWY9ImphdmFzY3JpcHQ6OyIgaWQ9InNob3J0Y3V0Y2xvc2VpZCIgdGl0bGU9IntsYW5nIGNsb3NlfSI+e2xhbmcgY2xvc2V9PC9hPjwvc3Bhbj4KCQkJCXtsYW5nIHNob3J0Y3V0X25vdGljZX0KCQkJCTxhIGhyZWY9ImphdmFzY3JpcHQ6OyIgaWQ9InNob3J0Y3V0dGlwIj57bGFuZyBzaG9ydGN1dF9hZGR9PC9hPgoKCQkJPC9kaXY+CgkJCTxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij5zZXRUaW1lb3V0KHNldFNob3J0Y3V0LCAyMDAwKTs8L3NjcmlwdD4KCQk8IS0tey9pZn0tLT4KCQk8ZGl2IGlkPSJ0b3B0YiIgY2xhc3M9ImNsIj4KCQkJPCEtLXtob29rL2dsb2JhbF9jcG5hdl90b3B9LS0+CgkJCTxkaXYgY2xhc3M9IndwIj4KCQkJCTxkaXYgY2xhc3M9InoiPgoJCQkJCTwhLS17bG9vcCAkX0dbJ3NldHRpbmcnXVsndG9wbmF2cyddWzBdICRuYXZ9LS0+CgkJCQkJCTwhLS17aWYgaXNfYXJyYXkoJG5hdikgJiYgJG5hdlsnYXZhaWxhYmxlJ10gJiYgKCEkbmF2WydsZXZlbCddIHx8ICgkbmF2WydsZXZlbCddID09IDEgJiYgJF9HWyd1aWQnXSkgfHwgKCRuYXZbJ2xldmVsJ10gPT0gMiAmJiAkX0dbJ2FkbWluaWQnXSA+IDApIHx8ICgkbmF2WydsZXZlbCddID09IDMgJiYgJF9HWydhZG1pbmlkJ10gPT0gMSkpfS0tPiRuYXZbY29kZV08IS0tey9pZn0tLT4KCQkJCQk8IS0tey9sb29wfS0tPgoJCQkJCTwhLS17aG9vay9nbG9iYWxfY3BuYXZfZXh0cmExfS0tPgoJCQkJPC9kaXY+CgkJCQk8ZGl2IGNsYXNzPSJ5Ij4KCQkJCQk8YSBpZD0ic3dpdGNoYmxpbmQiIGhyZWY9ImphdmFzY3JpcHQ6OyIgb25jbGljaz0idG9nZ2xlQmxpbmQodGhpcykiIHRpdGxlPSJ7bGFuZyBzd2l0Y2hfYmxpbmR9IiBjbGFzcz0ic3dpdGNoYmxpbmQiPjwvYT4KCQkJCQk8IS0te2hvb2svZ2xvYmFsX2NwbmF2X2V4dHJhMn0tLT4KCQkJCQk8IS0te2xvb3AgJF9HWydzZXR0aW5nJ11bJ3RvcG5hdnMnXVsxXSAkbmF2fS0tPgoJCQkJCQk8IS0te2lmIGlzX2FycmF5KCRuYXYpICYmICRuYXZbJ2F2YWlsYWJsZSddICYmICghJG5hdlsnbGV2ZWwnXSB8fCAoJG5hdlsnbGV2ZWwnXSA9PSAxICYmICRfR1sndWlkJ10pIHx8ICgkbmF2WydsZXZlbCddID09IDIgJiYgJF9HWydhZG1pbmlkJ10gPiAwKSB8fCAoJG5hdlsnbGV2ZWwnXSA9PSAzICYmICRfR1snYWRtaW5pZCddID09IDEpKX0tLT4kbmF2W2NvZGVdPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXsvbG9vcH0tLT4KCQkJCQk8IS0te2lmIGVtcHR5KCRfR1snZGlzYWJsZWR3aWR0aGF1dG8nXSkgJiYgJF9HWydzZXR0aW5nJ11bJ3N3aXRjaHdpZHRoYXV0byddfS0tPgoJCQkJCQk8YSBocmVmPSJqYXZhc2NyaXB0OjsiIGlkPSJzd2l0Y2h3aWR0aCIgb25jbGljaz0id2lkdGhhdXRvKHRoaXMpIiB0aXRsZT0ie2lmIHdpZHRoYXV0bygpfXtsYW5nIHN3aXRjaF9uYXJyb3d9e2Vsc2V9e2xhbmcgc3dpdGNoX3dpZGV9ey9pZn0iIGNsYXNzPSJzd2l0Y2h3aWR0aCI+PCEtLXtpZiB3aWR0aGF1dG8oKX0tLT57bGFuZyBzd2l0Y2hfbmFycm93fTwhLS17ZWxzZX0tLT57bGFuZyBzd2l0Y2hfd2lkZX08IS0tey9pZn0tLT48L2E+CgkJCQkJPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXtpZiAkX0dbJ3VpZCddICYmICFlbXB0eSgkX0dbJ3N0eWxlJ11bJ2V4dHN0eWxlJ10pfS0tPjxhIGlkPSJzc2xjdCIgaHJlZj0iamF2YXNjcmlwdDo7IiBvbm1vdXNlb3Zlcj0iZGVsYXlTaG93KHRoaXMsIGZ1bmN0aW9uKCkge3Nob3dNZW51KHsnY3RybGlkJzonc3NsY3QnLCdwb3MnOiczNCEnfSl9KTsiPntsYW5nIGNoYW5nZXN0eWxlfTwvYT48IS0tey9pZn0tLT4KCQkJCQk8IS0te2lmIGNoZWNrX2RpeV9wZXJtKCR0b3BpYyl9LS0+CgkJCQkJCSRkaXluYXYKCQkJCQk8IS0tey9pZn0tLT4KCQkJCTwvZGl2PgoJCQk8L2Rpdj4KCQk8L2Rpdj4KCgkJPCEtLXtpZiAhSVNfUk9CT1R9LS0+CgkJCTwhLS17aWYgJF9HWyd1aWQnXSAmJiAhJF9HWydzZXR0aW5nJ11bJ2JiY2xvc2VkJ10gJiYgZW1wdHkoJF9HWydtZW1iZXInXVsnZnJlZXplJ10pICYmICRfR1snbWVtYmVyJ11bJ2dyb3VwaWQnXSAhPSA1fS0tPgoJCQk8dWwgaWQ9Im15cHJvbXB0X21lbnUiIGNsYXNzPSJwX3BvcCIgc3R5bGU9ImRpc3BsYXk6IG5vbmU7Ij4KCQkJCTxsaT48YSBocmVmPSJob21lLnBocD9tb2Q9c3BhY2UmZG89cG0iIGlkPSJwbV9udGMiIHN0eWxlPSJiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0OyBiYWNrZ3JvdW5kLXBvc2l0aW9uOiAwIDUwJTsiPjxlbSBjbGFzcz0icHJvbXB0X25ld3N7aWYgZW1wdHkoJF9HW21lbWJlcl1bbmV3cG1dKX1fMHsvaWZ9Ij48L2VtPntsYW5nIHBtX2NlbnRlcn08L2E+PC9saT4KCQkJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ2ZvbGxvd3N0YXR1cyddfS0tPgoJCQkJCTxsaT48YSBocmVmPSJob21lLnBocD9tb2Q9Zm9sbG93JmRvPWZvbGxvd2VyIj48ZW0gY2xhc3M9InByb21wdF9mb2xsb3dlcntpZiBlbXB0eSgkX0dbbWVtYmVyXVtuZXdwcm9tcHRfbnVtXVtmb2xsb3dlcl0pfV8wey9pZn0iPjwvZW0+PCEtLXtsYW5nIG5vdGljZV9pbnRlcmFjdGl2ZV9mb2xsb3dlcn0tLT57aWYgJF9HW21lbWJlcl1bbmV3cHJvbXB0X251bV1bZm9sbG93ZXJdfSgkX0dbbWVtYmVyXVtuZXdwcm9tcHRfbnVtXVtmb2xsb3dlcl0pey9pZn08L2E+PC9saT4KCQkJCQk8IS0te2lmICRfR1ttZW1iZXJdW25ld3Byb21wdF0gJiYgJF9HW21lbWJlcl1bbmV3cHJvbXB0X251bV1bZm9sbG93XX0tLT4KCQkJCQkJPGxpPjxhIGhyZWY9ImhvbWUucGhwP21vZD1mb2xsb3ciPjxlbSBjbGFzcz0icHJvbXB0X2NvbmNlcm4iPjwvZW0+PCEtLXtsYW5nIG5vdGljZV9pbnRlcmFjdGl2ZV9mb2xsb3d9LS0+KCRfR1ttZW1iZXJdW25ld3Byb21wdF9udW1dW2ZvbGxvd10pPC9hPjwvbGk+CgkJCQkJPCEtLXsvaWZ9LS0+CgkJCQk8IS0tey9pZn0tLT4KCQkJCTwhLS17aWYgJF9HW21lbWJlcl1bbmV3cHJvbXB0XX0tLT4KCQkJCQk8IS0te2xvb3AgJF9HWydtZW1iZXInXVsnY2F0ZWdvcnlfbnVtJ10gJGtleSAkdmFsfS0tPgoJCQkJCQk8bGk+PGEgaHJlZj0iaG9tZS5waHA/bW9kPXNwYWNlJmRvPW5vdGljZSZ2aWV3PSRrZXkiPjxlbSBjbGFzcz0ibm90aWNlXyRrZXkiPjwvZW0+PCEtLXtlY2hvIGxhbmcoJ3RlbXBsYXRlJywgJ25vdGljZV8nLiRrZXkpfS0tPig8c3BhbiBjbGFzcz0icnEiPiR2YWw8L3NwYW4+KTwvYT48L2xpPgoJCQkJCTwhLS17L2xvb3B9LS0+CgkJCQk8IS0tey9pZn0tLT4KCQkJCTwhLS17aWYgZW1wdHkoJF9HWydjb29raWUnXVsnaWdub3JlX25vdGljZSddKX0tLT4KCQkJCQk8bGkgY2xhc3M9Imlnbm9yZV9ub3RpY2VsaSI+PGEgaHJlZj0iamF2YXNjcmlwdDo7IiBvbmNsaWNrPSJzZXRjb29raWUoJ2lnbm9yZV9ub3RpY2UnLCAxKTtoaWRlTWVudSgnbXlwcm9tcHRfbWVudScpIiB0aXRsZT0ie2xhbmcgdGVtcG9yYXJpbHlfdG9fcmVtaW5kfSI+PGVtIGNsYXNzPSJpZ25vcmVfbm90aWNlIj48L2VtPjwvYT48L2xpPgoJCQkJPCEtLXsvaWZ9LS0+CgkJCTwvdWw+CgkJCTwhLS17L2lmfS0tPgoJCQk8IS0te2lmICRfR1sndWlkJ10gJiYgIWVtcHR5KCRfR1snc3R5bGUnXVsnZXh0c3R5bGUnXSl9LS0+CgkJCQk8ZGl2IGlkPSJzc2xjdF9tZW51IiBjbGFzcz0iY2wgcF9wb3AiIHN0eWxlPSJkaXNwbGF5OiBub25lOyI+CgkJCQkJPCEtLXtpZiAhJF9HW3N0eWxlXVtkZWZhdWx0ZXh0c3R5bGVdfS0tPjxzcGFuIGNsYXNzPSJzc2xjdF9idG4iIG9uY2xpY2s9ImV4dHN0eWxlKCcnKSIgdGl0bGU9IntsYW5nIGRlZmF1bHR9Ij48aT48L2k+PC9zcGFuPjwhLS17L2lmfS0tPgoJCQkJCTwhLS17bG9vcCAkX0dbJ3N0eWxlJ11bJ2V4dHN0eWxlJ10gJGV4dHN0eWxlfS0tPgoJCQkJCQk8c3BhbiBjbGFzcz0ic3NsY3RfYnRuIiBvbmNsaWNrPSJleHRzdHlsZSgnJGV4dHN0eWxlWzBdJykiIHRpdGxlPSIkZXh0c3R5bGVbMV0iPjxpIHN0eWxlPSdiYWNrZ3JvdW5kOiRleHRzdHlsZVsyXSc+PC9pPjwvc3Bhbj4KCQkJCQk8IS0tey9sb29wfS0tPgoJCQkJPC9kaXY+CgkJCTwhLS17L2lmfS0tPgoJCQk8IS0te2lmICRfR1sndWlkJ119LS0+CgkJCQk8dWwgaWQ9Im15aXRlbV9tZW51IiBjbGFzcz0icF9wb3AiIHN0eWxlPSJkaXNwbGF5OiBub25lOyI+CgkJCQkJPCEtLXtpZiAkX0dbJ3NldHRpbmcnXVsnZm9ydW1zdGF0dXMnXX0tLT48bGk+PGEgaHJlZj0iaG9tZS5waHA/bW9kPXNwYWNlJmRvPXRocmVhZCZ2aWV3PW1lIj57bGFuZyBteXBvc3R9PC9hPjwvbGk+PCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXtpZiAkX0dbJ3NldHRpbmcnXVsnZmF2b3JpdGVzdGF0dXMnXX0tLT48bGk+PGEgaHJlZj0iaG9tZS5waHA/bW9kPXNwYWNlJmRvPWZhdm9yaXRlJnZpZXc9bWUiPntsYW5nIGZhdm9yaXRlfTwvYT48L2xpPjwhLS17L2lmfS0tPgoJCQkJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ2ZyaWVuZHN0YXR1cyddfS0tPjxsaT48YSBocmVmPSJob21lLnBocD9tb2Q9c3BhY2UmZG89ZnJpZW5kIj57bGFuZyBmcmllbmRzfTwvYT48L2xpPjwhLS17L2lmfS0tPgoJCQkJCTwhLS17aG9vay9nbG9iYWxfbXlpdGVtX2V4dHJhfS0tPgoJCQkJPC91bD4KCQkJPCEtLXsvaWZ9LS0+CgkJCTwhLS17c3VidGVtcGxhdGUgY29tbW9uL2hlYWRlcl9xbWVudX0tLT4KCQk8IS0tey9pZn0tLT4KCgkJPCEtLXthZC9oZWFkZXJiYW5uZXIvd3AgYV9ofS0tPgoJCTxkaXYgaWQ9ImhkIj4KCQkJPGRpdiBjbGFzcz0id3AiPgoJCQkJPGRpdiBjbGFzcz0iaGRjIGNsIj4KCQkJCQk8IS0te2V2YWwgJG1uaWQgPSBnZXRjdXJyZW50bmF2KCk7fS0tPgoJCQkJCTxoMj48IS0te2lmICFpc3NldCgkX0dbJ3NldHRpbmcnXVsnbmF2bG9nb3MnXVskbW5pZF0pfS0tPjxhIGhyZWY9IntpZiAkX0dbJ3NldHRpbmcnXVsnZG9tYWluJ11bJ2FwcCddWydkZWZhdWx0J119eyRfR1snc2NoZW1lJ119Oi8veyRfR1snc2V0dGluZyddWydkb21haW4nXVsnYXBwJ11bJ2RlZmF1bHQnXX0ve2Vsc2V9Li97L2lmfSIgdGl0bGU9IiRfR1snc2V0dGluZyddWydiYm5hbWUnXSI+eyRfR1snc3R5bGUnXVsnYm9hcmRsb2dvJ119PC9hPjwhLS17ZWxzZX0tLT4kX0dbJ3NldHRpbmcnXVsnbmF2bG9nb3MnXVskbW5pZF08IS0tey9pZn0tLT48L2gyPgoJCQkJCTwhLS17dGVtcGxhdGUgY29tbW9uL2hlYWRlcl91c2Vyc3RhdHVzfS0tPgoJCQkJPC9kaXY+CgoJCQkJPGRpdiBpZD0ibnYiPgoJCQkJCTxhIGhyZWY9ImphdmFzY3JpcHQ6OyIgaWQ9InFtZW51IiBvbm1vdXNlb3Zlcj0iZGVsYXlTaG93KHRoaXMsIGZ1bmN0aW9uICgpIHtzaG93TWVudSh7J2N0cmxpZCc6J3FtZW51JywncG9zJzonMzQhJywnY3RybGNsYXNzJzonYScsJ2R1cmF0aW9uJzoyfSk7c2hvd0ZvcnVtbWVudSgkX0dbZmlkXSk7fSkiPntsYW5nIG15X25hdn08L2E+CgkJCQkJPHVsPgoJCQkJCQk8IS0te2xvb3AgJF9HWydzZXR0aW5nJ11bJ25hdnMnXSAkbmF2fS0tPgoJCQkJCQkJPCEtLXtpZiBpc19hcnJheSgkbmF2KSAmJiAkbmF2WydhdmFpbGFibGUnXSAmJiAoISRuYXZbJ2xldmVsJ10gfHwgKCRuYXZbJ2xldmVsJ10gPT0gMSAmJiAkX0dbJ3VpZCddKSB8fCAoJG5hdlsnbGV2ZWwnXSA9PSAyICYmICRfR1snYWRtaW5pZCddID4gMCkgfHwgKCRuYXZbJ2xldmVsJ10gPT0gMyAmJiAkX0dbJ2FkbWluaWQnXSA9PSAxKSl9LS0+PGxpIHtpZiAkbW5pZCA9PSAkbmF2W25hdmlkXSB8fCBzdWJzdHIoJF9TRVJWRVJbJ1JFUVVFU1RfVVJJJ10sIDEpID09IHN0cl9yZXBsYWNlKCcuLycsICcnLCAkbmF2W2ZpbGVuYW1lXSl9Y2xhc3M9ImEiIHsvaWZ9JG5hdltuYXZdPjwvbGk+PCEtLXsvaWZ9LS0+CgkJCQkJCTwhLS17L2xvb3B9LS0+CgkJCQkJPC91bD4KCQkJCQk8IS0te2hvb2svZ2xvYmFsX25hdl9leHRyYX0tLT4KCQkJCTwvZGl2PgoJCQkJPCEtLXtpZiAhZW1wdHkoJF9HWydzZXR0aW5nJ11bJ3BsdWdpbnMnXVsnanNtZW51J10pfS0tPgoJCQkJCTx1bCBjbGFzcz0icF9wb3AgaF9wb3AiIGlkPSJwbHVnaW5fbWVudSIgc3R5bGU9ImRpc3BsYXk6IG5vbmUiPgoJCQkJCTwhLS17bG9vcCAkX0dbJ3NldHRpbmcnXVsncGx1Z2lucyddWydqc21lbnUnXSAkbW9kdWxlfS0tPgoJCQkJCQkgPCEtLXtpZiBpbl9hcnJheSgkbW9kdWxlWydhZG1pbmlkJ10sIGFycmF5KDAsIC0xKSkgfHwgKCRtb2R1bGVbJ2FkbWluaWQnXSAmJiAkX0dbJ2FkbWluaWQnXSA+IDAgJiYgJG1vZHVsZVsnYWRtaW5pZCddID49ICRfR1snYWRtaW5pZCddKX0tLT4KCQkJCQkJIDxsaT4kbW9kdWxlW3VybF08L2xpPgoJCQkJCQkgPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXsvbG9vcH0tLT4KCQkJCQk8L3VsPgoJCQkJPCEtLXsvaWZ9LS0+CgkJCQkkX0dbc2V0dGluZ11bbWVudW5hdnNdCgkJCQk8ZGl2IGlkPSJtdSIgY2xhc3M9ImNsIj4KCQkJCTwhLS17aWYgJF9HWydzZXR0aW5nJ11bJ3N1Ym5hdnMnXX0tLT4KCQkJCQk8IS0te2xvb3AgJF9HW3NldHRpbmddW3N1Ym5hdnNdICRuYXZpZCAkc3VibmF2fS0tPgoJCQkJCQk8IS0te2lmICRfR1snc2V0dGluZyddWyduYXZzdWJob3ZlciddIHx8ICRtbmlkID09ICRuYXZpZH0tLT4KCQkJCQkJPHVsIGNsYXNzPSJjbCB7aWYgJG1uaWQgPT0gJG5hdmlkfWN1cnJlbnR7L2lmfSIgaWQ9InNuYXZfJG5hdmlkIntpZiAkbW5pZCAhPSAkbmF2aWR9IHN0eWxlPSJkaXNwbGF5Om5vbmUiey9pZn0+CgkJCQkJCSRzdWJuYXYKCQkJCQkJPC91bD4KCQkJCQkJPCEtLXsvaWZ9LS0+CgkJCQkJPCEtLXsvbG9vcH0tLT4KCQkJCTwhLS17L2lmfS0tPgoJCQkJPC9kaXY+CgkJCQk8IS0te2FkL3N1Ym5hdmJhbm5lci9hX211fS0tPgoJCQkJPCEtLXtzdWJ0ZW1wbGF0ZSBjb21tb24vcHVic2VhcmNoZm9ybX0tLT4KCQkJPC9kaXY+CgkJPC9kaXY+CgoJCTwhLS17aG9vay9nbG9iYWxfaGVhZGVyfS0tPgoJPCEtLXsvaWZ9LS0+CgoJPGRpdiBpZD0id3AiIGNsYXNzPSJ3cCI+Cg==
qidao123.com ToB IT社区-企服评测·应用市场»论坛 › 容器及微服务 › 容器及微服务 › [kubernetes]二进制方式部署单机k8s-v1.30.5
返回列表 发新帖

[kubernetes]二进制方式部署单机k8s-v1.30.5

[复制链接]
发表于 2024-10-5 15:25:15 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
媒介

之前在单机测试k8s的kind最近故障了,虚拟机运行个几分钟后就宕机了,不知道是根因是什么,而且kind部署k8s不太好做一些个性化设置,干脆用二进制方式重新搭一个单机k8s。
因为是用来开辟测试的,所以control-panel就不做高可用了,etcd+apiserver+controller-manager+scheduler都只有一个实例。
情况信息:

  • 主机:Debian 12.7,4核CPU、4GB内存、30GB存储(只是部署一个k8s的话,2C2G的设置也足够)
  • 容器运行时:containerd v1.7.22
  • etcd: v3.4.34
  • kubernetes:v1.30.5
  • cni: calico v3.25.0
本文中的大部门设置文件已上传到gitee - k8s-note,目录为"安装k8s/二进制单机部署k8s-v1.30.5",如有需要可直接clone repo.
准备

本节下令大部门都要root权限,如果执行下令时提示权限不足,可自行切换root用户或利用sudo。
调解主机参数


  • 修改主机名。kubernetes要求每个节点的hostname不一样
  1. hostnamectl set-hostname k8s-node1
复制代码

  • 修改/etc/hosts文件。如果内网有自建DNS可忽略
  1. 192.168.0.31 k8s-node1
复制代码

  • 安装时间同步服务。如果有多台主机,要注意主机之间的时间要同步。内网如果有时间同步服务器,可以修改chrony的设置来指向内网时间同步服务器
  1. sudo apt install -y chrony
  2. sudo systemctl start chrony
复制代码

  • 关闭swap。默认情况下,k8s没法在利用swap的主机上运行。这里用的临时关闭下令,固化设置需要修改/etc/fstab文件,将swap干系设置行删除或解释。
  1. sudo swapoff -a
复制代码

  • 装载内核模块。这步没做的话,下一步设置系统参数会报错。
  1. # 1. 添加配置
  2. cat <<EOF > /etc/modules-load.d/containerd.conf
  3. overlay
  4. br_netfilter
  5. EOF
  6. # 2. 立即装载
  7. modprobe overlay
  8. modprobe br_netfilter
  9. # 3. 检查装载。如果没有输出结果则说明没有装载成功。
  10. lsmod | grep br_netfilter
复制代码

  • 编辑设置文件/etc/containerd/config.toml,修改以下内容
  1. # 1. 添加配置文件
  2. cat << EOF > /etc/sysctl.d/k8s-sysctl.conf
  3. net.bridge.bridge-nf-call-ip6tables = 1
  4. net.bridge.bridge-nf-call-iptables = 1
  5. net.ipv4.ip_forward = 1
  6. user.max_user_namespaces=28633
  7. vm.swappiness = 0
  8. EOF
  9. # 2. 配置生效
  10. sysctl -p /etc/sysctl.d/k8s-sysctl.conf
复制代码

  • 启动containerd
  1. # 1. 安装依赖
  2. apt install -y ipset ipvsadm
  3. # 2. 立即装载
  4. modprobe -- ip_vs
  5. modprobe -- ip_vs_rr
  6. modprobe -- ip_vs_wrr
  7. modprobe -- ip_vs_sh
  8. modprobe -- nf_conntrack
  9. # 3. 固化到配置文件
  10. cat << EOF > /etc/modules-load.d/ipvs.conf
  11. ip_vs
  12. ip_vs_rr
  13. ip_vs_wrr
  14. ip_vs_sh
  15. nf_conntrack
  16. EOF
  17. # 4. 检查是否已装载
  18. lsmod |grep ip_vs
复制代码

  • 执行下令测试下containerd是否正常。没报错一般就是正常的
  1. tar xf cri-containerd-cni-1.7.22-linux-amd64.tar.gz -C /
复制代码
天生ca证书

后面的k8s和etcd集群都会用到ca证书。如果组织能提供统一的CA认证中心,则直接利用组织颁发的CA证书即可。如果没有统一的CA认证中心,则可以通过颁发自签名的CA证书来完成安全设置。这里自行天生一个ca证书。
  1. mkdir /etc/containerd
  2. containerd config default > /etc/containerd/config.toml
复制代码
安装etcd

etcd的安装包可以从官网下载,下载后解压。可以将压缩包中的etcd和etcdctl放到情况变量PATH中的目录。

  • 编辑文件etcd_ssl.cnf。IP地址为etcd节点。
  1. # 对于使用systemd作为init system的linux发行版,官方建议用systemd作为容器cgroup driver
  2. # false改成true
  3. SystemdCgroup = true
  4. # pause镜像的地址改为自己在阿里云上传的镜像地址。如果是内网环境,可改为内网registry的地址
  5. sandbox_image = "registry.cn-hangzhou.aliyuncs.com/rainux/pause:3.9"
复制代码

  • 创建etcd服务端证书
  1. systemctl start containerd
  2. systemctl enable containerd
复制代码

  • 创建etcd客户端证书
  1. crictl images
复制代码

  • 编辑etcd的设置文件。目录、文件路径,IP、端口等信息按实际情况修改
  1. # 生成私钥文件ca.key
  2. openssl genrsa -out ca.key 2048
  3. # 根据私钥文件生成根证书文件ca.crt
  4. # /CN为master的主机名或IP地址
  5. # days为证书的有效期
  6. openssl req -x509 -new -nodes -key ca.key -subj "/CN=k8s-node1" -days 36500 -out ca.crt
  7. # 拷贝ca证书到/etc/kubernetes/pki
  8. mkdir -p /etc/kubernetes/pki
  9. cp ca.crt ca.key /etc/kubernetes/pki/
复制代码

  • 编辑/etc/systemd/system/etcd.service,注意根据实际修改设置文件和etcd二进制文件的路径
  1. [ req ]
  2. req_extensions = v3_req
  3. distinguished_name = req_distinguished_name
  4. [ req_distinguished_name ]
  5. [ v3_req ]
  6. basicConstraints = CA:FALSE
  7. keyUsage = nonRepudiation, digitalSignature, keyEncipherment
  8. subjectAltName = @alt_names
  9. [ alt_names ]
  10. IP.1 = 192.168.0.31
复制代码

  • 启动etcd
  1. openssl genrsa -out etcd_server.key 2048
  2. openssl req -new -key etcd_server.key -config etcd_ssl.cnf -subj "/CN=etcd-server" -out etcd_server.csr
  3. openssl x509 -req -in etcd_server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -extensions v3_req -extfile etcd_ssl.cnf -out etcd_server.crt
复制代码

  • 利用etcd客户端验证下etcd状态
  1. openssl genrsa -out etcd_client.key 2048
  2. openssl req -new -key etcd_client.key -config etcd_ssl.cnf -subj "/CN=etcd-client" -out etcd_client.csr
  3. openssl x509 -req -in etcd_client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -extensions v3_req -extfile etcd_ssl.cnf -out etcd_client.crt
复制代码
安装control-panel

k8s的二进制文件安装包可以从github下载:https://github.com/kubernetes/kubernetes/releases
在changelog中找到二进制包的下载链接,下载server binary即可,内里包含了master和node的二进制文件。
解压后将其中的二进制文件挪到 /usr/local/bin目录
安装apiserver

apiserver的核心功能是提供k8s各类资源对象的增删改查及watch等HTTP REST接口,成为集群内各个功能模块之间数据交互和通信的中心枢纽,是整个系统的数据总线和数据中心。除此之外,它还是集群管理的API入口,是资源配额控制的入口,提供了完备的集群安全机制。

  • 编辑master_ssl.cnf。DNS.5为三台服务器的主机名,另行设置/etc/hosts。IP.1为Master Service虚拟服务的Cluster IP地址,IP.2为apiserver的服务器IP
  1. ETCD_NAME=etcd1
  2. ETCD_DATA_DIR=/home/rainux/apps/etcd/data
  3. ETCD_CERT_FILE=/home/rainux/apps/etcd/certs/etcd_server.crt
  4. ETCD_KEY_FILE=/home/rainux/apps/etcd/certs/etcd_server.key
  5. ETCD_TRUSTED_CA_FILE=/home/rainux/apps/certs/ca.crt
  6. ETCD_CLIENT_CERT_AUTH=true
  7. ETCD_LISTEN_CLIENT_URLS=https://192.168.0.31:2379
  8. ETCD_ADVERTISE_CLIENT_URLS=https://192.168.0.31:2379
  9. ETCD_PEER_CERT_FILE=/home/rainux/apps/etcd/certs/etcd_server.crt
  10. ETCD_PEER_KEY_FILE=/home/rainux/apps/etcd/certs/etcd_server.key
  11. ETCD_PEER_TRUSTED_CA_FILE=/home/rainux/apps/certs/ca.crt
  12. ETCD_LISTEN_PEER_URLS=https://192.168.0.31:2380
  13. ETCD_INITIAL_ADVERTISE_PEER_URLS=https://192.168.0.31:2380
  14. ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
  15. ETCD_INITIAL_CLUSTER="etcd1=https://192.168.0.31:2380"
  16. ETCD_INITIAL_CLUSTER_STATE=new
复制代码

  • 天生ssl证书文件
  1. [Unit]
  2. Description=etcd key-value store
  3. Documentation=https://github.com/etcd-io/etcd
  4. After=network.target
  5. [Service]
  6. User=rainux
  7. EnvironmentFile=/home/rainux/apps/etcd/conf/etcd.conf
  8. ExecStart=/home/rainux/apps/etcd/etcd
  9. Restart=on-failure
  10. [Install]
  11. WantedBy=multi-user.target
复制代码

  • 利用cfssl创建sa.pub和sa-key.pem。cfssl和cfssljson可以从GitHub - cfssl下载
  1. systemctl daemon-reload
  2. systemctl start etcd
  3. systemctl enable etcd
  4. # 检查service状态
  5. systemctl status etcd
复制代码

  • 编辑kube-apiserver的设置文件,注意根据实际情况修改文件路径和etcd地址
  1. etcdctl --cacert=/etc/kubernetes/pki/ca.crt --cert=$HOME/apps/certs/etcd_client.crt --key=$HOME/apps/certs/etcd_client.key --endpoints=https://192.168.0.31:2379 endpoint health
  2. # 正常情况下会有类似以下输出
  3. https://192.168.0.31:2379 is healthy: successfully committed proposal: took = 13.705325ms
复制代码

  • 编辑service文件。/etc/systemd/system/kube-apiserver.service
  1. [req]
  2. req_extensions = v3_req
  3. distinguished_name = req_distinguished_name
  4. [req_distinguished_name]
  5. [ v3_req ]
  6. basicConstraints = CA:FALSE
  7. keyUsage = nonRepudiation, digitalSignature, keyEncipherment
  8. subjectAltName = @alt_names
  9. [alt_names]
  10. DNS.1 = kubernetes
  11. DNS.2 = kubernetes.default
  12. DNS.3 = kubernetes.default.svc
  13. DNS.4 = kubernetes.default.svc.cluster.local
  14. DNS.5 = k8s-node1
  15. IP.1 = 169.169.0.1
  16. IP.2 = 192.168.0.31
复制代码

  • 启动apiserver
  1. openssl genrsa -out apiserver.key 2048
  2. openssl req -new -key apiserver.key -config master_ssl.cnf -subj "/CN=k8s-node1" -out apiserver.csr
  3. openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 36500 -extensions v3_req -extfile master_ssl.cnf -out apiserver.crt
复制代码

  • 天生客户端证书
  1. cat<<EOF > sa-csr.json
  2. {
  3.     "CN":"sa",
  4.     "key":{
  5.         "algo":"rsa",
  6.         "size":2048
  7.     },
  8.     "names":[
  9.         {
  10.             "C":"CN",
  11.             "L":"BeiJing",
  12.             "ST":"BeiJing",
  13.             "O":"k8s",
  14.             "OU":"System"
  15.         }
  16.     ]
  17. }
  18. EOF
  19. cfssl gencert -initca sa-csr.json | cfssljson -bare sa -
  20. openssl x509 -in sa.pem -pubkey -noout > sa.pub
复制代码

  • 创建客户端毗连apiserver所需的kubeconfig设置文件。其中server为nginx监听地址。注意根据实际修改设置。这个kubeconfig设置文件也可以给kubectl利用,所以开辟情况中可以直接文件路径置为$HOME/.kube/config
  1. KUBE_API_ARGS="--secure-port=6443 \
  2. --tls-cert-file=/home/rainux/apps/certs/apiserver.crt \
  3. --tls-private-key-file=/home/rainux/apps/certs/apiserver.key \
  4. --client-ca-file=/home/rainux/apps/certs/ca.crt \
  5. --service-account-issuer=https://kubernetes.default.svc.cluster.local \
  6. --service-account-key-file=/home/rainux/apps/certs/sa.pub \
  7. --service-account-signing-key-file=/home/rainux/apps/certs/sa-key.pem \
  8. --apiserver-count=1 \
  9. --endpoint-reconciler-type=master-count \
  10. --etcd-servers=https://192.168.0.31:2379 \
  11. --etcd-cafile=/home/rainux/apps/certs/ca.crt \
  12. --etcd-certfile=/home/rainux/apps/certs/etcd_client.crt \
  13. --etcd-keyfile=/home/rainux/apps/certs/etcd_client.key \
  14. --service-cluster-ip-range=169.169.0.0/16 \
  15. --service-node-port-range=30000-32767 \
  16. --allow-privileged=true \
  17. --audit-log-maxsize=100 \
  18. --audit-log-maxage=15 \
  19. --audit-log-path=/home/rainux/apps/kubernetes/logs/apiserver.log --v=2"
复制代码
安装kube-controller-manager

controller-manager通过apiserver提供的接口实时监控监控集群中特定资源的状态变化,当资源对象不符合预期状态时,controller-manager会尝试将其状态调解为盼望的状态。

  • 编辑设置文件 /home/rainux/apps/kubernetes/conf/kube-controller-manager.conf
  1. [Unit]
  2. Description=Kubernetes API Server
  3. Documentation=https://github.com/kubernetes/kubernetes
  4. After=etcd.service
  5. [Service]
  6. EnvironmentFile=/home/rainux/apps/kubernetes/conf/apiserver.conf
  7. ExecStart=/usr/local/bin/kube-apiserver $KUBE_API_ARGS
  8. Restart=on-failure
  9. [Install]
  10. WantedBy=multi-user.target
复制代码

  • 编辑service文件/etc/systemd/system/kube-controller-manager.service
  1. systemctl daemon-reload
  2. systemctl start kube-apiserver
  3. systemctl enable kube-apiserver
  4. # 检查service状态
  5. systemctl status kube-apiserver
复制代码

  • 启动kube-controller-manager
  1. openssl genrsa -out client.key 2048
  2. # /CN的名称用于标识连接apiserver的客户端用户名称
  3. openssl req -new -key client.key -subj "/CN=admin" -out client.csr
  4. openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 36500
复制代码
安装kube-scheduler


  • 编辑设置文件/home/rainux/apps/kubernetes/conf/kube-scheduler.conf
  1. apiVersion: v1
  2. kind: Config
  3. clusters:
  4. - name: default
  5.   cluster:
  6.     server: https://192.168.0.31:6443
  7.     certificate-authority: /home/rainux/apps/certs/ca.crt
  8. users:
  9. - name: admin
  10.   user:
  11.     client-certificate: /home/rainux/apps/certs/client.crt
  12.     client-key: /home/rainux/apps/certs/client.key
  13. contexts:
  14. - context:
  15.     cluster: default
  16.     user: admin
  17.   name: default
  18. current-context: default
复制代码

  • 编辑service文件 /etc/systemd/system/kube-scheduler.service
  1. KUBE_CONTROLLER_MANAGER_ARGS="--kubeconfig=/home/rainux/.kube/config \
  2. --leader-elect=true \
  3. --service-cluster-ip-range=169.169.0.0/16 \
  4. --service-account-private-key-file=/home/rainux/apps/certs/apiserver.key \
  5. --root-ca-file=/home/rainux/apps/certs/ca.crt \
  6. --v=0"
复制代码

  • 启动
  1. [Unit]
  2. Description=Kubernetes Controller Manager
  3. Documentation=https://github.com/kubernetes/kubernetes
  4. After=kube-apiserver.service
  5. [Service]
  6. EnvironmentFile=/home/rainux/apps/kubernetes/conf/kube-controller-manager.conf
  7. ExecStart=/usr/local/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_ARGS
  8. Restart=on-failure
  9. [Install]
  10. WantedBy=multi-user.target
复制代码
安装worker node

安装kubelet


  • 编辑文件 /home/rainux/apps/kubernetes/conf/kubelet.conf。注意根据实际修改hostname-override和kubeconfig。
  1. systemctl daemon-reload
  2. systemctl start kube-controller-manager
  3. systemctl enable kube-controller-manager
复制代码

  • 编辑/home/rainux/apps/kubernetes/conf/kubelet.config文件。
  1. KUBE_SCHEDULER_ARGS="--kubeconfig=/home/rainux/.kube/config \
  2. --leader-elect=true \
  3. --v=0"
复制代码

  • 编辑service文件 /etc/systemd/system/kubelet.service
  1. [Unit]
  2. Description=Kubernetes Scheduler
  3. Documentation=https://github.com/kubernetes/kubernetes
  4. After=kube-apiserver.service
  5. [Service]
  6. EnvironmentFile=/home/rainux/apps/kubernetes/conf/kube-scheduler.conf
  7. ExecStart=/usr/local/bin/kube-scheduler $KUBE_SCHEDULER_ARGS
  8. Restart=on-failure
  9. [Install]
  10. WantedBy=multi-user.target
复制代码

  • 启动kubelet
  1. systemctl daemon-reload
  2. systemctl start kube-scheduler
  3. systemctl enable kube-scheduler
复制代码
安装kube-proxy


  • 编辑设置文件/home/rainux/apps/kubernetes/conf/kube-proxy.conf。proxy-mode参数默认为iptables,如果安装了ipvs,建议修改为ipvs
  1. KUBELET_ARGS="--kubeconfig=/home/rainux/.kube/config \
  2. --config=/home/rainux/apps/kubernetes/conf/kubelet.config \
  3. --hostname-override=k8s-node1 \
  4. --v=0 \
  5. --container-runtime-endpoint="unix:///run/containerd/containerd.sock"
复制代码

  • 编辑service文件 /etc/systemd/system/kube-proxy.service
  1. kind: KubeletConfiguration
  2. apiVersion: kubelet.config.k8s.io/v1beta1
  3. address: 0.0.0.0  # 服务监听地址
  4. port: 10250  # 服务监听端口号
  5. cgroupDriver: systemd  # cgroup驱动,默认为cgroupfs, 建议systemd
  6. clusterDNS: ["169.169.0.100"]  # 集群DNS地址
  7. clusterDomain: cluster.local  # 服务DNS域名后缀
  8. authentication:  # 是否允许匿名访问或者是否使用webhook鉴权
  9.   anonymous:
  10.     enabled: true
复制代码

  • 启动kube-proxy
  1. [Unit]
  2. Description=Kubernetes Kubelet Server
  3. Documentation=https://github.com/kubernetes/kubernetes
  4. After=containerd.service
  5. [Service]
  6. EnvironmentFile=/home/rainux/apps/kubernetes/conf/kubelet.conf
  7. ExecStart=/usr/local/bin/kubelet $KUBELET_ARGS
  8. Restart=on-failure
  9. [Install]
  10. WantedBy=multi-user.target
复制代码
安装calico


  • 下载calico设置文件
  1. systemctl daemon-reload
  2. systemctl start kubelet
  3. systemctl enable kubelet
复制代码

  • 如果可以正常访问docker hub,则可以直接利用设置文件来创建calico资源对象,否则需要修改其中的镜像地址。如果用的calico版本也是3.25.0,可以用我在阿里云上传的镜像。
  1. KUBE_PROXY_ARGS="--kubeconfig=/home/rainux/.kube/config \
  2. --hostname-override=k8s-node1 \
  3. --proxy-mode=ipvs \
  4. --v=0"
复制代码

  • 执行安装
  1. [Unit]
  2. Description=Kubernetes Kube-Proxy Server
  3. Documentation=https://github.com/kubernetes/kubernetes
  4. After=kubelet.service
  5. [Service]
  6. EnvironmentFile=/home/rainux/apps/kubernetes/conf/kube-proxy.conf
  7. ExecStart=/usr/local/bin/kube-proxy $KUBE_PROXY_ARGS
  8. Restart=on-failure
  9. [Install]
  10. WantedBy=multi-user.target
复制代码

  • 查看calico的pod是否正常运行。如果正常,状态应该都是running;若不正常,则需要describe pod的信息查看什么问题
  1. systemctl daemon-reload
  2. systemctl start kube-proxy
  3. systemctl enable kube-proxy
复制代码
安装CoreDNS


  • 编辑部署文件 coredns.yaml。注意service中指定了clusterIP,以及镜像地址改为了我在阿里云上传的。
  1. wget https://docs.projectcalico.org/manifests/calico.yaml
复制代码

  • 创建coredns服务
  1. image: registry.cn-hangzhou.aliyuncs.com/rainux/calico:cni-v3.25.0
  2. image: registry.cn-hangzhou.aliyuncs.com/rainux/calico:node-v3.25.0
  3. image: registry.cn-hangzhou.aliyuncs.com/rainux/calico:kube-controllers-v3.25.0
复制代码

  • 在repo中我放了一份test-dns.yaml用来测试dns是否正常。创建这个测试对象后,在debian的pod中安装nslookup,测试可否解析出svc-nginx
  1. kubectl create -f calico.yaml
复制代码
安装metrics-server

在新版k8s中,系统资源的收罗和HPA功能均需要利用metrics-server

  • 编辑设置文件。注意镜像地址
  1. kubectl get pods -A
复制代码

  • 创建干系资源对象
  1. ---
  2. apiVersion: v1
  3. kind: ConfigMap
  4. metadata:
  5.   name: coredns
  6.   namespace: kube-system
  7.   labels:
  8.       addonmanager.kubernetes.io/mode: EnsureExists
  9. data:
  10.   Corefile: |
  11.     cluster.local {
  12.         errors
  13.         health {
  14.           lameduck 5s
  15.         }
  16.         ready
  17.         kubernetes cluster.local 169.169.0.0/16 {
  18.           fallthrough in-addr.arpa ip6.arpa
  19.         }
  20.         prometheus :9153
  21.         forward . /etc/resolv.conf
  22.         cache 30
  23.         loop
  24.         reload
  25.         loadbalance
  26.     }
  27.     . {
  28.         cache 30
  29.         loadbalance
  30.         forward . /etc/resolv.conf
  31.     }  
  32. ---
  33. apiVersion: apps/v1
  34. kind: Deployment
  35. metadata:
  36.   name: coredns
  37.   namespace: kube-system
  38.   labels:
  39.     k8s-app: kube-dns
  40.     kubernetes.io/name: "CoreDNS"
  41. spec:
  42.   replicas: 1
  43.   strategy:
  44.     type: RollingUpdate
  45.     rollingUpdate:
  46.       maxUnavailable: 1
  47.   selector:
  48.     matchLabels:
  49.       k8s-app: kube-dns
  50.   template:
  51.     metadata:
  52.       labels:
  53.         k8s-app: kube-dns
  54.     spec:
  55.       priorityClassName: system-cluster-critical
  56.       tolerations:
  57.         - key: "CriticalAddonsOnly"
  58.           operator: "Exists"
  59.       nodeSelector:
  60.         kubernetes.io/os: linux
  61.       affinity:
  62.          podAntiAffinity:
  63.            preferredDuringSchedulingIgnoredDuringExecution:
  64.            - weight: 100
  65.              podAffinityTerm:
  66.                labelSelector:
  67.                  matchExpressions:
  68.                    - key: k8s-app
  69.                      operator: In
  70.                      values: ["kube-dns"]
  71.                topologyKey: kubernetes.io/hostname
  72.       containers:
  73.       - name: coredns
  74.         image: registry.cn-hangzhou.aliyuncs.com/rainux/coredns:1.11.3
  75.         imagePullPolicy: IfNotPresent
  76.         resources:
  77.           limits:
  78.             memory: 170Mi
  79.           requests:
  80.             cpu: 100m
  81.             memory: 70Mi
  82.         args: [ "-conf", "/etc/coredns/Corefile" ]
  83.         volumeMounts:
  84.         - name: config-volume
  85.           mountPath: /etc/coredns
  86.           readOnly: true
  87.         ports:
  88.         - containerPort: 53
  89.           name: dns
  90.           protocol: UDP
  91.         - containerPort: 53
  92.           name: dns-tcp
  93.           protocol: TCP
  94.         - containerPort: 9153
  95.           name: metrics
  96.           protocol: TCP
  97.         securityContext:
  98.           allowPrivilegeEscalation: false
  99.           capabilities:
  100.             add:
  101.             - NET_BIND_SERVICE
  102.             drop:
  103.             - all
  104.           readOnlyRootFilesystem: true
  105.         livenessProbe:
  106.           httpGet:
  107.             path: /health
  108.             port: 8080
  109.             scheme: HTTP
  110.           initialDelaySeconds: 60
  111.           timeoutSeconds: 5
  112.           successThreshold: 1
  113.           failureThreshold: 5
  114.         readinessProbe:
  115.           httpGet:
  116.             path: /ready
  117.             port: 8181
  118.             scheme: HTTP
  119.       dnsPolicy: Default
  120.       volumes:
  121.         - name: config-volume
  122.           configMap:
  123.             name: coredns
  124.             items:
  125.             - key: Corefile
  126.               path: Corefile
  127. ---
  128. apiVersion: v1
  129. kind: Service
  130. metadata:
  131.   name: kube-dns
  132.   namespace: kube-system
  133.   annotations:
  134.     prometheus.io/port: "9153"
  135.     prometheus.io/scrape: "true"
  136.   labels:
  137.     k8s-app: kube-dns
  138.     kubernetes.io/cluster-service: "true"
  139.     kubernetes.io/name: "CoreDNS"
  140. spec:
  141.   selector:
  142.     k8s-app: kube-dns
  143.   clusterIP: 169.169.0.100
  144.   ports:
  145.   - name: dns
  146.     port: 53
  147.     protocol: UDP
  148.   - name: dns-tcp
  149.     port: 53
  150.     protocol: TCP
  151.   - name: metrics
  152.     port: 9153
  153.     protocol: TCP
复制代码

  • 执行干系下令测试是否安装正常
  1. kubectl create -f coredns.yaml
复制代码
小结

按照以上步骤执行完成后,一个用于开辟测试的单机k8s就搭建好了,而且增加节点也比较方便,同时二进制部署方式也便于修改集群参数。
回复

使用道具 举报

返回列表 发新帖
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录

QQ|手机版|qidao123.com IT社区;IT企服评测▪应用市场 ( 浙ICP备20004199|浙ICP备20004199号 )|网站地图

GMT+8, 2026-10-2 01:14 , Processed in 0.020559 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5 Licensed

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表