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 svc详解
返回列表 发新帖

k8s svc详解

[复制链接]
发表于 2026-5-17 15:38:08 | 显示全部楼层 |阅读模式
一、k8s svc详解


  • 先容了pod之间怎么通讯的,可以通过ClusterIP,dns,pod ip直接通讯
  • dns比力风趣 web-svc.default.svc.cluster.local
  • pod对外提供服务就必要NodePort,LoadBalance
  • 如果还对七层有要求的话,就必要ingress
1、为什么必要这个svc呢?


  • 核心缘故起因

    • pod的ip不固定,pod重启,重新调理后ip会厘革
    • 如果没有svc,就必要直接访问pod的ip,但是pod的ip一但厘革的,全部依赖这个设置的都必要重新设置,在生产情况中是不可继续的

  • 办理了核心的题目

    • 稳固的网络入口,提供了一个假造的ip(clusterip)和dns名称,就是不必要管后端pod的厘革了
    • 实现了负载均衡,svc主动的将流量转发到后端的pod,无需设置额外的负载均衡器
    • 服务发现,集群内的其他组件可以通过dns直接访问

1、svc的设置



  • 也是通过标签关联一组pod
创建一个nginx,svc
  1. [root@master01 svc]# kubectl create deployment web1 --image=nginx --dry-run=client -o yaml > web1.yml
  2. # 查看pod的ip地址
  3. [root@master01 svc]# kubectl get pod -o wide
  4. NAME                  READY   STATUS    RESTARTS   AGE     IP              NODE       NOMINATED NODE   READINESS GATES
  5. web1-8fd498dd-klfrx   1/1     Running   0          6m17s   10.246.73.146   node       <none>           <none>
  6. web1-8fd498dd-nch98   1/1     Running   0          6m17s   10.244.59.197   master02   <none>           <none>
  7. [root@master01 svc]# kubectl expose deployment web1 --port=80 --target-port=80 --type=ClusterIP
  8. service/web1 exposed
  9. [root@master01 svc]# kubectl describe svc web1
  10. Name:              web1
  11. Namespace:         default
  12. Labels:            app=web1  # 选择的标签
  13. Annotations:       <none>
  14. Selector:          app=web1
  15. Type:              ClusterIP
  16. IP Family Policy:  SingleStack
  17. IP Families:       IPv4
  18. IP:                10.110.146.0
  19. IPs:               10.110.146.0
  20. Port:              <unset>  80/TCP
  21. TargetPort:        80/TCP
  22. Endpoints:         10.244.59.197:80,10.246.73.146:80  # 关联上带app=web1的pod了
  23. Session Affinity:  None
  24. Events:            <none>
  25. # svc下面还有一个endpoints关联pod
  26. [root@master01 svc]# kubectl get endpoints
  27. NAME         ENDPOINTS                               AGE
  28. kubernetes   192.168.50.20:6443,192.168.50.21:6443   7d5h
  29. web1         10.244.59.197:80,10.246.73.146:80       2m4s
  30. # pod被删除了,这个ip也会变化,也会被endpoints重新记录新的pod的ip
  31. [root@master01 svc]# kubectl delete pod web1-8fd498dd-klfrx
  32. pod "web1-8fd498dd-klfrx" deleted
  33. [root@master01 svc]# kubectl get endpoints
  34. NAME         ENDPOINTS                               AGE
  35. kubernetes   192.168.50.20:6443,192.168.50.21:6443   7d5h
  36. web1         10.244.59.197:80,10.246.73.145:80       3m28s
复制代码
访问
  1. # 集群内部访问clusterip 就能访问到pod提供的业务了,发现是轮询的,实现了负载均衡的效果
  2. [root@master01 svc]# curl 10.110.146.0
  3. 456
  4. [root@master01 svc]# curl 10.110.146.0
  5. 123
复制代码

  • 集群外貌是不能通过clusterip访问的,必要借助其他的nodeport等等
2、kube-proxy详解

1、kube-proxy是什么


  • 在每一个节点上必须跑的一个署理步调,专门负责实现svc的网络转发本领(集群内部的调理员+规则设置员)
svc是一个设置,不会自己转发流量,kube-proxy才是干活的人


  • 监听svc和endpoint的厘革,知道哪些svc对应哪些pod的ip
  • 在节点上设置网络规则,ipvs和iptables规则
  • 实现服务访问和负载均衡的,当访问svc ip时,将流量转发到后端的pod上


  • 修改kube-proxy的模式为iptables
有一个存储kube-proxy的设置文件为configmap,修改后,删除全部pod,设置就会更新过来
  1. [root@master01 ~]# kubectl edit cm -n kube-system kube-proxy
  2.     mode: iptables
  3. # 删除kube-proxy关联的pod
  4. [root@master01 ~]# kubectl delete pods -n kube-system -l k8s-app=kube-proxy
  5. pod "kube-proxy-95mlq" deleted
  6. pod "kube-proxy-svx52" deleted
  7. pod "kube-proxy-tzts4" deleted
  8. # 会重新创建出来,配置也被更新了
  9. [root@master01 ~]# kubectl get pod -n kube-system -l k8s-app=kube-proxy
  10. NAME               READY   STATUS    RESTARTS   AGE
  11. kube-proxy-bs4rg   1/1     Running   0          5s
  12. kube-proxy-kzknc   1/1     Running   0          4s
  13. kube-proxy-zq975   1/1     Running   0          4s
  14. # 查看日志日志,发现使用了iptables规则
  15. [root@master01 ~]# kubectl logs -n kube-system kube-proxy-bs4rg
  16. I0401 07:39:33.514227       1 node.go:163] Successfully retrieved node IP: 192.168.50.22
  17. I0401 07:39:33.514303       1 server_others.go:138] "Detected node IP" address="192.168.50.22"
  18. I0401 07:39:33.532944       1 server_others.go:206] "Using iptables Proxier"
  19. # 查看iptables规则
  20. [root@master01 ~]# iptables -t nat -L -n | grep 10.110.237.145
  21. KUBE-SVC-CWMY3MEVXVILAFTH  tcp  --  0.0.0.0/0            10.110.237.145       /* default/v1 cluster IP */ tcp dpt:80
  22. KUBE-MARK-MASQ  tcp  -- !10.240.0.0/12        10.110.237.145       /* default/v1 cluster IP */ tcp dpt:80
