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社区-企服评测·应用市场»论坛 › 容器及微服务 › 容器及微服务 › k8s StorageClass 存储类
返回列表 发新帖

k8s StorageClass 存储类

[复制链接]
发表于 2024-9-25 02:19:30 | 显示全部楼层 |阅读模式

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

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

×
目录

  • 一、概述

    • 1、StorageClass 对象定义
    • 2、StorageClass YAML 示例

  • 二、StorageClass 字段

    • 1、provisioner(存储制备器)

      • 1.1、内置制备器
      • 1.2、第三方制备器

    • 2、reclaimPolicy(回收策略)
    • 3、allowVolumeExpansion(允许卷扩展)
    • 4、mountOptions(挂载选项)
    • 5、volumeBindingMode(卷绑定模式)

      • 5.1、Immediate
      • 5.2、WaitForFirstConsumer

    • 6、allowedTopologies(允许的拓扑结构)

      • 6.1、示例

    • 7、parameters(存储参数)

      • 7.1、示例
      • 7.2、存储参数(AWSElasticBlockStore)

    • 8、设置默认的 StorageClass(storageclass.kubernetes.io/is-default-class)

      • 8.1、示例
      • 8.2、修改已有的 StorageClass

        • 8.2.1、将存在的 SC 设置为默认
        • 8.2.2、将存在的 SC 设置为非默认



  • 三、实例 -- 使用 NFS 范例的 StorageClass 动态创建 PV

    • 1、配置 NFS 服务端

      • 1.1、master 节点安装 nfs-utils 包
      • 1.2、master 节点创建共享目录
      • 1.3、编辑/etc/exports文件
      • 1.4、应用新的导出设置
      • 1.5、重启并设置 NFS 开机自启
      • 1.6、检查 NFS 共享

    • 2、配置 NFS 客户端

      • 2.1、安装 nfs-utils 包
      • 2.2、创建目录挂载 NFS 共享

        • 2.2.1、卸载错误的挂载点

      • 2.3、重启并设置 NFS 开机自启
      • 2.4、系统启动主动挂载 NFS 共享(非须要)
      • 2.5、查看挂载状态

    • 3、创建存储类
    • 4、创建 RBAC 权限
    • 5、创建 provisioner
    • 6、创建 PVC
    • 7、观察 PV 是否动态创建
    • 8、创建使用同一 PVC 的多个 Pod
    • 9、向共享存储写入数据
    • 10、从另一个 Pod 读取数据
    • 11、查看 nfs 服务端与客户端的共享目录

      • 11.1、PV 目录创建的流程
      • 11.2、PV 目录的结构

    • 12、修改 NFS 服务器共享目录内容查看容器内部变化

  • 四、实例 -- 动态创建 PVC 和 PV

    • 1、创建 Headless Service
    • 2、创建 StatefulSet
    • 3、观察 Pod状态
    • 4、观察到 PVC 与 PV 已经动态创建并相互绑定了
    • 5、每一个 Pod 都会通过绑定 PVC 获取一块独立的 PV


一、概述

集群级别资源,StorageClass 是 Kubernetes 中的一种资源对象,它定义了创建 Persistent Volume (PV) 的策略和方法。StorageClass 主要用于实现 PV 的动态供应,这意味着当用户创建了一个 Persistent Volume Claim (PVC) 时,Kubernetes 会根据所指定的 StorageClass 主动创建一个符合要求的 PV 并将其绑定到 PVC 上
StorageClass 作为对存储资源的抽象定义,对用户设置的 PVC 申请屏蔽后端存储的细节,一方面减少了用户对于存储资源细节的关注,另一方面减轻了管理员手工管理 PV 的工作,由系统主动完成 PV 的创建和绑定,实现动态的资源供应。基于 StorageClass 的动态资源供应模式将逐步成为云平台的标准存储管理模式。
1、StorageClass 对象定义

