{
    "componentChunkName": "component---src-templates-issues-tsx",
    "path": "/issues/520",
    "result": {"data":{"issuesJson":{"id":"bc6906c7-e540-5933-93fa-2948fe7863c7","title":"skooner-k8s/skooner: 简单的 Kubernetes 实时仪表板和管理工具","number":520,"bodyHTML":"<div align=\"center\" dir=\"auto\">\n<p dir=\"auto\"><a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/a15b413168923d02e21292705ceaf86b92675f98e250c5c896a02ba7504a6eae/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f657279616a662f7475406d61696e2f696d672f696d6167655f32303234303432305f3231343430382e676966\"><img src=\"https://camo.githubusercontent.com/a15b413168923d02e21292705ceaf86b92675f98e250c5c896a02ba7504a6eae/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f657279616a662f7475406d61696e2f696d672f696d6167655f32303234303432305f3231343430382e676966\" width=\"100%\" height=\"3\" data-animated-image=\"\" data-canonical-src=\"https://cdn.jsdelivr.net/gh/eryajf/tu@main/img/image_20240420_214408.gif\" style=\"max-width: 100%; height: auto; max-height: 3px;\"></a><br><br></p>\n<markdown-accessiblity-table><table role=\"table\">\n<thead>\n<tr>\n<th align=\"right\">Repos</th>\n<th align=\"left\"><a href=\"https://github.com/skooner-k8s/skooner\">skooner-k8s/skooner</a></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td align=\"right\"><strong>Views</strong></td>\n<td align=\"left\"><a href=\"https://github.com/opsre/awesome-ops\"><img src=\"https://camo.githubusercontent.com/6008ce5361959fe0deea860895f8676b6cae9fbdd48f6121fb1677f8fcfd393a/68747470733a2f2f76696577732e77686174696c656172656e65642e746f6461792f76696577732f6769746875622f736b6f6f6e65722d6b38732f736b6f6f6e65722e737667\" alt=\"views\" data-canonical-src=\"https://views.whatilearened.today/views/github/skooner-k8s/skooner.svg\" style=\"max-width: 100%;\"></a></td>\n</tr>\n<tr>\n<td align=\"right\"><strong>Stars</strong></td>\n<td align=\"left\"><a href=\"https://github.com/opsre/awesome-ops\"><img src=\"https://camo.githubusercontent.com/660de9ccd8d5f8be2c6f9c27be9f79d6dc3d89071d9677f76443637ae4529525/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f736b6f6f6e65722d6b38732f736b6f6f6e65723f636f6c6f723d663266303864266c6f676f3d556e64657274616c65266c6f676f436f6c6f723d656234363330\" alt=\"stars\" data-canonical-src=\"https://img.shields.io/github/stars/skooner-k8s/skooner?color=f2f08d&amp;logo=Undertale&amp;logoColor=eb4630\" style=\"max-width: 100%;\"></a></td>\n</tr>\n<tr>\n<td align=\"right\"><strong>Forks</strong></td>\n<td align=\"left\"><a href=\"https://github.com/opsre/awesome-ops\"><img src=\"https://camo.githubusercontent.com/7809dc632080ed7615a0fe0b968bc7902bc237044336ea6a3ca37ea485fa4e71/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f666f726b732f736b6f6f6e65722d6b38732f736b6f6f6e65723f636f6c6f723d626138366562266c6f676f3d48616e647368616b65266c6f676f436f6c6f723d656136616136\" alt=\"forks\" data-canonical-src=\"https://img.shields.io/github/forks/skooner-k8s/skooner?color=ba86eb&amp;logo=Handshake&amp;logoColor=ea6aa6\" style=\"max-width: 100%;\"></a></td>\n</tr>\n<tr>\n<td align=\"right\"><strong>License</strong></td>\n<td align=\"left\"><a href=\"https://github.com/opsre/awesome-ops\"><img src=\"https://camo.githubusercontent.com/c4d91682dba9559279b632c716980cfdfcf6e22199fbf1c54e45e0cadda8a92f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f736b6f6f6e65722d6b38732f736b6f6f6e65723f6c6f676f3d64617461253341696d616765253246706e672533426261736536342532436956424f5277304b47676f414141414e53556845556741414144414141414177434159414141425841766d48414141414358424957584d41414173544141414c457745416d70775941414144336b6c45515652346e4f335953557a5555426748384a726f57567255474a66456d3773584e63534446784d544c327069347348456778654e526f77586770455742445552522532424e414e4f4b4f4b36366f6f4b4a4742586545475263574163455646475152484677516d483525324630774861655748493944554455354c356b6e6568644f62377a66652532423139636e434a47495243516945596c514237594a4979474c38616f73756c565a36695246516a69474b6b7564576735614c6c704f70704e586e665071773555304459524a6d56786a4367464633424c755a476d416f5655694b4541726d583744375553677351706f72674761336748664b34483663754262435644334771683141352532424c6745253242467749656e514d306a6f446f66714c6f48564e7742796d384370546e416d327a51713073676478624964515a556c416b7150415a3664676a303541446f59526f6f66792532466f5869726f376b3551586a4c6f70677a4b69514e6c4c4461716f4967754577426a7a7150355066446a45394479495879493633464d547751464d43567271774e61763451666f52673538514625324266724d485172454b3844546f434d714e4179574e4866786d54526f4c4f726d5352566747744466714345715a4f4851727a6f34706243557341333431365169364551394b476a6345465267484f724f4b6e5536574162396247455459656b4b7843766a546167394534706a653534446b3551503862624d4859762532464333756541654a6b50304f4778422532424a70426e4172595238455951516e6f4e31414e4661426e5050356c385372736559514c303641646b30464a5938484f5761424d6c6541486a683068506f73497a6c6f3876304125324633345a694f6548726130714b52504d5653493774762532423932747725324676687855654252713456454c674d376642714b354770526d6f514c584e7075625475367a6f4e52706754386e5051627138347764253246494375767978694b4871694e41664933774d367549684271476b4c696977414f734b44714f68743749747239567938536a52424557667941627225324668523142667056514664484a42253246423268683778376a36517077435665655951326b72554235436c636a3641326d3067576a25324244306d4c34397a573563517943484c4e37726a6c6d6d6174457958582532464372547a412532466f51785a6b576c39474a5443566f25324279546a3837253242346769504b6376307149486f344156344430565a727251493334706e70524d36357875652532467a417265453425324654253246536f676c664542794d7369517441546c4c3352414a355948725378365a44665337307337754d486842705225324659423573305057366f455270316236253246667252684b3353444c35546965364f515548516c5133735644752532427a50636b397657453973747225324236496a533967486d5750616861444a25324277434b364e494242587348423948796b587378774470686c436d416476706c6162554a4e6e5a504239342532464e7436784f6538587a4562503257684d335741673147756236744825324233513150673337365239713475716c6e6f36676448476a444f5139306562303141484d3672596975554a314f713472344656756a35765239427a4d3957674e764f7977446869495951467667626366774166774d764863615067425041253246447948476a50624e394138616d6562636477416444354e6633373574787165774e5552656f797677424958594c645170576c6877465771745061435044334173467541535636717171496c62304a766b564331464c39576b4c55556c55574b337a585a4c46432532423125324642726f46746f364f7358497545594a5034447a7a5732594656316f4a614141414141456c46546b5375516d4343\" alt=\"license\" data-canonical-src=\"https://img.shields.io/github/license/skooner-k8s/skooner?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAD3klEQVR4nO3YSUzUUBgH8JroWVrUGJfEm7sXNcSDFxMTL2pi4sHEgxeNRowXgpEWBDURR%2BNANOKOK66ooKJGBXeEGRcWAcEVFGQRHFwQmH5%2F0wHaeWHI9DUDU5L5knehdOb7zfe%2B19cnCJGIRCQiEYlQB7YJIyGL8aosulVZ6iRFQjiGKkudWg5aLlpOppNXnfPqw5U0DYRJmVxjCgFF3BLuZGmAoVUiKEArmX7D7USgsQporgGa3gHfK4H6cuBbCVD3Gqh1A5%2BLgE%2BFwIenQM0joDofqLoHVNwBym8CpTnAm2zQq0sgdxbIdQZUlAkqPAZ6dgj05ADoYRoofy%2FoXiro7k5QXjLopgzKiQNlLDaqoIguEwBjzqP5PfDjE9DyIXyI63FMTwQFMCVrqwNav4QfoRg58QF%2BfrMHQrEK8DToCMqNAyWNHfxmTRoLOrmSRVgGtDfqCEqZOHQrzo4pbCUsA3416Qi6EQ9KGjcEFRgHOrOKnU6WAb9bGETYekKxCvjTag9E4pje54Dk5QP8bbMHYv%2FC3ueAeJkP0OGxB%2BJpBnArYR8EYQQnoN1ANFaBnPP5l8SrseYQL06Adk0FJY8HOWaBMleAHjh0hPosIzlo8v0A%2F34ZiOeHra0qKRPMVSI7tv%2B92tw%2FvhxUeBRq4VELgM7fBqK5GpRmoQLXNpubTu6zoNRpgT8nPQbq84wd%2FICuvyxiKHqiNAfI3wM6uIhBqGkLiiwAOsKDqOht7Itr9Vy8SjRBEWfyAbr%2FhR1BfpVQFdHJB%2FB2hh7x7j6QpwCVeeYQ2krUB5Clcj6A2m0gWj%2BD0mL49zW5cQyCHLN7rjlmmatEyXX%2FCrTzA%2FoQxZkWl9GJTCVo%2ByTj87%2B4giPKcv0qIHo4AV4D0VZrrQI34pnpRM65xue%2FzAreE4%2FT%2FSoglfEByMsiQtATlL3RAJ5YHrSx6ZDfS70s7uMHhBpR%2FYB5s0PW6oERp1b6%2FfrRhK3SDL5Tie6OQUHQlQ3sVDu%2BzPck9vWE9str%2B6IjS9gHmWPahaDJ%2BwCK6NIBBXsHB9HykXsxwDphlCmAdvplabUJNnZPB94%2FNt6xOe8XzEbP2WhM3WAg1Gub6tH%2B3Q1Pg376R9q4uqlno6gdHGjDOQ90eb01AHM6rYiuUJ1Oq4r4FVuj5vR9BzM9WgNvOywDhiIYQFvgbcfwAfwMvHcaPgBPA%2FDyHGjPbN9A8amebcdwAdD5Nf375txqewNUReoyvwBIXYLdQpWlhwFWqtPaCPD3AsFuASV6qqqIlb0JvkVC1FL9WkLUUlUWK3zXZLFC%2B1%2FBroFto6OsXIuEYJP4DzzW2YFV1oJaAAAAAElFTkSuQmCC\" style=\"max-width: 100%;\"></a></td>\n</tr>\n<tr>\n<td align=\"right\"><strong>UpdatedAt</strong></td>\n<td align=\"left\"><a href=\"https://github.com/opsre/awesome-ops\"><img src=\"https://camo.githubusercontent.com/c3aeaa0c95d9e67cd1bda63d63f483bd6130fb6d92ec3102c04a99fb089a15f9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f736b6f6f6e65722d6b38732f736b6f6f6e65723f646973706c61795f74696d657374616d703d636f6d6d6974746572266c6f676f3d64617461253341696d616765253246706e672533426261736536342532436956424f5277304b47676f414141414e5355684555674141414234414141416543415941414141374d4b3669414141414358424957584d41414173544141414c457745416d7077594141414648556c45515652346e4c5658375539615678776d3236646c582532466468627825324232253246516e626b7655627264554151674a4a496655444e574454546d4f76314651554661504a346b7573725630314a7431734e70637453327533626f745a746d786439744a5346536f714b71494635625944464c436f76436c656673747a4a387758524c445a4c7a6e6b634f343535376e3364332532466e655a3472454f515a74315771462532423858467234253242664f4c4565326a6f59307a776638546f795a50766a45676b4c592532426b306d6d72584f36644b696e787a476b30666a5430782532425279723055716e6359637a4d317263347451253242497270324c4758646f344e4334567657715453373277716c632532427231334f527269364b6458646e624f484c6c776c7a4a70524b6e3657342532424b36706f4f434e6e494166486a253246253242776168495a4234764b6e715a6630714a704e49716c2532467638545530634e6c3572627963337730516e54703379324c54614a374d314e617844723266526e315370504736476961323174664533345463614f617931694d55564f5146624659714957536f31573854694156616e43306576584f4542375770313448466232327a453566714c4f433545524c515769644e614e49347545636339693768634a6c644868324e57725135674464624f6c7061756d49754c62326174415144506e7a3062384e6257636d785656524a33486d7870536377777a4f4a6d4b44524765384c6c435a444c4739673754496e5631516c376462586256316533675430574b697243466f6d6b5079767758466c5a474a4f6a563625324253743634757564445a4f55354555636f782532464d455144567674364d62634e3237593341797a687633737061557242365a3971724a534f3139657a6a387032704c426b4a792532426343484a7857493567573574636652527a31645531394766476b6f7539505a4f34736d52396a4746777065783444793362766e6d4b79706f74625531335669646a71595a68726a343972764d457425324625324659714c7a396430304e6a57253246637a67796f394f35317a7336614e6c6f354644747530445a675146686c47584a30644241446f4e6864367576703657686f617967374e394c564748386d443462253246486e667455516f4e4734764c51306769784d716c5725324234714f6a744e48446733723166365969525347785279375576714c62395534716b716e78504f4e7661356c447048723125324279794b524e4b57425a793565644d554842326d3572792532422532424551772532427a6766347a6f39253246306f634e3357527a4c4277344a2532424a7950574372716d4967475974554f735744346f785a46516f50556a4770564871493425324661666b51504336665a5165654d31253242764c7549516e6a754257514444437363726d485039656f4e5041744271664f6e5875614b25324268364a45624772732532427076764d6d78654962683836336162565065597953456f39464a48704e4d464a59253242503563575a6b6667374f3174537759436553514c54593345385130392532464256504a556c78516a7368543142736343593032723955445542667643484236367063665041336c794165336e6772332532463437584467614a7a736c7937787741364e5a746c555550437541487161536a5549502532427375653842525741432532464e6651374a5a505a35397330476a3756747049537a34685125324243706658474d4b685a63764c70554b7866574d386f68766637702532464f446a4842666356463849736b383267314648796b63564645253242555a414158343761452532464d6c34504f3530506e75683025324678346e6d637957507364774468427836436d6b4c562532466746446a594b784f4a4f4674623077517949684c39527943774b33414f664947703159464542686e4d4a634c525745624b644b516f55366e63545a6b494544696341792532463831645675454d3552775066657934784f7830496b25324649324e6e466b692532425761664f6f464959466367595a43797864376543556a626334416d46363566742532466b4d686b336f25324235686337734d4a79716a4a45477659466151464972375930775077384246415925324236253242766d6b3377367a7a5275444d6d5a5652736668385274413075455453443775434254364459514e36697665553066706b594c6a453671725672744f78654e4b553954484c5a4a396b4255324a427342685635416976422532466f4b61514e4b675043427744596149665a4334616454684f71463457454e56694c4a77566f586f62664c424b56773637414f6154734c6336355461564b32317651344c613939654b6359673576627873624f627a5451394e37554b4467554f3177446a6944494942736868357a746733396e514d4c535a4248344f7a424f55444551586d323036643366634c67737762585141345068634b336e6873775531427a3877765130395248472532466f597933656a6677424e6d746f59714c4130586741414141424a52553545726b4a676767253344253344266c6162656c3d557064617465644174\" alt=\"last-commit\" data-canonical-src=\"https://img.shields.io/github/last-commit/skooner-k8s/skooner?display_timestamp=committer&amp;logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHUlEQVR4nLVX7U9aVxwm26dlX%2Fdhbx%2B2%2FQnbkvUbrdUAQgJJIfUDNWDTTmOv1FQUFaPJ4kusrV01Jt1sNpctS2u3botZtmxd9tJSFSoqKqIF5bYDFLCovClefstzJ8wXRLDZLznkcO4557n3d3%2FneZ4rEOQZt1WqF%2B8XFr4%2BfOLEe2joY0zwf8ToyZPvjEgkLY%2Bk0mmrXO6dKinxzGk0fjT0x%2BRyr0UqncYczM1rc4tQ%2BIrp2LGXdo4NC4VvWqTS72wqlc%2Br13ORri6KdXdnbOHLlwlzJpRKn6W4%2BK6poOCNnIAfHj%2F%2BwahIZB4vKnqZf0qJpNIql%2Fv8TU0cNl5rbyc3w0QnTp3y2LTaJ7M1NaxDr2fRn1SpPG6Gia21tfE34TcaOay1iMUVOQFbFYqIWSo1W8TiAVanC0evXOEB7Wp14HFb22zE5fqLOC5ERLQWidNaNI4uEcc9i7hcJldHh2NWrQ5gDdbOlpaumIuLb2atAQDPnz0b8NbWcmxVVRJ3HmxpScwwzOJmKDRGe8LlCZDLG9g7TInV1Ql7dbXbV1e3gT0WKirCFomkPyvwXFlZGJOjV6%2BSt64uudDZOU5EUcox%2FMEQDVvt6MbcN27Y3Ayzhv3spaUrB6Z9qrJSO19ezj8p2pLBkJy%2BcCHJxWI5gW5tcfRRz1dU19GfGkou9PZO4smR9jGFwpex4Dy3bvnmKypotbU13VidjqYZhrj49rvMEt%2F%2FYqLz9d00NjW%2Fczgyo9O51zs6aNlo5FDtu0DZgQFhlGXJ0dBADoNhd6uvp6Whoayg7N9LVGH8mD4b%2FHnftUQoNG4vLQ0gixMqlW%2B4qOjtNHDg3r1f6YiRSGxRy7UvqLb9U4qkqnxPONva5lDpHr1%2ByyKRNKWBZy5edMUHB2m5ry%2B%2BEQw%2Bzgf4zo9%2F0ocN3WRzLBw4J%2BJyPWCrqmIgGYtUOsWD4oxZFQoPUjGpVHqI4%2FafkQPC6fZQeeM1%2BvLuIQnjuBWQDDCscrmHP9eoNPAtBqfOnXuaK%2Bh6JEbGrs%2BpvvMmxeIbh863abVPeYySEo9FJHpNMFJY%2BP5cWZkfg7O1tSwYCeSQLTY3E8Q09%2FBVPJUlxQjshT1BscCY02r9UDUBfvCHB66pcfPA3lyAe3ngr3%2F47XDgaJzsly7xwA6NZtlUUPCuAHqaSjUIP%2Bsue8BRWAC%2FNfQ7JZPZ59s0Gj7VtpISz4hQ%2BCpfXGMKhZcvLpUKxfWM8ohvf7p%2FODjHBfcVF8Isk82g1FHykcVFE%2BUZAAX47aE%2FMl4PO50Pnuh0%2Fx4nmcyWPsdwDhBx6CmkLV%2FgFDjYKxOJOFtb0wQyIhL9RyCwK3AOfIGp1YFEBhnMJcLRWEbKdKQoU6ncTZkIEDicAy%2F81dVuEM5RwPfey4xOx0Ik%2FI2NnFki%2BWafOoFIYFcgYZCyxd7eCUjbc4AmF65ft%2FkMhk3o%2B5hc7sMJyqjJEGvYFaQFIr7Y0wPw8BFAY%2B6%2Bvmk3w6zzRuDMmZVRsfh8RtA0uETSD7uCBT6DYQN6iveU0fpkYLjE6qrVrtOxeNKU9THLZJ9kBU2JBsBhV5AivB%2FoKaQNKgPCBwDYaIfZC4adThOqF4WENViLJwVoXobfLBKVw67AOaTsLc65TaVK21vQ4La99eKcYg5vbxsbObzTQ9N7UKDgUO1wDjiDIIBshh5ztg39nQMLSZBH4OzBOUDEQXm206d3fcLgswbXQA4PhcK3nhswU1Bz8wvQ09RHG%2FoYy3ejfwBNmtoYqLA0XgAAAABJRU5ErkJggg%3D%3D&amp;label=UpdatedAt\" style=\"max-width: 100%;\"></a></td>\n</tr>\n<tr>\n<td align=\"right\"><strong>CreatedAt</strong></td>\n<td align=\"left\"><a href=\"https://github.com/opsre/awesome-ops\"><img src=\"https://camo.githubusercontent.com/be801b4f79915c0eaa803d5f9f2ea5a2683699f5ccbb6e2794a04925b773c396/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f637265617465642d61742f736b6f6f6e65722d6b38732f736b6f6f6e65723f6c6f676f3d64617461253341696d616765253246706e672533426261736536342532436956424f5277304b47676f414141414e5355684555674141414234414141416543415941414141374d4b3669414141414358424957584d41414173544141414c457745416d7077594141414648556c45515652346e4c5658375539615678776d3236646c582532466468627825324232253246516e626b7655627264554151674a4a496655444e574454546d4f76314651554661504a346b7573725630314a7431734e70637453327533626f745a746d786439744a5346536f714b71494635625944464c436f76436c656673747a4a387758524c445a4c7a6e6b634f343535376e3364332532466e655a3472454f515a74315771462532423858467234253242664f4c4565326a6f59307a776638546f795a50766a45676b4c592532426b306d6d72584f36644b696e787a476b30666a5430782532425279723055716e6359637a4d317263347451253242497270324c4758646f344e4334567657715453373277716c632532427231334f527269364b6458646e624f484c6c776c7a4a70524b6e3657342532424b36706f4f434e6e494166486a253246253242776168495a4234764b6e715a6630714a704e49716c2532467638545530634e6c3572627963337730516e54703379324c54614a374d314e617844723266526e315370504736476961323174664533345463614f617931694d55564f5146624659714957536f31573854694156616e43306576584f4542375770313448466232327a453566714c4f433545524c515769644e614e49347545636339693768634a6c644868324e57725135674464624f6c7061756d49754c62326174415144506e7a3062384e6257636d785656524a33486d7870536377777a4f4a6d4b44524765384c6c435a444c4739673754496e5631516c376462586256316533675430574b697243466f6d6b5079767758466c5a474a4f6a563625324253743634757564445a4f55354555636f782532464d455144567674364d62634e3237593341797a687633737061557242365a3971724a534f3139657a6a387032704c426b4a792532426343484a7857493567573574636652527a31645531394766476b6f7539505a4f34736d52396a4746777065783444793362766e6d4b79706f74625531335669646a71595a68726a343972764d457425324625324659714c7a396430304e6a57253246637a67796f394f35317a7336614e6c6f354644747530445a675146686c47584a30644241446f4e6864367576703657686f617967374e394c564748386d443462253246486e667455516f4e4734764c51306769784d716c5725324234714f6a744e48446733723166365969525347785279375576714c62395534716b716e78504f4e7661356c447048723125324279794b524e4b57425a793565644d554842326d3572792532422532424551772532427a6766347a6f39253246306f634e3357527a4c4277344a2532424a7950574372716d4967475974554f735744346f785a46516f50556a4770564871493425324661666b51504336665a5165654d31253242764c7549516e6a754257514444437363726d485039656f4e5041744271664f6e5875614b25324268364a45624772732532427076764d6d78654962683836336162565065597953456f39464a48704e4d464a59253242503563575a6b6667374f3174537759436553514c54593345385130392532464256504a556c78516a7368543142736343593032723955445542667643484236367063665041336c794165336e6772332532463437584467614a7a736c7937787741364e5a746c555550437541487161536a5549502532427375653842525741432532464e6651374a5a505a35397330476a3756747049537a34685125324243706658474d4b685a63764c70554b7866574d386f68766637702532464f446a4842666356463849736b383267314648796b63564645253242555a414158343761452532464d6c34504f3530506e75683025324678346e6d637957507364774468427836436d6b4c562532466746446a594b784f4a4f4674623077517949684c39527943774b33414f664947703159464542686e4d4a634c525745624b644b516f55366e63545a6b494544696341792532463831645675454d3552775066657934784f7830496b25324649324e6e466b692532425761664f6f464959466367595a43797864376543556a626334416d46363566742532466b4d686b336f25324235686337734d4a79716a4a45477659466151464972375930775077384246415925324236253242766d6b3377367a7a5275444d6d5a5652736668385274413075455453443775434254364459514e36697665553066706b594c6a453671725672744f78654e4b553954484c5a4a396b4255324a427342685635416976422532466f4b61514e4b675043427744596149665a4334616454684f71463457454e56694c4a77566f586f62664c424b56773637414f6154734c6336355461564b32317651344c613939654b6359673576627873624f627a5451394e37554b4467554f3177446a6944494942736868357a746733396e514d4c535a4248344f7a424f55444551586d323036643366634c67737762585141345068634b336e6873775531427a3877765130395248472532466f597933656a6677424e6d746f59714c4130586741414141424a52553545726b4a676767253344253344266c6162656c3d437265617465644174\" alt=\"create-at\" data-canonical-src=\"https://img.shields.io/github/created-at/skooner-k8s/skooner?logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHUlEQVR4nLVX7U9aVxwm26dlX%2Fdhbx%2B2%2FQnbkvUbrdUAQgJJIfUDNWDTTmOv1FQUFaPJ4kusrV01Jt1sNpctS2u3botZtmxd9tJSFSoqKqIF5bYDFLCovClefstzJ8wXRLDZLznkcO4557n3d3%2FneZ4rEOQZt1WqF%2B8XFr4%2BfOLEe2joY0zwf8ToyZPvjEgkLY%2Bk0mmrXO6dKinxzGk0fjT0x%2BRyr0UqncYczM1rc4tQ%2BIrp2LGXdo4NC4VvWqTS72wqlc%2Br13ORri6KdXdnbOHLlwlzJpRKn6W4%2BK6poOCNnIAfHj%2F%2BwahIZB4vKnqZf0qJpNIql%2Fv8TU0cNl5rbyc3w0QnTp3y2LTaJ7M1NaxDr2fRn1SpPG6Gia21tfE34TcaOay1iMUVOQFbFYqIWSo1W8TiAVanC0evXOEB7Wp14HFb22zE5fqLOC5ERLQWidNaNI4uEcc9i7hcJldHh2NWrQ5gDdbOlpaumIuLb2atAQDPnz0b8NbWcmxVVRJ3HmxpScwwzOJmKDRGe8LlCZDLG9g7TInV1Ql7dbXbV1e3gT0WKirCFomkPyvwXFlZGJOjV6%2BSt64uudDZOU5EUcox%2FMEQDVvt6MbcN27Y3Ayzhv3spaUrB6Z9qrJSO19ezj8p2pLBkJy%2BcCHJxWI5gW5tcfRRz1dU19GfGkou9PZO4smR9jGFwpex4Dy3bvnmKypotbU13VidjqYZhrj49rvMEt%2F%2FYqLz9d00NjW%2Fczgyo9O51zs6aNlo5FDtu0DZgQFhlGXJ0dBADoNhd6uvp6Whoayg7N9LVGH8mD4b%2FHnftUQoNG4vLQ0gixMqlW%2B4qOjtNHDg3r1f6YiRSGxRy7UvqLb9U4qkqnxPONva5lDpHr1%2ByyKRNKWBZy5edMUHB2m5ry%2B%2BEQw%2Bzgf4zo9%2F0ocN3WRzLBw4J%2BJyPWCrqmIgGYtUOsWD4oxZFQoPUjGpVHqI4%2FafkQPC6fZQeeM1%2BvLuIQnjuBWQDDCscrmHP9eoNPAtBqfOnXuaK%2Bh6JEbGrs%2BpvvMmxeIbh863abVPeYySEo9FJHpNMFJY%2BP5cWZkfg7O1tSwYCeSQLTY3E8Q09%2FBVPJUlxQjshT1BscCY02r9UDUBfvCHB66pcfPA3lyAe3ngr3%2F47XDgaJzsly7xwA6NZtlUUPCuAHqaSjUIP%2Bsue8BRWAC%2FNfQ7JZPZ59s0Gj7VtpISz4hQ%2BCpfXGMKhZcvLpUKxfWM8ohvf7p%2FODjHBfcVF8Isk82g1FHykcVFE%2BUZAAX47aE%2FMl4PO50Pnuh0%2Fx4nmcyWPsdwDhBx6CmkLV%2FgFDjYKxOJOFtb0wQyIhL9RyCwK3AOfIGp1YFEBhnMJcLRWEbKdKQoU6ncTZkIEDicAy%2F81dVuEM5RwPfey4xOx0Ik%2FI2NnFki%2BWafOoFIYFcgYZCyxd7eCUjbc4AmF65ft%2FkMhk3o%2B5hc7sMJyqjJEGvYFaQFIr7Y0wPw8BFAY%2B6%2Bvmk3w6zzRuDMmZVRsfh8RtA0uETSD7uCBT6DYQN6iveU0fpkYLjE6qrVrtOxeNKU9THLZJ9kBU2JBsBhV5AivB%2FoKaQNKgPCBwDYaIfZC4adThOqF4WENViLJwVoXobfLBKVw67AOaTsLc65TaVK21vQ4La99eKcYg5vbxsbObzTQ9N7UKDgUO1wDjiDIIBshh5ztg39nQMLSZBH4OzBOUDEQXm206d3fcLgswbXQA4PhcK3nhswU1Bz8wvQ09RHG%2FoYy3ejfwBNmtoYqLA0XgAAAABJRU5ErkJggg%3D%3D&amp;label=CreatedAt\" style=\"max-width: 100%;\"></a></td>\n</tr>\n</tbody>\n</table></markdown-accessiblity-table>\n<a href=\"https://github.com/opsre/awesome-ops\">\n</a><p dir=\"auto\"><a href=\"https://github.com/opsre/awesome-ops\"><img src=\"https://camo.githubusercontent.com/b964a36ea4078c39f603d46a29436371c7541a2f26e0228d7b21b9d9805b43d3/68747470733a2f2f736f6369616c6966792e6769742e63692f6f707372652f617765736f6d652d6f70732f696d6167653f6465736372697074696f6e3d3126666f6e743d42697474657226666f726b733d31266973737565733d31266c616e67756167653d31266c6f676f3d6874747073253341253246253246617661746172732e67697468756275736572636f6e74656e742e636f6d25324675253246313838353638303230266e616d653d31266f776e65723d31267061747465726e3d436972637569742b426f6172642670756c6c733d31267374617267617a6572733d31267468656d653d4c69676874\" alt=\"\" data-canonical-src=\"https://socialify.git.ci/opsre/awesome-ops/image?description=1&amp;font=Bitter&amp;forks=1&amp;issues=1&amp;language=1&amp;logo=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F188568020&amp;name=1&amp;owner=1&amp;pattern=Circuit+Board&amp;pulls=1&amp;stargazers=1&amp;theme=Light\" style=\"max-width: 100%;\"></a></p>\n<a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/a15b413168923d02e21292705ceaf86b92675f98e250c5c896a02ba7504a6eae/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f657279616a662f7475406d61696e2f696d672f696d6167655f32303234303432305f3231343430382e676966\"><img src=\"https://camo.githubusercontent.com/a15b413168923d02e21292705ceaf86b92675f98e250c5c896a02ba7504a6eae/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f657279616a662f7475406d61696e2f696d672f696d6167655f32303234303432305f3231343430382e676966\" width=\"100%\" height=\"3\" data-animated-image=\"\" data-canonical-src=\"https://cdn.jsdelivr.net/gh/eryajf/tu@main/img/image_20240420_214408.gif\" style=\"max-width: 100%; height: auto; max-height: 3px;\"></a>\n</div>\n<h1 dir=\"auto\">Skooner - Kubernetes Dashboard</h1>\n<p dir=\"auto\"><strong>We are changing our name from k8dash to Skooner! Please bear with us as we update our documentation and codebase to reflect this change. If you previously installed k8dash, you will need to uninstall it from your cluster and install Skooner instead. For most cases this can be done by running the following <code class=\"notranslate\">kubectl delete deployment,service k8dash</code></strong></p>\n<p dir=\"auto\">Skooner is the easiest way to manage your Kubernetes cluster. Skooner is now a sandbox project of the <a href=\"https://www.cncf.io/sandbox-projects\" rel=\"nofollow\">Cloud Native Computing Foundation</a>!</p>\n<ul dir=\"auto\">\n<li><strong>Full cluster management</strong>: Namespaces, Nodes, Pods, Replica Sets, Deployments, Storage, RBAC and more</li>\n<li><strong>Blazing fast and Always Live</strong>: no need to refresh pages to see the latest cluster status</li>\n<li><strong>Quickly visualize cluster health at a glance</strong>: Real time charts help quickly track down poorly performing resources</li>\n<li><strong>Easy CRUD and scaling</strong>: plus inline API docs to easily understand what each field does</li>\n<li><strong>100% responsive</strong> (runs on your phone/tablet)</li>\n<li><strong>Simple OpenID integration</strong>: no special proxies required</li>\n<li><strong>Simple installation</strong>: use the provided yaml resources to have skooner up and running in under 1 minute (no, seriously)</li>\n<li><strong>See Skooner in action</strong>:<br><br>\n<a href=\"http://www.youtube.com/watch?v=u-1jGAhAHAM\" title=\"Skooner - Kubernetes Dashboard\" rel=\"nofollow\"><img src=\"https://raw.githubusercontent.com/skooner-k8s/skooner/master/docs/videoThumbnail.png\" alt=\"Skooner - Kubernetes Dashboard\" style=\"max-width: 100%;\"></a></li>\n</ul>\n<br>\n<h2 dir=\"auto\">Table of Contents</h2>\n<ul dir=\"auto\">\n<li><a href=\"#skooner---kubernetes-dashboard\">Skooner - Kubernetes Dashboard</a>\n<ul dir=\"auto\">\n<li><a href=\"#table-of-contents\">Table of Contents</a></li>\n<li><a href=\"#prerequisites\">Prerequisites</a></li>\n<li><a href=\"#getting-started\">Getting Started</a></li>\n<li><a href=\"#kubectl-proxy\">kubectl proxy</a></li>\n<li><a href=\"#logging-in\">Logging in</a>\n<ul dir=\"auto\">\n<li><a href=\"#service-account-token\">Service Account Token</a></li>\n<li><a href=\"#oidc\">OIDC</a></li>\n<li><a href=\"#nodeport\">NodePort</a></li>\n<li><a href=\"#metrics\">Metrics</a></li>\n</ul>\n</li>\n<li><a href=\"#development\">Development</a></li>\n<li><a href=\"#skooner-architecture\">Skooner Architecture</a>\n<ul dir=\"auto\">\n<li><a href=\"#server\">Server</a></li>\n<li><a href=\"#client\">Client</a></li>\n</ul>\n</li>\n<li><a href=\"#license\">License</a></li>\n</ul>\n</li>\n</ul>\n<h2 dir=\"auto\">Prerequisites</h2>\n<ul dir=\"auto\">\n<li>A running Kubernetes cluster (e.g., <a href=\"https://kubernetes.io/docs/tasks/tools/install-minikube/\" rel=\"nofollow\">minikube</a>), with...\n<ul dir=\"auto\">\n<li><a href=\"https://github.com/kubernetes-incubator/metrics-server\">metrics server</a> installed (optional, but strongly recommended)</li>\n<li>configuration for <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens\" rel=\"nofollow\">OpenId Connect</a> authentication (optional)</li>\n</ul>\n</li>\n</ul>\n<p dir=\"auto\">(Back to <a href=\"#table-of-contents\">Table of Contents</a>)</p>\n<h2 dir=\"auto\">Getting Started</h2>\n<p dir=\"auto\">Deploy Skooner with something like the following...</p>\n<p dir=\"auto\">NOTE: never trust a file downloaded from the internet. Make sure to review the contents of <a href=\"https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner.yaml\" rel=\"nofollow\">kubernetes-skooner.yaml</a> before running the script below.</p>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"kubectl apply -f https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner.yaml\"><pre class=\"notranslate\">kubectl apply -f https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner.yaml</pre></div>\n<p dir=\"auto\">To access skooner, you must make it publicly visible. If you have an ingress server setup, you can accomplish by adding a route like the following:</p>\n<div class=\"highlight highlight-source-yaml notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"kind: Ingress\napiVersion: networking.k8s.io/v1\nmetadata:\n  name: skooner\n  namespace: kube-system\nspec:\n  rules:\n    - host: skooner.example.com\n      http:\n        paths:\n          - path: /\n            backend:\n              service:\n                name: skooner\n                port:\n                  number: 80\n            pathType: ImplementationSpecific\"><pre class=\"notranslate\"><span class=\"pl-ent\">kind</span>: <span class=\"pl-s\">Ingress</span>\n<span class=\"pl-ent\">apiVersion</span>: <span class=\"pl-s\">networking.k8s.io/v1</span>\n<span class=\"pl-ent\">metadata</span>:\n  <span class=\"pl-ent\">name</span>: <span class=\"pl-s\">skooner</span>\n  <span class=\"pl-ent\">namespace</span>: <span class=\"pl-s\">kube-system</span>\n<span class=\"pl-ent\">spec</span>:\n  <span class=\"pl-ent\">rules</span>:\n    - <span class=\"pl-ent\">host</span>: <span class=\"pl-s\">skooner.example.com</span>\n      <span class=\"pl-ent\">http</span>:\n        <span class=\"pl-ent\">paths</span>:\n          - <span class=\"pl-ent\">path</span>: <span class=\"pl-s\">/</span>\n            <span class=\"pl-ent\">backend</span>:\n              <span class=\"pl-ent\">service</span>:\n                <span class=\"pl-ent\">name</span>: <span class=\"pl-s\">skooner</span>\n                <span class=\"pl-ent\">port</span>:\n                  <span class=\"pl-ent\">number</span>: <span class=\"pl-c1\">80</span>\n            <span class=\"pl-ent\">pathType</span>: <span class=\"pl-s\">ImplementationSpecific</span></pre></div>\n<p dir=\"auto\">Note: <code class=\"notranslate\">networking.k8s.io/v1</code> Ingress is required for Kubernetes v1.22+; <code class=\"notranslate\">extensions/v1beta1</code> Ingress is deprecated in v1.14+ and unavailable in v1.22+.</p>\n<p dir=\"auto\">(Back to <a href=\"#table-of-contents\">Table of Contents</a>)</p>\n<h2 dir=\"auto\">kubectl proxy</h2>\n<p dir=\"auto\">Unfortunately, <code class=\"notranslate\">kubectl proxy</code> cannot be used to access Skooner. According to <a href=\"https://github.com/kubernetes/kubernetes/issues/38775#issuecomment-277915961\" data-hovercard-type=\"issue\" data-hovercard-url=\"/kubernetes/kubernetes/issues/38775/hovercard\">this comment</a>, it seems that <code class=\"notranslate\">kubectl proxy</code> strips the Authorization header when it proxies requests.</p>\n<blockquote>\n<p dir=\"auto\">this is working as expected. \"proxying\" through the apiserver will not get you standard proxy behavior (preserving Authorization headers end-to-end), because the API is not being used as a standard proxy</p>\n</blockquote>\n<p dir=\"auto\">(Back to <a href=\"#table-of-contents\">Table of Contents</a>)</p>\n<h2 dir=\"auto\">Logging in</h2>\n<p dir=\"auto\">There are multiple options for logging into the dashboard: <a href=\"#Service-Account-Token\">Service Account Token</a>, <a href=\"#oidc\">OIDC</a>, and <a href=\"#Nodeport\">NodePort</a>.</p>\n<h3 dir=\"auto\">Service Account Token</h3>\n<p dir=\"auto\">The first (and easiest) option is to create a dedicated service account. In the command line:</p>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"# Create the service account in the current namespace (we assume default)\nkubectl create serviceaccount skooner-sa\n\n# Give that service account root on the cluster\nkubectl create clusterrolebinding skooner-sa --clusterrole=cluster-admin --serviceaccount=default:skooner-sa\n\n# For Kubernetes v1.21 or lower\n# Find the secret that was created to hold the token for the SA\nkubectl get secrets\n\n# Show the contents of the secret to extract the token\nkubectl describe secret skooner-sa-token-xxxxx\n\n# For Kubernetes v1.22 or higher\nkubectl create token skooner-sa\n\"><pre class=\"notranslate\"><span class=\"pl-c\"><span class=\"pl-c\">#</span> Create the service account in the current namespace (we assume default)</span>\nkubectl create serviceaccount skooner-sa\n\n<span class=\"pl-c\"><span class=\"pl-c\">#</span> Give that service account root on the cluster</span>\nkubectl create clusterrolebinding skooner-sa --clusterrole=cluster-admin --serviceaccount=default:skooner-sa\n\n<span class=\"pl-c\"><span class=\"pl-c\">#</span> For Kubernetes v1.21 or lower</span>\n<span class=\"pl-c\"><span class=\"pl-c\">#</span> Find the secret that was created to hold the token for the SA</span>\nkubectl get secrets\n\n<span class=\"pl-c\"><span class=\"pl-c\">#</span> Show the contents of the secret to extract the token</span>\nkubectl describe secret skooner-sa-token-xxxxx\n\n<span class=\"pl-c\"><span class=\"pl-c\">#</span> For Kubernetes v1.22 or higher</span>\nkubectl create token skooner-sa\n</pre></div>\n<p dir=\"auto\">Copy the <code class=\"notranslate\">token</code> value from the secret, and enter it into the login screen to access the dashboard.</p>\n<h3 dir=\"auto\">OIDC</h3>\n<p dir=\"auto\">Skooner makes using OpenId Connect for authentication easy. Assuming your cluster is configured to use OIDC, all you need to do is create a secret containing your credentials and apply <a href=\"https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner-oidc.yaml\" rel=\"nofollow\">kubernetes-skooner-oidc.yaml</a>.</p>\n<p dir=\"auto\">To learn more about configuring a cluster for OIDC, check out these great links</p>\n<ul dir=\"auto\">\n<li><a href=\"https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens\" rel=\"nofollow\">Authenticating | Kubernetes</a></li>\n<li><a href=\"https://medium.com/@mrbobbytables/kubernetes-day-2-operations-authn-authz-with-oidc-and-a-little-help-from-keycloak-de4ea1bdbbe\" rel=\"nofollow\">Kubernetes Day 2 Operations: AuthN/AuthZ with OIDC and a Little Help From Keycloak | by Bob Killen | Medium</a></li>\n<li><a href=\"https://medium.com/@int128/kubectl-with-openid-connect-43120b451672\" rel=\"nofollow\">kubectl with OpenID Connect. TL;DR | by Hidetake Iwata | Medium</a></li>\n<li><a href=\"https://www.google.com/search?q=kubernetes+configure+oidc\" rel=\"nofollow\">kubernetes configure oidc - Google Search</a></li>\n</ul>\n<p dir=\"auto\">You can deploy Skooner with OIDC support using something like the following script...</p>\n<p dir=\"auto\">NOTE: never trust a file downloaded from the internet. Make sure to review the contents of <a href=\"https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner-oidc.yaml\" rel=\"nofollow\">kubernetes-skooner-oidc.yaml</a> before running the script below.</p>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"OIDC_URL=&lt;put your endpoint url here... something like https://accounts.google.com&gt;\nOIDC_ID=&lt;put your id here... something like blah-blah-blah.apps.googleusercontent.com&gt;\nOIDC_SECRET=&lt;put your oidc secret here&gt;\n\nkubectl create secret -n kube-system generic skooner \\\n--from-literal=url=$OIDC_URL \\\n--from-literal=id=$OIDC_ID \\\n--from-literal=secret=$OIDC_SECRET\n\nkubectl apply -f https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner-oidc.yaml\n\"><pre class=\"notranslate\">OIDC_URL=<span class=\"pl-k\">&lt;</span>put your endpoint url here... something like https://accounts.google.com<span class=\"pl-k\">&gt;</span>\nOIDC_ID=<span class=\"pl-k\">&lt;</span>put your id here... something like blah-blah-blah.apps.googleusercontent.com<span class=\"pl-k\">&gt;</span>\nOIDC_SECRET=<span class=\"pl-k\">&lt;</span>put your oidc secret here<span class=\"pl-k\">&gt;</span>\n\nkubectl create secret -n kube-system generic skooner \\\n--from-literal=url=<span class=\"pl-smi\">$OIDC_URL</span> \\\n--from-literal=id=<span class=\"pl-smi\">$OIDC_ID</span> \\\n--from-literal=secret=<span class=\"pl-smi\">$OIDC_SECRET</span>\n\nkubectl apply -f https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner-oidc.yaml\n</pre></div>\n<p dir=\"auto\">Additionally, you can provide other OIDC options via these environment variables:</p>\n<ul dir=\"auto\">\n<li><code class=\"notranslate\">OIDC_SCOPES</code>: The default value for this value is <code class=\"notranslate\">openid email</code>, but additional scopes can also be added using something like <code class=\"notranslate\">OIDC_SCOPES=\"openid email groups\"</code></li>\n<li><code class=\"notranslate\">OIDC_METADATA</code>: Skooner uses the excellent <a href=\"https://github.com/panva/node-openid-client\">node-openid-client</a> module. <code class=\"notranslate\">OIDC_METADATA</code> will take a JSON string and pass it to the <code class=\"notranslate\">Client</code> constructor. Docs <a href=\"https://github.com/panva/node-openid-client/blob/master/docs/README.md#client\">here</a>. For example, <code class=\"notranslate\">OIDC_METADATA='{\"token_endpoint_auth_method\":\"client_secret_post\"}</code></li>\n</ul>\n<h3 dir=\"auto\">NodePort</h3>\n<p dir=\"auto\">If you do not have an ingress server setup, you can utilize a NodePort service as configured in <a href=\"https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner-nodeport.yaml\" rel=\"nofollow\">kubernetes-skooner-nodeport.yaml</a>. This is ideal when creating a single node master, or if you want to get up and running as fast as possible.</p>\n<p dir=\"auto\">This will map Skooner port <code class=\"notranslate\">4654</code> to a randomly selected port on the running node. The assigned port can be found using:</p>\n<div class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"$ kubectl get svc --namespace=kube-system\n\nNAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE\nskooner     NodePort    10.107.107.62   &lt;none&gt;        4654:32565/TCP   1m\"><pre class=\"notranslate\"><code class=\"notranslate\">$ kubectl get svc --namespace=kube-system\n\nNAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE\nskooner     NodePort    10.107.107.62   &lt;none&gt;        4654:32565/TCP   1m\n</code></pre></div>\n<h3 dir=\"auto\">Metrics</h3>\n<p dir=\"auto\">Skooner relies heavily on <a href=\"https://github.com/kubernetes-incubator/metrics-server\">metrics-server</a> to display real time cluster metrics. It is strongly recommended to have <code class=\"notranslate\">metrics-server</code> installed to get the best experience from Skooner.</p>\n<ul dir=\"auto\">\n<li><a href=\"https://github.com/kubernetes-incubator/metrics-server\">Installing metrics-server</a></li>\n<li><a href=\"https://medium.com/@waleedkhan91/how-to-configure-metrics-server-on-kubeadm-provisioned-kubernetes-cluster-f755a2ac43a2\" rel=\"nofollow\">Running metrics-server with kubeadm</a></li>\n</ul>\n<p dir=\"auto\">(Back to <a href=\"#table-of-contents\">Table of Contents</a>)</p>\n<h2 dir=\"auto\">Development</h2>\n<p dir=\"auto\">You will need:</p>\n<ul dir=\"auto\">\n<li>A running Kubernetes cluster\n<ul dir=\"auto\">\n<li>Installing and running <a href=\"https://kubernetes.io/docs/tasks/tools/install-minikube/\" rel=\"nofollow\">minikube</a> is an easy way to get this.</li>\n<li>Once minikube is installed, you can run it with the command <code class=\"notranslate\">minikube start --driver=docker</code></li>\n</ul>\n</li>\n<li>Once the cluster is up and running, create some login credentials as described <a href=\"#logging-in\">above</a></li>\n</ul>\n<p dir=\"auto\">(Back to <a href=\"#table-of-contents\">Table of Contents</a>)</p>\n<h2 dir=\"auto\">Skooner Architecture</h2>\n<h3 dir=\"auto\">Server</h3>\n<p dir=\"auto\">To run the server, run <code class=\"notranslate\">npm i</code> from the <code class=\"notranslate\">/server</code> directory to install dependencies and then <code class=\"notranslate\">npm start</code> to run the server.<br>\nThe server is a simple express.js server that is primarily responsible for proxying requests to the Kubernetes api server.</p>\n<p dir=\"auto\">During development, the server will use whatever is configured in <code class=\"notranslate\">~/.kube/config</code> to connect the desired cluster. If you are using minikube, for example, you can run <code class=\"notranslate\">kubectl config set-context minikube</code> to get <code class=\"notranslate\">~/.kube/config</code> set up correctly.</p>\n<h3 dir=\"auto\">Client</h3>\n<p dir=\"auto\">The client is a React application (using TypeScript) with minimal other dependencies.</p>\n<p dir=\"auto\">To run the client, open a new terminal tab and navigate to the <code class=\"notranslate\">/client</code> directory, run <code class=\"notranslate\">npm i</code> and then <code class=\"notranslate\">npm start</code>. This will open up a browser window to your local Skooner dashboard. If everything compiles correctly, it will load the site and then an error message will pop up <code class=\"notranslate\">Unhandled Rejection (Error): Api request error: Forbidden...</code>. The error message has an 'X' in the top righthand corner to close that message. After you close it, you should see the UI where you can enter your token.</p>\n<p dir=\"auto\">(Back to <a href=\"#table-of-contents\">Table of Contents</a>)</p>\n<h2 dir=\"auto\">Troubleshooting</h2>\n<h3 dir=\"auto\">Recommendation for keycloak configuration:</h3>\n<ol dir=\"auto\">\n<li>Set OIDC_URL to keycloak OpenId endpoint configuration page.</li>\n</ol>\n<ul dir=\"auto\">\n<li><code class=\"notranslate\">OIDC_URL=https://{keycloak_domain}/realms/foo/.well-known/openid-configuration</code></li>\n<li>Also set <code class=\"notranslate\">$OIDC_ID</code> locally with <code class=\"notranslate\">OIDC_ID={client_id}</code></li>\n<li>You can get <code class=\"notranslate\">$OIDC_SECRET</code> from keycloak\n<ul dir=\"auto\">\n<li>(You need to set the Client authentication toggle to be on, for older version of keycloaks you should switch access type to confidential )<br>\n<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"imgs/OIDC_keycloak_settings.png\"><img src=\"imgs/OIDC_keycloak_settings.png\" alt=\"img.png\" style=\"max-width: 100%;\"></a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"imgs/OIDC_SECTET_img.png\"><img src=\"imgs/OIDC_SECTET_img.png\" alt=\"img.png\" style=\"max-width: 100%;\"></a></li>\n</ul>\n</li>\n</ul>\n<ol start=\"2\" dir=\"auto\">\n<li>While creating secret, use correct var name and use skooner namespace (by default it's <code class=\"notranslate\">kube-system</code>):</li>\n</ol>\n<div class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"kubectl create secret generic skooner \\\n--from-literal=url=$OIDC_URL \\\n--from-literal=id=$OIDC_ID \\\n--from-literal=secret=$OIDC_SECRET \\\n--namespace=kube-system\"><pre class=\"notranslate\"><code class=\"notranslate\">kubectl create secret generic skooner \\\n--from-literal=url=$OIDC_URL \\\n--from-literal=id=$OIDC_ID \\\n--from-literal=secret=$OIDC_SECRET \\\n--namespace=kube-system\n</code></pre></div>\n<ol start=\"3\" dir=\"auto\">\n<li>\n<p dir=\"auto\">following that, redeploy skooner server with<br>\n<code class=\"notranslate\">kubectl apply -f https://raw.githubusercontent.com/skooner-k8s/skooner/master/kubernetes-skooner-oidc.yaml</code></p>\n</li>\n<li>\n<p dir=\"auto\">Make sure skooner is running by checking <code class=\"notranslate\">kubectl rollout status deploy/skooner --namespace=kube-system</code><br>\nIf not, report error with logging in <code class=\"notranslate\">kubectl describe pod skooner --namespace=kube-system</code></p>\n</li>\n<li>\n<p dir=\"auto\">[Optional] create an ingress for skooner, you can take <code class=\"notranslate\">provision/keycloak/skooner-ingress.yaml</code> as an example</p>\n</li>\n<li>\n<p dir=\"auto\">visit skooner, check if login succeeded</p>\n</li>\n<li>\n<p dir=\"auto\">[Trouble Shooting] If the api call returns 403 with a message containing some error like: <code class=\"notranslate\">User \\\"system:anonymous\\\" cannot list resource \\\"selfsubjectrulesreviews\\\" in API group \\\"authorization.k8s.io\\\" at the cluster scope\"</code></p>\n<ul dir=\"auto\">\n<li>it means you'll need a cluster role bond. You can take <code class=\"notranslate\">provision/keycloak/skooner-oidc-patch.yaml</code> as an example</li>\n<li><a class=\"user-mention notranslate\" data-hovercard-type=\"user\" data-hovercard-url=\"/users/elieassi/hovercard\" data-octo-click=\"hovercard-link-click\" data-octo-dimensions=\"link_type:self\" href=\"https://github.com/elieassi\">@elieassi</a> suggests create a serviceaccount separately, I feel like it's more secure but I hadn't test it out. See <a href=\"https://github.com/skooner-k8s/skooner/issues/361\" data-hovercard-type=\"issue\" data-hovercard-url=\"/skooner-k8s/skooner/issues/361/hovercard\">this issue</a> for more details</li>\n</ul>\n</li>\n<li>\n<p dir=\"auto\">If failed, please report both client and server error.<br>\nClient error: check browser console and send a screenshot<br>\nServer error: check logs by <code class=\"notranslate\">kubectl logs deploy/skooner --namespace=kube-system</code><br>\nNote that <code class=\"notranslate\">RequestError: connect ECONNREFUSED</code> may indicate a configuration issue rather than Skooner's issue.</p>\n</li>\n</ol>\n<h2 dir=\"auto\">License</h2>\n<p dir=\"auto\"><a href=\"https://raw.githubusercontent.com/skooner-k8s/skooner/master/LICENSE\" rel=\"nofollow\">Apache License 2.0</a></p>\n<p dir=\"auto\"><a href=\"https://app.fossa.com/projects/git%2Bgithub.com%2Findeedeng%2Fk8dash?ref=badge_large\" rel=\"nofollow\"><img src=\"https://camo.githubusercontent.com/8fa45ab6e4794906500656e2b4e50c0969ad688e38b12d687ce5e2857b3d07a1/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f6769742532426769746875622e636f6d253246696e64656564656e672532466b38646173682e7376673f747970653d6c61726765\" alt=\"FOSSA Status\" data-canonical-src=\"https://app.fossa.com/api/projects/git%2Bgithub.com%2Findeedeng%2Fk8dash.svg?type=large\" style=\"max-width: 100%;\"></a></p>\n<p dir=\"auto\">(Back to <a href=\"#table-of-contents\">Table of Contents</a>)</p>","updatedAt":"2025-05-22T01:48:33Z","upvoteCount":null,"author":{"login":"eryajf","avatarUrl":"https://avatars.githubusercontent.com/u/33259379?u=e4a4090a38ac2473aaed4ef9945233636776c6c3&v=4","url":"https://github.com/eryajf"},"category":null,"labels":{"edges":[{"node":{"name":"更多","color":"25B472"}},{"node":{"name":"K8S-Tools","color":"2d411a"}},{"node":{"name":"skooner-k8s","color":"57c2ad"}}]},"comments":{"edges":[]}}},"pageContext":{"number":520,"previous":{"title":"lotabout/skim: 一个类似 grep 命令的通用的模糊查找器，可以节省您的时间。","number":519},"next":{"title":"apache/skywalking:  一个开源的 APM 系统，为云原生架构中的分布式系统提供监控、跟踪和诊断功能。","number":521}}},
    "staticQueryHashes": ["151096407","2861350382"]}