复制代码
2、kube-proxy和svc的区别


  • 关系是,svc是访问的入口,kube-proxy是实现这个入口转发本领的节点署理进程
  • svc是提供稳固的假造ip,端口和负载均衡入口,通过标签选择一组pod,自己是不处置惩罚流量的
  • kube-proxy每个节点上运行的进程,监听svc和endpoints厘革,在节点上设置ipvs/iptables规则,实现流量转发和负载均衡,是svc的实验者
  • svc和kube-proxy共同利用

    • svc界说访问的计谋,端口,稳固的入口
    • kube-proxy,实现这些svc界说的计谋,实现流量转发的本领
    • 没有svc,不知道怎么访问
    • 没有kube-proxy,有svc,但是没有现实的流量转发本领,也访问不到

3、服务发现


  • 就是pod之间通过这些来举行通讯
  • 服务发现流程,就是pod访问别的一个pod的场景

    • 容器内部举行dns剖析,指向了core-dns
    • core-dns查询当地的缓存,找到对应的svc
    • 得到应用的ip
    • 发送哀求到该ip
    • kube-proxy的iptables/ipvs规则
    • 转发到后端的pod

1、clusterip


  • 是svc的默认范例,为svc分配一个集群内部专用的假造ip,只能在集群内部举行访问
  • 这个ip网段,在创建k8s集群的时间,可以指定的,差别的网段,底层是买通的
  • 是一个假造网卡,没有实体的网卡绑定
  • 仅存在iptables/ipvs规则中,通过kube-proxy实现流量的转发
  • 等完成后,将kube-proxy模式改为iptables,就能看到iptables规则了
继续看我们上面完成的实验
  1. # type的类型是clusterip
  2. # 虚拟ip为10.110.146.0
  3. # 监听的端口是80的   这个ip和端口都是虚拟出来的
  4. [root@master01 svc]# kubectl get svc web1
  5. NAME   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
  6. web1   ClusterIP   10.110.146.0   <none>        80/TCP    17m
  7. # 访问这个虚拟ip就能访问pod了
  8. # 查看ipvs规则
  9. # ipvsadm -ln
  10. # 关联的pod的ip
  11. TCP  10.110.146.0:80 rr
  12.   -> 10.244.59.197:80             Masq    1      0          0         
  13.   -> 10.246.73.145:80             Masq    1      0          0
复制代码
2、dns方式


  • 集群内里有core-dns这个pod,这个就是集群pod内部的dns服务器
  • CoreDNS 的 DNS 纪录完全泉源于 Service(以及 Pod、Endpoint 等资源):
  • 为什么必要呢?

    • svc的假造ip难记
    • 一个服务多个端口的时间难以区分
    • 跨ns的时间调用困难,必要知道对方的clusterip
    • 可以直接通过域名的方式来举行访问,差别名称空间下面也可以举行访问
    • 就不必要关系clusterip的厘革,由于删除clusterip的话,ip地点会变动

  • core-dns为每一个创建的svc主动天生一个唯一的域名,也就是dns纪录,每一个svc都在上面举行注册了,一个域名剖析器

    • 域名的格式为 svcname.nsname.svc.cluster.local
    • 服务名称.名称空间.范例.集群域

  • kube-dns已经没有被维护了,大多数利用的是core-dns
1、检察集群dns

检察集群dns
  1. # 查看集群dns 10.96.0.10
  2. [root@master01 ~]# kubectl get svc -n kube-system
  3. NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
  4. kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   7d5h
  5. # pod里面的dns也是10.96.0.10
  6. root@web1-8fd498dd-nch98:/# cat /etc/resolv.conf
  7. nameserver 10.96.0.10
  8. search default.svc.cluster.local svc.cluster.local cluster.local
  9. options ndots:5
  10. # 查看core-dns,集群现在就是这2个pod在提供dns服务
  11. [root@master01 ~]# kubectl get pod -n kube-system  -o wide | grep dns
  12. coredns-665d974787-46d59                   1/1     Running   11             7d6h   
  13. coredns-665d974787-s564k                   1/1     Running   11             7d6h
复制代码

  • 上面不是说kube-dns没有被维护了,为什么照旧利用kube-dns呢?

    • 转发到kube-dns,末了照旧转发到core-dns的pod了
    • 照旧在利用core-dns

  1. # 查看kube-dns的详细信息
  2. [root@master01 ~]# kubectl describe svc -n kube-system kube-dns  | grep -i endpoints
  3. Endpoints:         10.255.112.164:53,10.255.112.165:53
  4. Endpoints:         10.255.112.164:53,10.255.112.165:53
  5. Endpoints:         10.255.112.164:9153,10.255.112.165:9153
  6. # 发现转发到后端的pod是core-dns
  7. [root@master01 ~]# kubectl get pod -n kube-system  -o wide | grep dns
  8. coredns-665d974787-46d59                   1/1     Running   11             7d6h   10.255.112.164   master01   <none>           <none>
  9. coredns-665d974787-s564k                   1/1     Running   11             7d6h   10.255.112.165   master01   <none>           <none>