StorageClass 资源对象的定义主要包罗:名称、后端存储的提供者 (provisioner)、后端存储的相关参数配置(parameters)和回收策略(reclaimPolicy)、卷绑定模式(volumeBindingMode)


  • StorageClass 的名称很重要,将在创建 PVC 时引用,管理员应该正确定名具有不同存储特性的 StorageClass。
  • StorageClass 一旦被创建,则无法修改,如需更改,则只能删除原 StorageClass 资源对象并重新创建。
2、StorageClass YAML 示例
  1. apiVersion: storage.k8s.io/v1
  2. kind: StorageClass
  3. metadata:
  4.   # 存储类的名称,用户在 PVC 中引用
  5.   name: example-storage-class
  6.   storageclass.kubernetes.io/is-default-class: "true"  # 设置为默认的 StorageClass
  7. # 动态制备器的名称,需要与已安装的制备器匹配
  8. provisioner: kubernetes.io/aws-ebs # 例子中使用的是 AWS EBS 制备器
  9. # reclaimPolicy 定义了当 PVC 被删除时,PV 应该如何处理
  10. reclaimPolicy: Delete # 可选值为 Retain 或 Delete
  11. # 允许卷扩展
  12. allowVolumeExpansion: true # 可选值为 true 或 false
  13. # 定义了卷绑定到 Pod 的模式
  14. volumeBindingMode: Immediate # 可选值为 Immediate 或 WaitForFirstConsumer
  15. # 定义了存储系统需要的参数,这些参数会传递给制备器
  16. parameters:
  17.   # 存储类型,根据制备器和存储系统的要求设置
  18.   type: gp2 # AWS EBS 的例子,对于其他系统可能有不同的值
  19.   # 存储 IOPS 性能,某些存储系统可能需要这个参数
  20.   iopsPerGB: "10" # 例子,具体值根据需求和制备器支持设置
  21.   # 存储的最小 IOPS 值,某些存储系统可能需要这个参数
  22.   minimumIOPS: "1000" # 例子,具体值根据需求和制备器支持设置
  23.   # 存储的最大 IOPS 值,某些存储系统可能需要这个参数
  24.   maximumIOPS: "20000" # 例子,具体值根据需求和制备器支持设置
  25.   # 存储的加密选项,某些存储系统可能支持加密
  26.   encrypted: "true" # 例子,具体值根据需求和制备器支持设置
  27.   # 存储的区域,对于跨区域存储系统可能需要这个参数
  28.   availabilityZone: "us-east-1a" # 例子,具体值根据制备器和存储系统的要求设置
  29.   # 存储的性能等级,某些存储系统可能提供不同的性能等级
  30.   performance: "high" # 例子,具体值根据制备器和存储系统的要求设置
  31. # 定义了挂载选项,这些选项会在 PV 被挂载到节点时使用
  32. mountOptions:
  33.   - debug # 例子,具体值根据需求设置,可能包括 "debug", "defaults", "ro" 等
  34.   # - other-option # 可以添加额外的挂载选项
  35. # 允许的拓扑约束,定义了存储可以被哪些节点访问
  36. allowedTopologies:
  37.   - matchLabelExpressions:
  38.     - key: topology.kubernetes.io/region
  39.       values:
  40.         - us-east-1
  41.     - key: topology.kubernetes.io/zone
  42.       values:
  43.         - us-east-1a
复制代码

二、StorageClass 字段

1、provisioner(存储制备器)

provisioner 指定了用于动态创建 PersistentVolume (PV) 的制备器(Provisioner)。制备器是一个插件,它负责在后端存储系统中根据 PersistentVolumeClaim (PVC) 的哀求来创建存储资源,不同的存储插件支持不同的存储后端和服务提供商。当 PVC 被创建而且与之关联的 StorageClass 指定了一个制备器时,Kubernetes 会调用这个制备器来主动创建相应的 PV。
卷插件内置制备器配置示例AWSElasticBlockStore√AWS EBSAzureFile√Azure文件(已弃用)AzureDisk√Azure DiskCephFS--Cinder√Open Stack CinderFC--FlexVolume--GCEPersistentDisk√gcePDGlusterfs√GlusterFSiSCSI--Local-LocalNFS-NFSPortworxVolume√portworx-volumeRBD√ceph-rbdVsphereVolume√Vsphere1.1、内置制备器