复制代码
2、pod之间通过域名来访问


  • 域名剖析同一个名称空间下
  1. # 我们上面创建了一个web1 svc,关联了2个pod
  2. # 因此创建一个临时容器测试一下
  3. [root@master01 svc]# kubectl run b1 --image=busybox --rm -ti -- sh
  4. / # wget web1  # 直接访问web1服务,不需要知道web1的svc的ip地址,因为有dns记录,会自动的解析
  5. Connecting to web1 (10.110.146.0:80)
  6. saving to 'index.html'
  7. index.html           100% |**********************************|     4  0:00:00 ETA
  8. 'index.html' saved
  9. / # cat index.html
  10. 123
  11. # busybox会自己去找dns,然后解析这个web1的ip,从而实现访问,就是在访问clusterip,从而获取提供的服务
复制代码

  • 域名剖析不在同一个名称空间下面
  1. # 在test空间下,创建一个pod,测试能不能解析default下的svc
  2. [root@master01 svc]# kubectl run b1 --image=busybox --namespace test  --rm -ti -- sh
  3. # 直接解析svc,没有成功
  4. / # wget web1
  5. wget: bad address 'web1'
  6. # 添加一个defaul空间,就能解析成功
  7. / # wget web1.default
  8. Connecting to web1.default (10.110.146.0:80)
  9. saving to 'index.html'
  10. index.html           100% |**********************************|     4  0:00:00 ETA
  11. 'index.html' saved
  12. # 这个是dns的地址
  13. / # cat /etc/resolv.conf
  14. nameserver 10.96.0.10
  15. search test.svc.cluster.local svc.cluster.local cluster.local
  16. options ndots:5
复制代码

  • 尚有一个题目,pod可以访问差别空间下的pod,直接利用ip访问
  1. / # ping 10.246.73.145
  2. PING 10.246.73.145 (10.246.73.145): 56 data bytes
  3. 64 bytes from 10.246.73.145: seq=0 ttl=63 time=0.093 ms
复制代码

  • 这是是由于不必要dns剖析,直接走的calico网络,pod网络是扁平化的
  • 无论pod在哪一个ns,ip段都是互通的
  • 没有ns的网络隔离(除非利用网络计谋,上一篇博客讲了的)
  • coredns的设置
  1. [root@master01 ~]# kubectl get configmaps -n kube-system coredns -o yaml
  2. apiVersion: v1
  3. data:
  4.   Corefile: |
  5.     .:53 {  # 监听所有dns的请求
  6.         errors
  7.         health {
  8.            lameduck 5s
  9.         }
  10.         ready
  11.         kubernetes cluster.local in-addr.arpa ip6.arpa {
  12.            pods insecure   # 允许pod ip解析pod的名称
  13.            fallthrough in-addr.arpa ip6.arpa
  14.            ttl 30  # dns记录缓存30s
  15.         }
  16.         prometheus :9153
  17.         forward . /etc/resolv.conf {  # 非集群域名(baidu.com0)转发到上游的dns,也就是宿主机配置的dns
  18.            max_concurrent 1000
  19.         }
  20.         cache 30
  21.         loop
  22.         reload
  23.         loadbalance
  24.     }
  25. kind: ConfigMap
  26. metadata:
  27.   creationTimestamp: "2026-03-24T04:41:18Z"
  28.   name: coredns
  29.   namespace: kube-system
  30.   resourceVersion: "302"
  31.   uid: 9281803b-4bfe-4a36-8796-ef60d870e801
复制代码
3、无头的clusterip


  • 也就是svc没有clusterip的ip地点
  • 实用的场景,三个pod,一个主mysql,2个都是备mysql,只要主继续哀求,由于clusterip是轮询的,以是不可,必要headless clsuterip
  • 连合这个dns,statefulset(有序的) 常连合一起利用,为每一个pod分配一个唯一的域名,如许就能指定访问一个pod,不会轮询了
  • 在这种情况下可以通过访问pod的域名来实现访问,其他情况下都是通过访问svc实现对pod的访问
  1. [root@master01 svc]# cat ds.yml
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5.   name: nginx
  6. spec:
  7.   clusterIP: None   # 为none就是没有clusterip
  8.   selector:
  9.      app: d1
  10.   ports:
  11.     - port: 80
  12.       targetPort: 80
  13. ---
  14. apiVersion: apps/v1
  15. kind: StatefulSet  # sts的控制器
  16. metadata:
  17.   creationTimestamp: null
  18.   labels:
  19.     app: d1
  20.   name: d1
  21. spec:
  22.   replicas: 2
  23.   selector:
  24.     matchLabels:
  25.       app: d1
  26.   serviceName: "nginx"  # 指定服务,这个服务关联一组pod,dns为每一个这样的pod分配唯一的域名,因为没有clusterip,所以这样
  27.   template:
  28.     metadata:
  29.       creationTimestamp: null
  30.       labels:
  31.         app: d1
  32.     spec:
  33.       containers:
  34.       - image: nginx
  35.         name: nginx
  36.         ports:
  37.         - containerPort: 80
  38. # 创建一个测试容器
  39. [root@master01 ~]# kubectl run b1 --image=busybox    --rm -ti -- sh
  40. # 解析这个nginx svc 返回的是一组pod的域名和ip
  41. / # nslookup nginx
  42. Server:                10.96.0.10
  43. Address:        10.96.0.10:53
  44. ** server can't find nginx.cluster.local: NXDOMAIN
  45. Name:        nginx.default.svc.cluster.local
  46. Address: 10.246.73.150
  47. Name:        nginx.default.svc.cluster.local
  48. Address: 10.244.59.198
  49. # 可以单独访问指定的pod
  50. / # ping d1-0.nginx.default.svc.cluster.local
  51. PING d1-0.nginx.default.svc.cluster.local (10.246.73.150): 56 data bytes
  52. 64 bytes from 10.246.73.150: seq=0 ttl=63 time=0.054 ms
复制代码
4、core-dns和svc的关系


  • 图自己修改一劣等一下
  • 就是在集群中创建一个svc,kueb-proxy会天生ipvs规则大概iptables规则
  • 然后这个core-dns监听svc,会纪录在内里,并有dns纪录


  • pod通过域名访问

    • 起首找自己的dns,也就是core-dns
    • 通过这个dns找到了这个域名对应的ip
    • 然后访问这个pod即可,内核照旧kube-proxy实现的

  1. Service        提供稳定的访问入口(IP + 端口)        餐厅的实体店面
  2. CoreDNS        提供服务名到 IP 的映射        餐厅的地图导航
  3. kube-proxy        实现流量的负载均衡和转发        餐厅的服务员和调度
复制代码
3、变量的方式

4、NodePort


  • 之前的clusterip是集群内部举行访问的,集群外貌就不可了
  • nodeport就是做一个端口映射的,访问物理主机+映射到主机的端口就能访问到集群内部的服务了
  • 创建出来后,每个物理主机都有这个端口,因此每一个主机+映射的端口就能访问
  • 默认天生一个3w以上的端口
  • 寻常的svc利用ipvs全节点转发,kube-proxy在全部节点都创建了ipvs转发规则

    • 为什么全部节点都能访问呢?

      • 缘故起因就是这个externalTrafficPolicy: Cluster这个参数, 全部节点都能转发
      • 这个是控制外部流量怎么访问集群
      • 尚有一个local就是只有当地有pod,才气被访问,背面ingress 会详细讲授的,就是为什么其他节点没有ingress pod就访问不到了?


  • 核心就是添加一个ipvs规则大概iptables规则
  • nodeport访问流程

    • 先访问主机ip+端口
    • 转发到svc的ip+端口
    • kube-proxy通过ipvs规则,转发到后端的关联的pod,从而实现访问

  1. kubectl expose deployment web1 --name nginx-svc --port 80 --target-port 80 --type NodePort
  2. [root@master01 svc]# kubectl get svc
  3. NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
  4. kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        7d6h
  5. nginx-svc    NodePort    10.109.165.192   <none>        80:30108/TCP   49s
  6. web1         ClusterIP   10.110.146.0     <none>        80/TCP         93m
  7. # 所有节点都有这个映射的端口
  8. [root@master02 ~]# netstat -pant|grep 30108
  9. tcp        0      0 0.0.0.0:30108           0.0.0.0:*               LISTEN      2315/kube-proxy  
  10. curl 192.168.50.20:30108
  11. curl 192.168.50.21:30108
  12. curl 192.168.50.22:30108
  13. # 查看ipvs信息
  14. ipvsadm -ln
  15. TCP  10.255.112.128:30108 rr
  16.   -> 10.244.59.199:80             Masq    1      0          0         
  17.   -> 10.246.73.152:80             Masq    1      0          0      
复制代码
5、ingress(最常用的)


  • 上面的几种方式都是四层,基于ip和端口的
  • ingress是基于七层的
  • 让用户通过一个域名/ip,访问集群内里多个差别的svc
  • 是一个七层的路由,可以或许根据域名和url路径转发
1、核心组件


  • ingress资源

    • 访问a.com 转发给svc1
    • 访问b.com/api 转发到svc2

  • ingress controller

    • 是真正干活的步调(nginx-ingress)
    • 监听全部ingress规则(自己编写的ingress规则)
    • 主动天生设置并见效,就是天生nginx.conf文件,翻译成这个
    • 吸收外部真实流量

2、工作流程


  • 用于输入域名,访问ingress的外部ip/域名
  • 流量到达ingress-controller这个pod

    • 默认监听是80/443
    • 一样寻常是nodeport

  • 根据ingress规则匹配

    • 域名是谁
    • url路径是谁
    • 转发到哪一个svc

  • 转发到svc和关联的pod上
  • 末了照旧靠的ipvs转发到对应的pod