Kubernetes 内置支持的 Provisioner 的定名都以 "kubernetes.io/" 开头

  • kubernetes.io/aws-ebs:用于在 AWS 上创建 Elastic Block Store (EBS) 卷。
  • kubernetes.io/azure-disk:用于在 Azure 上创建磁盘。
  • kubernetes.io/gce-pd:用于在 Google Cloud Platform (GCP) 上创建持久磁盘。
  • kubernetes.io/cinder:用于在 OpenStack 上创建 Cinder 卷。
1.2、第三方制备器

为了符合 StorageClass 的用法,自定义 Provisioner 必要符合存储卷的开发规范,外部存储供应商的作者对代码、提供方式、运行方式、存储插件(包罗Flex)等具有完全的自由控制权。
代码堆栈 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一个用于为外部制备器编写功能实现的类库。你可以访问代码堆栈 kubernetes-sigs/sig-storage-lib-external-provisioner 了解外部驱动列表。
比方,对NFS范例,Kubernetes没有提供内部的Provisioner,但可以使用外部的Provisioner。也有很多第三方存储提供商自行提供外部的Provisioner。
2、reclaimPolicy(回收策略)

通过动态资源供应模式创建的PV将继承在StorageClass资源对象上设置的回收策略,配置字段名称为“reclaimPolicy“,可以设置的选项包罗Delete(删除)和 Retain(保留)。


  • 如果StorageClass没有指定reclaimPolicy,则默认值为Delete。
  • 对于管理员手工创建的仍被StorageClass管理的PV,将使用创建PV时设置的资源回收策略。
3、allowVolumeExpansion(允许卷扩展)

PV 可以被配置为允许扩容,当 StorageClass 资源对象的 allowVolumeExpansion字段被设置为true时,将允许用户通过编辑PVC的存储空间主动完成PV的扩容。
下表形貌了支持存储扩容的Volume范例和要求的Kubernetes最低版本:
支持存储扩容的 Volume 范例Kubernetes 最低版本gcePersistentDisk1.11awsElasticBlock Store1.11Cinder1.11glusterfs1.11RBD1.11Azure File1.11Azure Disk1.11Portworx1.13FlexVolume1.14(Alpha)CSI1.16(Beta)
此功能仅可用于扩容卷,不能用于缩小卷。
4、mountOptions(挂载选项)

通过StorageClass资源对象的mountOptions字段,系统将为动态创建的PV设置挂载选项。
并不是所有 PV范例都支持挂载选项,如果 PV不支持但 StorageClass 设置了该字段,则 PV将会创建失败。另外,系统不会对挂载选项进行验证,如果设置了错误的选项,则容器在挂载存储时将直接失败。
5、volumeBindingMode(卷绑定模式)

StorageClass 资源对象的 volumeBindingMode 字段设置用于控制何时将 PVC 与动态创建的 PV 绑定。
目前支持的绑定模式包罗: Immediate 和 WaitForFirstConsumer。
5.1、Immediate

存储绑定模式的默认值为 Immediate,表示当一个PersistentVolumeClaim (PVC)创建出来时,就动态创建PV并进行PVC与PV的绑定操纵。
必要注意的是,对于拓扑受限 (Topology-limited) 或无法从全部Node访问的后端存储,将在不了解Pod调度需求的情况下完成PV的绑定操纵,这大概会导致某些Pod无法完成调度。
5.2、WaitForFirstConsumer