3、安装ingress


  • https://github.com/kubernetes/ingress-nginx
  • https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml
  • 上面这个文件,路径在deploy/static/下面
  1. # 将里面三个镜像可以改成华为的
  2. kubectl apply -f ingress.yml
  3. [root@master01 svc]# kubectl get pod -n ingress-nginx
  4. NAME                                        READY   STATUS      RESTARTS   AGE
  5. ingress-nginx-admission-create-dqrkj        0/1     Completed   0          65s
  6. ingress-nginx-admission-patch-pjbf5         0/1     Completed   0          65s
  7. ingress-nginx-controller-8478d55789-f4444   1/1     Running     0          65s
  8. # 查看svc
  9. [root@master01 svc]# kubectl get svc -n ingress-nginx
  10. NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
  11. ingress-nginx-controller             LoadBalancer   10.103.125.75   <pending>     80:32162/TCP,443:30717/TCP   70s
  12. ingress-nginx-controller-admission   ClusterIP      10.111.38.80    <none>        443/TCP                      70s
  13. # 将这个ingress-nginx-controller改成nodeport
  14. # 直接修改配置文件即可
  15. [root@master01 svc]# kubectl get svc -n ingress-nginx
  16. NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
  17. ingress-nginx-controller             NodePort    10.103.125.75   <none>        80:32162/TCP,443:30717/TCP   3m46s
  18. ingress-nginx-controller-admission   ClusterIP   10.111.38.80    <none>        443/TCP                      3m46s
复制代码
4、界说ingress规则


  • 实验图


  • ingress实验流程就是

    • 访问节点ip+32162,这个svc,根据这个ipvs规则(创建了一个svc,kube-proxy会主动创建一个ipvs规则),转发到ingress-nginx-controller这个pod
    • 根据这ingress这个规则,转发到提供服务的svc
    • 根据这个ipvs规则转发到后端的pod

  1. # class为nginx
  2. [root@master01 svc]# kubectl get ingressclasses.networking.k8s.io
  3. NAME    CONTROLLER             PARAMETERS   AGE
  4. nginx   k8s.io/ingress-nginx   <none>       11m
  5. [root@master01 svc]# cat in.yml
  6. apiVersion: networking.k8s.io/v1
  7. kind: Ingress
  8. metadata:
  9.   name: my-app-ingress
  10. spec:
  11.   ingressClassName: nginx   # 需要定义class规则,对一组ingress
  12.   rules:
  13.   - host: www.meme1.com
  14.     http:
  15.       paths:
  16.       - path: / # 直接匹配根路径
  17.         pathType: Prefix  # 前缀匹配
  18.         backend:
  19.           service:
  20.             name: svcn1   # 转发到svcn1的80端口,从而转发到后端的pod
  21.             port:
  22.               number: 80
  23.   - host: www.meme2.com
  24.     http:
  25.       paths:
  26.       - path: /
  27.         pathType: Prefix
  28.         backend:
  29.           service:
  30.             name: svcn2
  31.             port:
  32.               number: 80
  33. # 创建svcn1和svcn2
  34. [root@master01 svc]# cat web1.yml
  35. apiVersion: v1
  36. kind: Service
  37. metadata:
  38.   name: svcn1
  39. spec:
  40.   type: NodePort
  41.   selector:
  42.     app: svcn1
  43.   ports:
  44.   - port: 80
  45.     targetPort: 80
  46.     nodePort: 32222
  47. ---
  48. apiVersion: apps/v1
  49. kind: Deployment
  50. metadata:
  51.   creationTimestamp: null
  52.   labels:
  53.     app: svcn1
  54.   name: web1
  55. spec:
  56.   replicas: 1
  57.   selector:
  58.     matchLabels:
  59.       app: svcn1
  60.   strategy: {}
  61.   template:
  62.     metadata:
  63.       creationTimestamp: null
  64.       labels:
  65.         app: svcn1
  66.     spec:
  67.       containers:
  68.       - image: nginx
  69.         name: nginx
  70.         ports:
  71.         - containerPort: 80
  72.         resources: {}
  73. [root@master01 svc]# kubectl get pod
  74. NAME                   READY   STATUS    RESTARTS   AGE
  75. web1-5b7f5548b-vx9vt   1/1     Running   0          23m
  76. web2-d86c55fbf-2mm2b   1/1     Running   0          21m
  77. [root@master01 svc]# kubectl get svc
  78. NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
  79. kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        7d8h
  80. svcn1        NodePort    10.101.227.56   <none>        80:32222/TCP   23m
  81. svcn2        NodePort    10.108.20.222   <none>        80:32223/TCP   22m
复制代码
  1. # 部署ingress规则
  2. [root@master01 svc]# kubectl get ingress
  3. NAME             CLASS   HOSTS                         ADDRESS         PORTS   AGE
  4. my-app-ingress   nginx   www.meme1.com,www.meme2.com   10.103.125.75   80      21m
  5. # 已经做好了映射了
  6. [root@master01 svc]# kubectl describe ingress
  7. Name:             my-app-ingress
  8. Labels:           <none>
  9. Namespace:        default
  10. Address:          10.103.125.75
  11. Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
  12. Rules:
  13.   Host           Path  Backends
  14.   ----           ----  --------
  15.   www.meme1.com  
  16.                  /   svcn1:80 (10.246.73.160:80)
  17.   www.meme2.com  
  18.                  /   svcn2:80 (10.246.73.159:80)
  19. Annotations:     <none>
  20. Events:
  21.   Type    Reason  Age                From                      Message
  22.   ----    ------  ----               ----                      -------
  23.   Normal  Sync    21m (x2 over 21m)  nginx-ingress-controller  Scheduled for sync
复制代码
5、客户端欣赏器测试和细节
  1. [root@master01 svc]# curl -H "Host: www.meme1.com" http://192.168.50.22:32162
  2. meme1.com
  3. [root@master01 svc]# curl -H "Host: www.meme2.com" http://192.168.50.22:32162
  4. meme2
  5. # 只能访问22才能访问到,原因就是20,21节点上面没有这个ingress-nginx这个pod
  6. # 访问20:32162 没有这个pod,进不去,也没有这ipvs
  7. # 21一样
  8. # 因此将这个副本数变成3个即可
  9. [root@master01 svc]# kubectl scale deployment ingress-nginx-controller -n ingress-nginx --replicas=3
  10. # 就能访问了,也有这个ipvs规则了
复制代码

  • 上面的实验,为什么21,20的32162不能访问呢?

    • 缘故起因就是ingress-nginx这个svc中的externalTrafficPolicy: Local 是这个模式

      • 这个模式下,当地有ingresss pod ,该节点的ipvs才有后端,能访问
      • 当地没有ingress pod ,该节点的ipvs没有后端,访问拒绝

    • 摆设3个ingrees pod 后,一个在master02上,一个在node上
    • 这2个节点都能访问到,master01上有污点,以是不能摆设,也就没有ipvs后端,也就访问不到了

  • 总结一下

    • 由于ingress的svc是local,这个节点上有这个ingress的pod,才气实现访问节点(有ingress的节点)+端谈锋气访问到,其他节点上没有这个ingress的pod,就访问不到,有ingress pod的节点就有转发到ingree pod的规则
    • 这个nodeport的svc不能实现跨节点的通讯
    • 改成externalTrafficPolicy: cluster就能访问到了,这个就是无论节点上有没有这个ingress pod,都能访问,就天生了ipvs规则,到这个ingress pod的规则

  • 上面不通,除了摆设多个ingrees pod 外,尚有一种方式就是将loacl改成cluster,如许不管其他节点有没有ingress pod 都能访问到了
  1. [root@master01 svc]# kubectl edit svc -n ingress-nginx ingress-nginx-controller
  2. externalTrafficPolicy: Cluster
  3. # 修改后,ipvs规则就有了,对应的是3个ingress pod ,因为流量必须经过这个ingrees pod 然后根据这个ingress规则实现转发
  4. TCP  192.168.50.20:32162 rr
  5.   -> 10.244.59.201:80             Masq    1      0          0         
  6.   -> 10.246.73.162:80             Masq    1      0          0         
  7.   -> 10.246.73.163:80             Masq    1      0          1      
复制代码
6、ingress规则详细设置
  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4.   name: my-ingress
  5.   namespace: default
  6.   annotations:
  7.     # 最重要的注解(rewrite、限流、超时都在这里)
  8.     nginx.ingress.kubernetes.io/rewrite-target: /  # 路径重写,/api/v1 转发到 / 就是只访问根目录
  9. spec:
  10.   # 指定 Ingress 控制器(必须写)
  11.   ingressClassName: nginx
  12.   
  13.   # 路由规则(核心!)
  14.   rules:
  15.   - host: www.meme1.com   # 访问域名
  16.     http:  # 因为是七层的,所以是http访问
  17.       paths:
  18.       - path: /           # URL 路径
  19.         pathType: Prefix  # 匹配类型
  20.         backend:  # 将符合上面的规则转发到哪一个svc上
  21.           service:
  22.             name: svcn1   # 转发到哪个 Service
  23.             port:
  24.               number: 80  # Service 端口
  25.   - host: www.meme2.com
  26.     http:
  27.       paths:
  28.       - path: /
  29.         pathType: Prefix
  30.         backend:
  31.           service:
  32.             name: svcn2
  33.             port:
  34.               number: 80
复制代码

  • pathType详解

    • Prefix 前缀匹配,/匹配全部的,/api 匹配/api/,/api/v1, /api/user
    • Exact 准确匹配,必须完全一样即可, /api 不匹配/api/

  • 只必要访问根目次 添加一个表明即可
  1. annotations:
  2.   nginx.ingress.kubernetes.io/rewrite-target: /
复制代码
7、ingress进阶实验


  • 同一个域名差别的路径转发到差别的服务
  • 访问a.com/v1 跳转到v1服务
  • 访问a.com/v2 跳转到v2 服务
  1. [root@master01 svc]# cat in1.yml
  2. apiVersion: networking.k8s.io/v1
  3. kind: Ingress
  4. metadata:
  5.   name: ingress-1
  6.   annotations:
  7.     nginx.ingress.kubernetes.io/rewrite-target: /
  8. spec:
  9.   ingressClassName: "nginx"
  10.   rules:
  11.   - host: "a.com"
  12.     http:
  13.       paths:
  14.       - path: /v1
  15.         pathType: Prefix
  16.         backend:
  17.           service:
  18.             name: v1
  19.             port:
  20.               number: 80
  21.   - host: "a.com"
  22.     http:
  23.       paths:
  24.       - path: /v2  # a.com/v2 由于是nginx的配置(这个配置会翻译成nginx的配置)
  25.                    # a.com/v2 会跳转到 /usr/share/nginx/html/v1/index.html 这个页面
  26.         pathType: Prefix
  27.         backend:
  28.           service:
  29.             name: v2
  30.             port:
  31.               number: 80
  32. [root@master01 svc]#  kubectl describe ingress ingress-1
  33. Name:             ingress-1
  34. Labels:           <none>
  35. Namespace:        default
  36. Address:          10.103.125.75
  37. Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
  38. Rules:
  39.   Host        Path  Backends
  40.   ----        ----  --------
  41.   a.com      
  42.               /v1   v1:80 (10.246.73.166:80)
  43.   a.com      
  44.               /v2   v2:80 (10.246.73.167:80)
  45. Annotations:  nginx.ingress.kubernetes.io/rewrite-target: /
  46. Events:
  47.   Type    Reason  Age                From                      Message
  48.   ----    ------  ----               ----                      -------
  49.   Normal  Sync    11m (x4 over 29m)  nginx-ingress-controller  Scheduled for sync
  50.   Normal  Sync    11m (x4 over 29m)  nginx-ingress-controller  Scheduled for sync
  51.   Normal  Sync    11m (x4 over 29m)  nginx-ingress-controller  Scheduled for sync