WaitForFirstConsumer绑定模式表示PVC与PV的绑定操纵延迟到第一个使用 PVC的Pod创建出来时再进行。
系统将根据Pod的调度需求,在Pod所在的Node上创建PV,这些调度需求可以通过以下条件(不限于)进行设置:

  • Pod对资源的需求
  • Node Selector
  • Pod亲和性和反亲和性设置
  • Taint和Toleration设置
目前支持 WaitForFirstConsumer 绑定模式的存储卷包罗:

  • AWSElasticBlockStore
  • AzureDisk
  • GCEPersistentDisk.
另外,有些存储插件通过预先创建好的PV绑定支持WaitForFirstConsumer模式,好比:

  • AWSElasticBlockStore
  • AzureDisk
  • GCEPersistentDisk
  • Local
6、allowedTopologies(允许的拓扑结构)

在使用WaitForFirstConsumer模式的环境中,如果仍然希望基于特定拓扑信息(Topology)进行PV绑定操纵,则在StorageClass的定义中还可以通过 allowedTopologies字段进行设置。
6.1、示例

下面的例子通过 matchLabelExpressions 设置目标 Node 的标签选择条件 (zone=us-central1-a或 us-central1-b) PV 将在满足这些条件的 Node 上允许创建
  1. apiVersion: storage.k8s.io/v1
  2. kind: StorageClass
  3. metadata:
  4.   name: standard
  5. provisioner: kubernetes.io/example
  6. parameters:
  7.   type: pd-standard
  8. volumeBindingMode: WaitForFirstConsumer
  9. allowedTopologies:
  10. - matchLabelExpressions:
  11.   - key: topology.kubernetes.io/zone
  12.     values:
  13.     - us-central-1a
  14.     - us-central-1b
复制代码
7、parameters(存储参数)

后端存储资源提供者的参数设置,不同的 Provisioner 大概提供不同的参数设置。某些参数可以不显示设定,Provisioner 将使用其默认值。
目前 StorageClass 资源对象支持设置的存储参数最多为 512个,全部 key 和 value 所占的空间不能超过 256KiB。
7.1、示例

下面举常见存储提供商(Provisioner)提供的 StorageClass 存储参数示例(以AWSElasticBlockStore存储卷为例子):
  1. apiVersion: storage.k8s.io/v1
  2. kind: StorageClass
  3. metadata:
  4.   name: ebs-sc
  5. provisioner: ebs.csi.aws.com
  6. volumeBindingMode: WaitForFirstConsumer
  7. parameters:
  8.   csi.storage.k8s.io/fstype: xfs
  9.   type: io1
  10.   iopsPerGB: "50"
  11.   encrypted: "true"
  12. allowedTopologies:
  13. - matchLabelExpressions:
  14.   - key: topology.ebs.csi.aws.com/zone
  15.     values:
  16.     - us-east-2c
复制代码
7.2、存储参数(AWSElasticBlockStore)