复制代码

  • 客户端测试
  1. [root@master01 svc]# curl -H "Host: a.com" http://192.168.50.22:32162/v1
  2. v1
  3. [root@master01 svc]# curl -H "Host: a.com" http://192.168.50.22:32162/v2
  4. v2
复制代码

  • ingress 只负责转发,不负责修改路径
  • 第一种在pod内里创建v2,v1目次,存放网页文件
  • 第二种,路径重写,跳转到/目次即可
  1.   annotations:
  2.     nginx.ingress.kubernetes.io/rewrite-target: /
复制代码
8、ingress总结


  • 负责路径的转发,这个设置会翻译成nginx的设置,雷同的,不会修改路径
  • 这个访问路径必须真实存在,才气访问到
6、LoadBalance

1、loadbalance是什么呢?


  • 之前学过的nodeport,必要袒露端口,3w以上的,不方便,访问必要加上端口
  • loadbalance直接分配一个公网ip,直接对外提供服务

    • lb=nodeport + 云厂商的外部负载均衡器

  • 由于我没有公网ip,因此必要下载一个插件,模拟一下即可
  1. # 这个external-ip 这个就是公网ip地址,没有指定,就是none
  2. [root@master01 wordpress]# kubectl get svc
  3. NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
  4. kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   15d
复制代码
2、下载插件文件
  1. [root@master01 lb]# wget https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml
  2. [root@master01 lb]# kubectl apply -f metallb-native.yaml
  3. [root@master01 lb]# kubectl get pod -n metallb-system
  4. NAME                         READY   STATUS    RESTARTS   AGE
  5. controller-7967ffcf8-h29sm   1/1     Running   0          6m15s
  6. speaker-btw9v                1/1     Running   0          6m15s
  7. speaker-lt2h6                1/1     Running   0          6m15s
  8. speaker-rvslq                1/1     Running   0          6m15s
复制代码
3、创建地点池和绑定
  1. # 安装一个网络计算工具
  2. yum -y install sipcalc
  3. [root@k-master svc]# sipcalc 192.168.50.100/24
  4. -[ipv4 : 192.168.50.100/24] - 0
  5. [CIDR]
  6. Host address                - 192.168.50.100
  7. Host address (decimal)        - 3232248420
  8. Host address (hex)        - C0A83264
  9. Network address                - 192.168.50.0
  10. Network mask                - 255.255.255.0
  11. Network mask (bits)        - 24
  12. Network mask (hex)        - FFFFFF00
  13. Broadcast address        - 192.168.50.255
  14. Cisco wildcard                - 0.0.0.255
  15. Addresses in network        - 256
  16. Network range                - 192.168.50.0 - 192.168.50.255
  17. Usable range                - 192.168.50.1 - 192.168.50.254
复制代码
  1. # 创建地址池
  2. [root@k-master svc]# cat pools.yaml
  3. apiVersion: metallb.io/v1beta1
  4. kind: IPAddressPool
  5. metadata:
  6.   name: first-pool
  7.   namespace: metallb-system
  8. spec:
  9.   addresses:
  10.   - 192.168.50.200-192.168.50.220
  11. # 创建实例绑定地址池
  12. [root@k-master svc]# cat l2.yaml
  13. apiVersion: metallb.io/v1beta1
  14. kind: L2Advertisement
  15. metadata:
  16.   name: example
  17.   namespace: metallb-system
  18. spec:
  19.   ipAddressPools:
  20.   - first-pool
  21. [root@k-master svc]# kubectl get ipaddresspools.metallb.io  -n metallb-system
  22. NAME         AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
  23. first-pool   true          false             ["192.168.50.200-192.168.50.220"]
复制代码
4、创建svc
  1. # 因为是LoadBalancer,所以会自动的分配外部ip地址,从之前创建的地址池中分配一个地址
  2. # 如果是对外提供的,就需要使用公网ip
  3. # 还会创建一个nodeport端口
  4. [root@k-master svc]# kubectl expose deployment nginx --name svc666 --port 80 --target-port 80 --type LoadBalancer
  5. service/svc666 exposed
  6. [root@k-master svc]# kubectl get svc
  7. NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
  8. kubernetes   ClusterIP      10.96.0.1      <none>           443/TCP        17d
  9. svc666       LoadBalancer   10.99.233.85   192.168.50.200   80:31439/TCP   3s
  10. # 直接访问ip即可,但是这个80端口如果换成其他的81,就需要加上端口了
复制代码
5、lb访问原理


  • 直接访问公网ip地点
  • 哀求到达集群节点的nodeport端口
  • 根据haproxy实现的ipvs规则转发到后端的pod
  • Nginx pod 相应
  • 公网ip+NodePort
6、lb访问
  1. # 直接访问这个模拟出来的公网ip地址就能访问到后端关联的pod
  2. # 不需要添加端口
  3. # 如果购买了域名的话,可以使用域名访问
  4. [root@k-master svc]# curl 192.168.50.200  # 等价于 :80
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <title>Welcome to nginx!</title>
  9. </head>
  10. <body>
  11. <h1>Welcome to nginx!</h1>
  12. <p>If you see this page, the nginx web server is successfully installed and
  13. working. Further configuration is required.</p>
  14. <p>For online documentation and support please refer to
  15. nginx.org.<br/>
  16. Commercial support is available at
  17. nginx.com.</p>
  18. <p><em>Thank you for using nginx.</em></p>
  19. </body>
  20. </html>