AWS EBS 存储参数


  • type (必需)

    • 定义 EBS 卷的存储范例(默认值gp3)。比方:

      • gp2:通用目的 SSD
      • io1:提供高 IOPS 的 SSD
      • io2:适用于必要大量 IOPS 的应用程序的新一代 SSD
      • st1:通过 HDD 存储优化的卷
      • sc1:通过冷 HDD 存储优化的卷


  • iopsPerGB (可选,仅当 type 为 io1 或 io2 时有效)

    • 定义每个 GiB 提供的 IOPS 数量。
    • 比方,如果 type 为 io1 而且 iopsPerGB 设置为 10,则 100 GiB 的卷将提供 1000 IOPS。

  • iops (可选,仅当 type 为 io1 时有效)

    • 直接定义卷的 IOPS 总数。比方,iops: "1000" 表示卷将提供 1000 IOPS。

  • throughput (可选,仅当 type 为 st1 时有效)

    • 定义卷的吞吐量,以 MiB/s 为单元。比方,throughput: "500" 表示卷的吞吐量为 500 MiB/s。

  • encrypted (可选)

    • 布尔值,指示是否应该加密 EBS 卷。比方,encrypted: "true"。

  • kmsKeyId (可选)

    • 指定用于加密 EBS 卷的 KMS 密钥 ID。比方,kmsKeyId: "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"。

  • fsType (可选)

    • 定义文件系统范例。比方,fsType: "ext4"。

  • volumeSize (可选)

    • 定义哀求的卷大小(以 GiB 为单元)。比方,volumeSize: "100" 表示哀求 100 GiB 的卷。

  • availabilityZone (可选)

    • 定义 EBS 卷应该创建在哪个可用区。比方,availabilityZone: "us-west-2a"。

  • multiAttachEnabled (可选)

    • 布尔值,指示是否启用多附加。比方,multiAttachEnabled: "true" 允许卷同时附加到多个实例。

  • snapshotId (可选)

    • 定义用于创建 EBS 卷的快照 ID。比方,snapshotId: "snap-0123456789abcdef0"。

  • tags (可选)

    • 定义一组键值对,用于标记 EBS 卷。比方:
      1. tags:
      2.   - key: "project"
      3.     value: "myproject"
      4.   - key: "owner"
      5.     value: "myteam"
      复制代码

8、设置默认的 StorageClass(storageclass.kubernetes.io/is-default-class)

在创建 SC 的 YAML 文件时,必要在 metadata 部分添加一个注解,以标记该 SC 为默认。
8.1、示例
  1. apiVersion: storage.k8s.io/v1
  2. kind: StorageClass
  3. metadata:
  4.   name: low-latency
  5.   annotations:
  6.     storageclass.kubernetes.io/is-default-class: "false"
  7. provisioner: csi-driver.example-vendor.example
  8. reclaimPolicy: Retain # 默认值是 Delete
  9. allowVolumeExpansion: true
  10. mountOptions:
  11.   - discard # 这可能会在块存储层启用 UNMAP/TRIM
  12. volumeBindingMode: WaitForFirstConsumer
  13. parameters:
  14.   guaranteedReadWriteLatency: "true" # 这是服务提供商特定的
复制代码
8.2、修改已有的 StorageClass

8.2.1、将存在的 SC 设置为默认
  1. kubectl patch storageclass <sc-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
复制代码
8.2.2、将存在的 SC 设置为非默认
  1. kubectl patch storageclass <sc-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
复制代码
如果你在集群中的多个 StorageClass 上将 storageclass.kubernetes.io/is-default-class 注解设置为 true,然后创建一个未设置 storageClassName 的 PersistentVolumeClaim (PVC), Kubernetes 将使用近来创建的默认 StorageClass。
三、实例 -- 使用 NFS 范例的 StorageClass 动态创建 PV

角色主机名ip地址nfs 服务端 + master 节点k8s-master1192.168.112.10nfs 客户端 + node 节点k8s-node1192.168.112.20nfs 客户端 + node 节点k8s-node2192.168.112.301、配置 NFS 服务端

1.1、master 节点安装 nfs-utils 包
  1. yum install -y nfs-utils
复制代码
1.2、master 节点创建共享目录
  1. mkdir -pv /data/nfs
复制代码

1.3、编辑/etc/exports文件
  1. echo "/data/nfs 192.168.112.0/24(rw,sync,no_root_squash)" > /etc/exports
复制代码

1.4、应用新的导出设置
  1. exportfs -arv
复制代码

1.5、重启并设置 NFS 开机自启
  1. systemctl restart nfs && systemctl enable nfs
复制代码

1.6、检查 NFS 共享
  1. showmount -e localhost
复制代码

2、配置 NFS 客户端

所有 node 节点
2.1、安装 nfs-utils 包
  1. yum install -y nfs-utils
复制代码
2.2、创建目录挂载 NFS 共享
  1. mkdir -pv /mnt/nfs
  2. mount -t nfs 192.168.112.10:/data/nfs /mnt/nfs
复制代码


2.2.1、卸载错误的挂载点

如果在执行 mount -t nfs 下令时出现了错误,好比使用了错误的参数或者路径,你可以通过卸载当前的挂载点然后再重新挂载来修正错误。

  • 确认当前的挂载状态

    • 使用 mount 下令查看当前的所有挂载情况,找到错误挂载的条目。
      1. mount
      复制代码

  • 卸载错误的挂载点

      1. # 知道错误的挂载点
      2. sudo umount /mnt/nfs
      复制代码
      1. # 知道 nfs 服务端 IP 地址和共享目录路径
      2. sudo umount 192.168.112.10:/data/nfs
      复制代码

  • 卸载时碰到设备/文件正在使用中

      1. umount -f /mnt/nfs
      复制代码
    • 强制卸载大概会导致数据丢失,因此只有在确定没有数据写入的情况下才这样做。

2.3、重启并设置 NFS 开机自启
  1. systemctl restart nfs && systemctl enable nfs
复制代码


2.4、系统启动主动挂载 NFS 共享(非须要)
  1. echo '192.168.112.10:/data/nfs /mnt/nfs nfs defaults 0 0' >> /etc/fstab
复制代码
2.5、查看挂载状态
  1. mount | grep 192.168.112.10
复制代码


3、创建存储类
  1. cat >> nfs-storage.yaml << EOF
  2. apiVersion: storage.k8s.io/v1
  3. kind: StorageClass
  4. metadata:
  5.   name: nfs-storage
  6.   namespace: default
  7.   labels:
  8.     environment: test
  9. provisioner: fuseim.pri/ifs
  10. reclaimPolicy: Retain
  11. volumeBindingMode: Immediate
  12. EOF
复制代码
10、从另一个 Pod 读取数据
  1. kubectl apply -f nfs-storage.yaml
复制代码

11、查看 nfs 服务端与客户端的共享目录
  1. cat >> rbac.yaml << EOF
  2. apiVersion: v1
  3. kind: ServiceAccount
  4. metadata:
  5.   name: nfs-client-provisioner
  6.   namespace: default
  7. ---
  8. kind: ClusterRole
  9. apiVersion: rbac.authorization.k8s.io/v1
  10. metadata:
  11.   name: nfs-client-provisioner-runner
  12. rules:
  13.   - apiGroups: [""]
  14.     resources: ["persistentvolumes"]
  15.     verbs: ["get", "list", "watch", "create", "delete"]
  16.   - apiGroups: [""]
  17.     resources: ["persistentvolumeclaims"]
  18.     verbs: ["get", "list", "watch", "update"]
  19.   - apiGroups: ["storage.k8s.io"]
  20.     resources: ["storageclasses"]
  21.     verbs: ["get", "list", "watch"]
  22.   - apiGroups: [""]
  23.     resources: ["events"]
  24.     verbs: ["create", "update", "patch"]
  25. ---
  26. kind: ClusterRoleBinding
  27. apiVersion: rbac.authorization.k8s.io/v1
  28. metadata:
  29.   name: run-nfs-client-provisioner
  30. subjects:
  31.   - kind: ServiceAccount
  32.     name: nfs-client-provisioner
  33.     namespace: default                                      
  34. roleRef:
  35.   kind: ClusterRole
  36.   name: nfs-client-provisioner-runner
  37.   apiGroup: rbac.authorization.k8s.io
  38. ---
  39. kind: Role
  40. apiVersion: rbac.authorization.k8s.io/v1
  41. metadata:
  42.   name: leader-locking-nfs-client-provisioner
  43.   namespace: default                                       
  44. rules:
  45.   - apiGroups: [""]
  46.     resources: ["endpoints"]
  47.     verbs: ["get", "list", "watch", "create", "update", "patch"]
  48. ---
  49. kind: RoleBinding
  50. apiVersion: rbac.authorization.k8s.io/v1
  51. metadata:
  52.   name: leader-locking-nfs-client-provisioner
  53.   namespace: default
  54. subjects:
  55.   - kind: ServiceAccount
  56.     name: nfs-client-provisioner
  57.     namespace: default
  58. roleRef:
  59.   kind: Role
  60.   name: leader-locking-nfs-client-provisioner
  61.   apiGroup: rbac.authorization.k8s.io
  62. EOF