复制代码
7、实验


  • wordpress和mysql

    • mysql和wordpress内部通讯,dns大概clusterip  wordpress访问mysql-svc就能访问到mysql
    • 外部访问wordpress,利用nodeport

1、创建mysql的pod和svc
  1. [root@master01 wordpress]# kubectl run db --image=mysql --image-pull-policy=IfNotPresent --dry-run=client -o yaml > db.yml
  2. [root@master01 wordpress]# cat db.yml
  3. apiVersion: v1
  4. kind: Pod
  5. metadata:
  6.   creationTimestamp: null
  7.   labels:
  8.     run: db
  9.   name: db
  10. spec:
  11.   nodeName: node  # 指定调度在node节点上
  12.   containers:
  13.   - image: mysql
  14.     imagePullPolicy: IfNotPresent
  15.     name: db
  16.     resources: {}
  17.     env:
  18.     - name: "MYSQL_ROOT_PASSWORD"  # 添加环境变量
  19.       value: "123"
  20.     - name: "MYSQL_DATABASE"
  21.       value: "wordpress"
  22.   dnsPolicy: ClusterFirst
  23.   restartPolicy: Always
  24. [root@master01 wordpress]# kubectl expose pod db --type ClusterIP --port=3306 --target-port 3306  --name db-svc --dry-run=client -o yaml > db-svc.yml
  25. [root@master01 wordpress]# cat db-svc.yml
  26. apiVersion: v1
  27. kind: Service
  28. metadata:
  29.   creationTimestamp: null
  30.   labels:
  31.     run: db
  32.   name: db-svc
  33. spec:
  34.   ports:
  35.   - port: 3306
  36.     protocol: TCP
  37.     targetPort: 3306
  38.   selector:
  39.     run: db
  40.   type: ClusterIP
  41. [root@master01 wordpress]# kubectl get pod,svc
  42. NAME     READY   STATUS    RESTARTS   AGE
  43. pod/db   1/1     Running   0          8m31s
  44. NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
  45. service/db-svc       ClusterIP   10.101.1.39   <none>        3306/TCP   5m50s
  46. service/kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    15d
复制代码
集群内部访问
  1. # 可以直接通过ClusterIP进行访问对应的pod
  2. [root@master01 wordpress]# mysql -uroot -p123 -h 10.101.1.39
  3. # 访问svc就能访问到对应的pod
复制代码
2、创建wordpress和svc
  1. kubectl run web-wordpress --image=wordpress --image-pull-policy=IfNotPresent --dry-run=client -o yaml > web.yml
  2. [root@master01 wordpress]# cat web.yml
  3. apiVersion: v1
  4. kind: Pod
  5. metadata:
  6.   creationTimestamp: null
  7.   labels:
  8.     run: web-wordpress
  9.   name: web-wordpress
  10. spec:
  11.   nodeName: master02
  12.   containers:
  13.   - image: wordpress
  14.     imagePullPolicy: IfNotPresent
  15.     name: web-wordpress
  16.     resources: {}
  17.     env:
  18.     - name: "WORDPRESS_DB_HOST"  # 连接后端数据的地址,这里使用的是svc,也可以使用svc的dns地址,这样svc的ip变化后,也不受影响,db-svc.default.svc.cluster.local
  19.       value: "10.101.1.39"
  20.     - name: "WORDPRESS_DB_USER"  # 数据库的用户
  21.       value: "root"
  22.     - name: "WORDPRESS_DB_PASSWORD"  # 数据库的密码
  23.       value: "123"
  24.     - name: "WORDPRESS_DB_NAME"  # 使用哪一个数据库
  25.       value: "wordpress"
  26.   dnsPolicy: ClusterFirst
  27. kubectl expose pod web-wordpress --type NodePort --port 80 --target-port 80 --name web-svc --dry-run=client -o yaml > web-svc.yml
  28. [root@master01 wordpress]# kubectl get pod
  29. NAME            READY   STATUS    RESTARTS   AGE
  30. db              1/1     Running   0          19m
  31. web-wordpress   1/1     Running   0          6m8s
  32. [root@master01 wordpress]# kubectl get svc
  33. NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
  34. db-svc       ClusterIP   10.101.1.39   <none>        3306/TCP       17m
  35. kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        15d
  36. web-svc      NodePort    10.98.68.65   <none>        80:31366/TCP   4m20s
复制代码

  • 欣赏器访问
  1. 192.168.50.20:31366
复制代码

  • 这个实验实现了什么呢?

    • pod与pod之间的通讯,可以通过ip,svc(svc对应后端的pod),大概svc的dns通讯
    • 这个wordpress的svc利用的是NodePort,对外提供服务的

svc中nodeport核心参数

字段管谁的流量可选项作用externalTrafficPolicy外部流量(你 curl 节点 IP)Cluster / Local控制外部访问要不要跨节点internalTrafficPolicy内部流量(Pod 访问 Service)Cluster / Local控制内部访问要不要跨节点

本帖子中包含更多资源

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

×
回复

使用道具 举报

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

本版积分规则

登录后关闭弹窗

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

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

GMT+8, 2026-9-30 00:43 , Processed in 0.024888 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5 Licensed

© 2001-2026 Discuz! Team.

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