复制代码



这个新出现的目录(PV 目录) default-nginx-pvc-pvc-c8a8b825-1577-4f76-ba1f-a1302941b333 用于映射 PersistentVolume (PV) 到 NFS 服务器上的具体路径
11.1、PV 目录创建的流程


  • 创建 PVC:

    • 当你创建 PVC 时,Kubernetes 会根据 StorageClass 主动创建 PV。

  • Provisioner 创建 PV:

    • Provisioner 会在 NFS 服务器上的共享目录下创建一个新目录,目录名称包含了 PVC 的名称和 UUID。

  • 挂载到 Pod:

    • 创建的 PV 会被挂载到 Pod 中指定的路径。

11.2、PV 目录的结构
  1. kubectl apply -f rbac.yaml
复制代码

  • 共享目录:

    • 这是你在 NFS 服务器上创建并共享出去的目录,好比 nfs 服务端的 /data/nfs 以及 nfs 客户端的 /mnt/nfs

  • 定名空间:

    • 这是 Kubernetes 中的一个逻辑分组,用于隔离不同的应用程序和服务。PVC 所属的定名空间名称。

  • PVC 名称:

    • 这是在 Kubernetes 中创建的 PersistentVolumeClaim 的名称。

  • PV 名称:

    • 这是根据 PVC 动态创建出来的 PersistentVolume 的名称,通常是一个带有 UUID 的字符串。

  1. cat >> nfs-provisioner.yaml << EOF
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5.   name: nfs-client-provisioner
  6.   labels:
  7.     app: nfs-client-provisioner
  8.   namespace: default
  9. spec:
  10.   replicas: 1
  11.   strategy:
  12.     type: Recreate
  13.   selector:
  14.     matchLabels:
  15.       app: nfs-client-provisioner
  16.   template:
  17.     metadata:
  18.       labels:
  19.         app: nfs-client-provisioner
  20.     spec:
  21.       serviceAccountName: nfs-client-provisioner
  22.       containers:
  23.         - name: nfs-client-provisioner
  24.           image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
  25.           volumeMounts:
  26.             - name: nfs-client-root
  27.               mountPath: /persistentvolumes
  28.           env:
  29.             - name: PROVISIONER_NAME
  30.               value: fuseim.pri/ifs       # 这里必须要填写storageclass中的PROVISIONER名称信息一致
  31.             - name: NFS_SERVER
  32.               value: 192.168.112.10       # 指定NFS服务器的IP地址
  33.             - name: NFS_PATH
  34.               value: /data/nfs            # 指定NFS服务器中的共享挂载目录
  35.       volumes:
  36.         - name: nfs-client-root           # 定义持久化卷的名称,必须要上面volumeMounts挂载的名称一致
  37.           nfs:
  38.             server: 192.168.112.10        # 指定NFS所在的IP地址
  39.             path: /data/nfs               # 指定NFS服务器中的共享挂载目录
  40. EOF
复制代码

12、修改 NFS 服务器共享目录内容查看容器内部变化

可以发现也是同步更新的
  1. kubectl apply -f nfs-provisioner.yaml
复制代码

四、实例 -- 动态创建 PVC 和 PV

1、创建 Headless Service

[code]cat >> nginx-headless.yaml > sts.yaml
回复

使用道具 举报

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

本版积分规则

登录后关闭弹窗

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

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

GMT+8, 2026-11-14 09:38 , Processed in 0.036622 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5 Licensed

© 2001-2026 Discuz! Team.

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