{"id":1111,"date":"2022-01-21T17:39:06","date_gmt":"2022-01-21T09:39:06","guid":{"rendered":"https:\/\/www.yinyubo.com\/?p=1111"},"modified":"2022-05-16T18:00:56","modified_gmt":"2022-05-16T10:00:56","slug":"k8s","status":"publish","type":"post","link":"https:\/\/www.yinyubo.com\/?p=1111","title":{"rendered":"\u4e00\u7bc7\u6587\u7ae0\u5e26\u4f60\u5165\u95e8K8S\u4e8c\u6b21\u5f00\u53d1"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">\u80cc\u666f<\/h2>\n\n\n\n<p>\u6211\u4eec\u7ecf\u5e38\u4f1a\u5728\u7f51\u4e0a\u770b\u5230K8S\u548c\u5468\u8fb9\u5de5\u5177\u7684\u6559\u7a0b\uff0c\u4f8b\u5982HELM\u7684\u4f7f\u7528\uff0cdroneCI\u7684\u4f7f\u7528\uff0c\u4f46\u662f\u5f88\u5c11\u6709\u6587\u7ae0\u5199\uff0c\u5982\u4f55\u57fa\u4e8eK8S\u8fdb\u884c\u4e8c\u6b21\u5f00\u53d1\uff0c\u672c\u7bc7\u6587\u7ae0\u5c06\u4f7f\u7528python\u548cvue\u8fdb\u884cK8S\u7684\u4e8c\u6b21\u5f00\u53d1\uff0c\u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u67e5\u8be2k8s\u7684pod\u548cnode\u4fe1\u606f\u7684\u9875\u9762<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u6548\u679c\u56fe<\/h2>\n\n\n\n<p>\u901a\u8fc7\u524d\u7aef\u9875\u9762\uff0c\u8c03\u7528\u540e\u7aefpython\u63a5\u53e3\uff0c\u67e5\u8be2k8s\u5f53\u524d\u7684\u8282\u70b9\u72b6\u6001\u548c\u5e94\u7528\u72b6\u6001<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"985\" height=\"644\" src=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image.png\" alt=\"\" class=\"wp-image-1113\" srcset=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image.png 985w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-300x196.png 300w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-768x502.png 768w\" sizes=\"auto, (max-width: 985px) 100vw, 985px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u6d89\u53ca\u5230\u7684\u77e5\u8bc6\u70b9<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>\u77e5\u8bc6\u70b9<\/td><td>\u8bf4\u660e<\/td><\/tr><tr><td>python-sanic\u5e93<\/td><td>\u4e3a\u524d\u53f0\u63d0\u4f9bAPI\u63a5\u53e3<\/td><\/tr><tr><td>python-kubernetes\u5e93<\/td><td>\u8bbf\u95eek8s\uff0c\u83b7\u53d6pod\u548cnode\u8d44\u6e90\u4fe1\u606f<\/td><\/tr><tr><td>nodejs-vue<\/td><td>\u524d\u7aef\u6846\u67b6<\/td><\/tr><tr><td>nodejs-element-UI<\/td><td>\u63d0\u4f9bUI\u7ec4\u4ef6\uff0c\u7528\u4e86\u56fe\u6807\u548c\u8868\u683c\u7ec4\u4ef6<\/td><\/tr><tr><td>k8s-helm<\/td><td>\u7a0b\u5e8f\u6700\u540e\u662f\u8981\u8fd0\u884c\u5728K8S\u91cc\uff0c\u6240\u4ee5\u8981\u7f16\u5199helm\u5305\uff0c\u5305\u62ecrbac,svc,deployment\u6587\u4ef6<\/td><\/tr><tr><td>docker<\/td><td>\u524d\u540e\u7aef\u7684docker\u955c\u50cf\u5236\u4f5c<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u7528\u6237\u6545\u4e8b<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-5-1024x384.png\" alt=\"\" class=\"wp-image-1123\" width=\"1024\" height=\"384\" srcset=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-5-1024x384.png 1024w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-5-300x113.png 300w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-5-768x288.png 768w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-5.png 1130w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u540e\u7aefpython\u4ee3\u7801\u89e3\u8bf4<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"314\" height=\"203\" src=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-1.png\" alt=\"\" class=\"wp-image-1114\" srcset=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-1.png 314w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-1-300x194.png 300w\" sizes=\"auto, (max-width: 314px) 100vw, 314px\" \/><\/figure>\n\n\n\n<p><strong>main.py \u4e3b\u51fd\u6570\u5165\u53e3<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#main.py\nfrom kubernetes import client, config\nfrom sanic import Sanic\nfrom sanic.response import json\n\nfrom cors import add_cors_headers\nfrom options import setup_options\n\n# sanic\u7a0b\u5e8f\u5fc5\u987b\u6709\u4e2a\u540d\u5b57\napp = Sanic(\"backend\")\n# \u5728\u672c\u5730\u8c03\u8bd5\uff0c\u628aconfig\u6587\u4ef6\u62f7\u8d1d\u5230\u672c\u673a\u7684~\/.kube\/config\u7136\u540e\u4f7f\u7528load_kube_config\uff0c\u5728K8S\u96c6\u7fa4\u91cc\u4f7f\u7528load_incluster_config\n# config.load_kube_config()\nconfig.load_incluster_config()\n\n\ndef check_node_status(receiver):\n    '''\n    \u68c0\u67e5\u8282\u70b9\u7684\u72b6\u6001\u662f\u5426\u6b63\u786e\uff0c\u6b63\u786e\u7684\u8bbe\u4e3a1\uff0c\u4e0d\u6b63\u786e\u7684\u8bbe\u4e3a0\n    '''\n    # \u671f\u671b\u7ed3\u679c\n    expect = {\"NetworkUnavailable\": \"False\",\n              \"MemoryPressure\": \"False\",\n              \"DiskPressure\": \"False\",\n              \"PIDPressure\": \"False\",\n              \"Ready\": \"True\"\n              }\n    result_dict = {}\n    for (key, value) in receiver.items():\n        # \u8fd9\u4e2a\u903b\u8f91\u662f\u5224\u65adk8s\u4f20\u8fc7\u6765\u7684\u503c\u4e0eexpect\u7684\u503c\u662f\u5426\u76f8\u540c\n        if expect&#91;key] == value:\n            result_dict&#91;key] = 1\n        else:\n            result_dict&#91;key] = 0\n    return result_dict\n\n\n@app.route(\"\/api\/node\")\nasync def node(request):\n    result = &#91;]\n    v1 = client.CoreV1Api()\n    node_rest = v1.list_node_with_http_info()\n    for i in node_rest&#91;0].items:\n        computer_ip = i.status.addresses&#91;0].address\n        computer_name = i.status.addresses&#91;1].address\n        # \u5148\u83b7\u5f97\u8282\u70b9\u7684IP\u548c\u540d\u5b57\n        info = {\"computer_ip\": computer_ip, \"computer_name\": computer_name}\n        status_json = {}\n        # \u8282\u70b9\u6709\u591a\u4e2a\u72b6\u6001\uff0c\u628a\u6240\u6709\u72b6\u6001\u67e5\u51fa\u6765\uff0c\u5b58\u5165json\u91cc\n        # \u8fd9\u91cc\u6709\u4e00\u4e2aflannel\u63d2\u4ef6\u7684\u5751\uff0c\u53ca\u65f6\u8282\u70b9\u5173\u673a\u4e86\uff0cNetworkUnavailable\u67e5\u51fa\u6765\u8fd8\u662fFalse\n        for node_condition in i.status.conditions:\n            status_json&#91;node_condition.type] = node_condition.status\n        check_dict = check_node_status(status_json)\n        # \u628a\u8282\u70b9\u7684\u72b6\u6001\u52a0\u5165\u8282\u70b9\u4fe1\u606fjson\u91cc\n        info.update(check_dict)\n        # \u628a\u6bcf\u4e00\u4e2a\u8282\u70b9\u7684\u67e5\u8be2\u7ed3\u679c\u52a0\u5165list\u91cc\uff0c\u8fd4\u56de\u7ed9\u524d\u7aef\n        result.append(info)\n    return json(result)\n\n\n@app.route(\"\/api\/pod\")\nasync def pod(request):\n    '''\n    \u63a5\u53e3\u540d\u662fpod\uff0c\u5176\u5b9e\u662f\u68c0\u67e5\u6240\u6709\u7684deployment\uff0cstatefulset\uff0cdaemonset\u7684\u526f\u672c\u72b6\u6001\n    \u901a\u8fc7\u8fd9\u4e9b\u72b6\u6001\u5224\u65ad\u5f53\u524d\u7684\u7a0b\u5e8f\u662f\u5426\u6b63\u5e38\u5de5\u4f5c\n    '''\n    pod_list = &#91;]\n    apis_api = client.AppsV1Api()\n    # \u68c0\u67e5deployment\u4fe1\u606f\n    resp = apis_api.list_deployment_for_all_namespaces()\n    for i in resp.items:\n        pod_name = i.metadata.name\n        pod_namespace = i.metadata.namespace\n        pod_unavailable_replicas = i.status.unavailable_replicas\n        # \u4e0d\u53ef\u7528\u526f\u672c\u72b6\u6001\u4e3aNone\u8868\u793a\u6ca1\u6709\u4e0d\u53ef\u7528\u7684\u526f\u672c\uff0c\u7a0b\u5e8f\u6b63\u5e38\n        if pod_unavailable_replicas == None:\n            pod_status = 1\n        else:\n            pod_status = 0\n        pod_json = {\"pod_namespace\": pod_namespace, \"pod_name\": pod_name, \"pod_status\": pod_status}\n        pod_list.append(pod_json)\n    # \u68c0\u67e5stateful_set\u4fe1\u606f\n    resp_stateful = apis_api.list_stateful_set_for_all_namespaces()\n    for i in resp_stateful.items:\n        pod_name = i.metadata.name\n        pod_namespace = i.metadata.namespace\n        # \u6b63\u5e38\u5de5\u4f5c\u7684\u526f\u672c\u6570\u91cf\uff0c\u7b49\u4e8e\u671f\u671b\u7684\u526f\u672c\u6570\u91cf\u65f6\uff0c\u8868\u660e\u7a0b\u5e8f\u662f\u53ef\u7528\u7684\n        if i.status.ready_replicas == i.status.replicas:\n            pod_status = 1\n        else:\n            pod_status = 0\n        pod_json = {\"pod_namespace\": pod_namespace, \"pod_name\": pod_name, \"pod_status\": pod_status}\n        pod_list.append(pod_json)\n    # \u68c0\u67e5daemonset\u4fe1\u606f\n    resp_daemonset = apis_api.list_daemon_set_for_all_namespaces()\n    for i in resp_daemonset.items:\n        pod_name = i.metadata.name\n        pod_namespace = i.metadata.namespace\n        # \u4e0d\u53ef\u7528\u526f\u672c\u72b6\u6001\u4e3aNone\u8868\u793a\u6ca1\u6709\u4e0d\u53ef\u7528\u7684\u526f\u672c\uff0c\u7a0b\u5e8f\u6b63\u5e38\n        if i.status.number_unavailable == None:\n            pod_status = 1\n        else:\n            pod_status = 0\n        pod_json = {\"pod_namespace\": pod_namespace, \"pod_name\": pod_name, \"pod_status\": pod_status}\n        pod_list.append(pod_json)\n    return json(pod_list)\n\n\n# Add OPTIONS handlers to any route that is missing it\napp.register_listener(setup_options, \"before_server_start\")\n\n# Fill in CORS headers\napp.register_middleware(add_cors_headers, \"response\")\nif __name__ == \"__main__\":\n    app.run(host=\"0.0.0.0\", port=8000)\n<\/code><\/pre>\n\n\n\n<p><strong>cors.py \u89e3\u51b3\u8de8\u57df\u95ee\u9898\uff0c\u4e3b\u8981\u662f\u672c\u5730\u8c03\u8bd5\u65b9\u4fbf\uff0c\u653e\u5230\u6211\u7684helm\u5305\u91cc\u90e8\u7f72\u5230K8S\u4e0a\u65f6\uff0c\u662f\u4e0d\u9700\u8981\u7684\uff0c\u56e0\u4e3a\u6211\u4f1a\u7528nginx\u628a\u4ed6\u53cd\u5411\u4ee3\u7406\u8fc7\u53bb<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#cors.py\nfrom typing import Iterable\n\n\ndef _add_cors_headers(response, methods: Iterable&#91;str]) -&gt; None:\n    '''\n    \u4e3a\u4e86\u5728\u6d4b\u8bd5\u7684\u65f6\u5019\u5077\u61d2\uff0c\u6211\u628aAccess-Control-Allow-Origin\u8bbe\u7f6e\u6210\u4e86*\n    \u5982\u679c\u662f\u505a\u6210\u955c\u50cf\u548c\u6211\u7684helm\u5305\u4e00\u8d77\u7528\uff0c\u662f\u4e0d\u9700\u8981\u8fd9\u6837\u7684\uff0c\u56e0\u4e3a\u6211\u4f1a\u7528nginx\u628a\u540e\u7aef\u548c\u524d\u7aef\u8bbe\u7f6e\u6210\u540c\u6e90\n    '''\n    allow_methods = list(set(methods))\n    if \"OPTIONS\" not in allow_methods:\n        allow_methods.append(\"OPTIONS\")\n    headers = {\n        \"Access-Control-Allow-Methods\": \",\".join(allow_methods),\n        \"Access-Control-Allow-Origin\": \"*\",\n        \"Access-Control-Allow-Credentials\": \"true\",\n        \"Access-Control-Allow-Headers\": (\n            \"origin, content-type, accept, \"\n            \"authorization, x-xsrf-token, x-request-id\"\n        ),\n    }\n    response.headers.extend(headers)\n\n\ndef add_cors_headers(request, response):\n    if request.method != \"OPTIONS\":\n        methods = &#91;method for method in request.route.methods]\n        _add_cors_headers(response, methods)\n<\/code><\/pre>\n\n\n\n<p><strong>options.py \u642d\u914d\u4e0a\u9762\u7684cors.py\u4f7f\u7528<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># options.py\nfrom collections import defaultdict\nfrom typing import Dict, FrozenSet\n\nfrom sanic import Sanic, response\nfrom sanic.router import Route\n\nfrom cors import _add_cors_headers\n\n\ndef _compile_routes_needing_options(\n        routes: Dict&#91;str, Route]\n) -&gt; Dict&#91;str, FrozenSet]:\n    needs_options = defaultdict(list)\n    # This is 21.12 and later. You will need to change this for older versions.\n    for route in routes.values():\n        if \"OPTIONS\" not in route.methods:\n            needs_options&#91;route.uri].extend(route.methods)\n\n    return {\n        uri: frozenset(methods) for uri, methods in dict(needs_options).items()\n    }\n\n\ndef _options_wrapper(handler, methods):\n    def wrapped_handler(request, *args, **kwargs):\n        nonlocal methods\n        return handler(request, methods)\n\n    return wrapped_handler\n\n\nasync def options_handler(request, methods) -&gt; response.HTTPResponse:\n    resp = response.empty()\n    _add_cors_headers(resp, methods)\n    return resp\n\n\ndef setup_options(app: Sanic, _):\n    app.router.reset()\n    needs_options = _compile_routes_needing_options(app.router.routes_all)\n    for uri, methods in needs_options.items():\n        app.add_route(\n            _options_wrapper(options_handler, methods),\n            uri,\n            methods=&#91;\"OPTIONS\"],\n        )\n    app.router.finalize()\n<\/code><\/pre>\n\n\n\n<p><strong>requirements.txt \u653e\u7f6epython\u9700\u8981\u7528\u5230\u7684sdk<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aiofiles==0.8.0\ncachetools==4.2.4\ncertifi==2021.10.8\ncharset-normalizer==2.0.10\ngoogle-auth==2.3.3\nhttptools==0.3.0\nidna==3.3\nJinja2==3.0.3\nkubernetes==21.7.0\nMarkupSafe==2.0.1\nmultidict==5.2.0\noauthlib==3.1.1\npyasn1==0.4.8\npyasn1-modules==0.2.8\npython-dateutil==2.8.2\nPyYAML==6.0\nrequests==2.27.1\nrequests-oauthlib==1.3.0\nrsa==4.8\nsanic==21.12.1\nsanic-ext==21.12.3\nsanic-routing==0.7.2\nsix==1.16.0\nurllib3==1.26.8\nwebsocket-client==1.2.3\nwebsockets==10.1\n<\/code><\/pre>\n\n\n\n<p><strong>Dockerfile \u6253\u5305\u540e\u7aef\u4ee3\u7801\u6210\u955c\u50cf\u4f7f\u7528  docker build -t k8s-backend .<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM python:3.9\nADD . .\nRUN pip install -r \/requirements.txt -i https:\/\/pypi.tuna.tsinghua.edu.cn\/simple\nWORKDIR .\nCMD &#91;\"python3\",\"main.py\"]<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u524d\u7aef\u4ee3\u7801\u89e3\u8bf4<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"414\" height=\"186\" src=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-2.png\" alt=\"\" class=\"wp-image-1116\" srcset=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-2.png 414w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-2-300x135.png 300w\" sizes=\"auto, (max-width: 414px) 100vw, 414px\" \/><figcaption>\u4e3b\u8981\u5c31\u662fApp.vue\u548cmain.ts\u4e24\u4e2a\u6587\u4ef6<\/figcaption><\/figure>\n\n\n\n<p><strong>\u8fd9\u91cc\u7701\u7565nodejs\u548cvue\u7684\u5b89\u88c5\u8fc7\u7a0b\uff0c\u4f7f\u7528\u4e0b\u9762\u7684\u547d\u4ee4\u521b\u5efa\u4e00\u4e2avue3\u7684\u9879\u76ee<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \u4e0b\u8f7dvue\u7684\u8fc7\u7a0b\u7701\u7565,\u521b\u5efa\u4e00\u4e2avue\u9879\u76ee\uff0c\u521b\u5efa\u7684\u65f6\u5019\uff0c\u9009\u62e9typescript\u7248\u672c\nvue create k8s-frontend\n# \u5b89\u88c5element-ui\u7684vue3\u7248\u672c\nnpm install element-plus --save\n# npm\u5b89\u88c5axios\uff0c\u7528\u4e8e\u5411\u540e\u53f0\u53d1\u8d77\u8bf7\u6c42\nnpm i axios -S\n<\/code><\/pre>\n\n\n\n<p><strong>main.ts \u4e3b\u5165\u53e3<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Component, createApp } from 'vue'\nimport ElementPlus from 'element-plus'\nimport 'element-plus\/dist\/index.css'\nimport App from '.\/App.vue'\nconst app = createApp(App)\n\napp.use(ElementPlus)\n\napp.mount('#app')\n<\/code><\/pre>\n\n\n\n<p><strong>App.vue \u505ademo\u56fe\u7701\u4e8b\uff0c\u6211\u5c31\u7528\u4e86\u8fd9\u4e00\u4e2avue\u6587\u4ef6\u653e\u4e86\u6240\u6709\u529f\u80fd<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;template&gt;\n\n  &lt;h2&gt;\u670d\u52a1\u5668\u4fe1\u606f&lt;\/h2&gt;\n  &lt;el-table \n    :data=\"tableData\" style=\"width: 100%\"&gt;\n    &lt;el-table-column prop=\"computer_ip\" label=\"IP\u5730\u5740\" width=\"180\" \/&gt;\n    &lt;el-table-column prop=\"computer_name\" label=\"\u670d\u52a1\u5668\u540d\u5b57\" width=\"180\" \/&gt;\n    &lt;el-icon&gt;&lt;check \/&gt;&lt;\/el-icon&gt;\n    &lt;el-table-column label=\"\u7f51\u7edc\u63d2\u4ef6\" width=\"100\"&gt;\n      &lt;template #default=\"scope\"&gt;\n        &lt;el-icon :size=\"20\"&gt;\n          &lt;check class=\"check\" v-if=\"scope.row.NetworkUnavailable ==1\" \/&gt;\n          &lt;close class=\"close\" v-else \/&gt;\n        &lt;\/el-icon&gt;\n      &lt;\/template&gt;\n    &lt;\/el-table-column&gt;\n    &lt;el-table-column label=\"\u5185\u5b58\u538b\u529b\" width=\"100\"&gt;\n      &lt;template #default=\"scope\"&gt;\n        &lt;el-icon :size=\"20\"&gt;\n          &lt;check class=\"check\" v-if=\"scope.row.MemoryPressure ==1\" \/&gt;\n          &lt;close class=\"close\" v-else \/&gt;\n        &lt;\/el-icon&gt;\n      &lt;\/template&gt;\n    &lt;\/el-table-column&gt;\n    &lt;el-table-column label=\"\u786c\u76d8\u538b\u529b\" width=\"100\"&gt;\n      &lt;template #default=\"scope\"&gt;\n        &lt;el-icon :size=\"20\"&gt;\n          &lt;check class=\"check\" v-if=\"scope.row.DiskPressure ==1\" \/&gt;\n          &lt;close class=\"close\" v-else \/&gt;\n        &lt;\/el-icon&gt;\n      &lt;\/template&gt;\n    &lt;\/el-table-column&gt;\n    &lt;el-table-column label=\"\u8fdb\u7a0b\u538b\u529b\" width=\"100\"&gt;\n      &lt;template #default=\"scope\"&gt;\n        &lt;el-icon :size=\"20\"&gt;\n          &lt;check class=\"check\" v-if=\"scope.row.PIDPressure ==1\" \/&gt;\n          &lt;close class=\"close\" v-else \/&gt;\n        &lt;\/el-icon&gt;\n      &lt;\/template&gt;\n    &lt;\/el-table-column&gt;\n    &lt;el-table-column label=\"K3S\u72b6\u6001\" width=\"100\"&gt;\n      &lt;template #default=\"scope\"&gt;\n        &lt;el-icon :size=\"20\"&gt;\n          &lt;check class=\"check\" v-if=\"scope.row.Ready ==1\" \/&gt;\n          &lt;close class=\"close\" v-else \/&gt;\n        &lt;\/el-icon&gt;\n      &lt;\/template&gt;\n    &lt;\/el-table-column&gt;\n  &lt;\/el-table&gt;\n  &lt;el-divider&gt;&lt;\/el-divider&gt;\n  &lt;h2&gt;\u5e94\u7528\u7a0b\u5e8f\u4fe1\u606f&lt;\/h2&gt;\n  &lt;el-table\n    :data=\"podData\"\n    style=\"width: 100%\"\n    :default-sort=\"{ prop: 'pod_status', order: 'ascending' }\"\n  &gt;\n    &lt;el-table-column prop=\"pod_namespace\" sortable  label=\"\u547d\u540d\u7a7a\u95f4\" width=\"180\" \/&gt;\n    &lt;el-table-column prop=\"pod_name\" sortable label=\"\u5e94\u7528\u540d\u5b57\" width=\"180\" \/&gt;\n    &lt;el-icon&gt;&lt;check \/&gt;&lt;\/el-icon&gt;\n    &lt;el-table-column prop=\"pod_status\" label=\"\u662f\u5426\u6b63\u5e38\" sortable width=\"100\"&gt;\n      &lt;template #default=\"scope\"&gt;\n        &lt;el-icon :size=\"20\"&gt;\n          &lt;check class=\"check\" v-if=\"scope.row.pod_status ==1\" \/&gt;\n          &lt;close class=\"close\" v-else \/&gt;\n        &lt;\/el-icon&gt;\n      &lt;\/template&gt;\n    &lt;\/el-table-column&gt;\n  &lt;\/el-table&gt;\n  &lt;el-divider&gt;&lt;\/el-divider&gt;\n&lt;\/template&gt;\n\n&lt;script lang=\"ts\" &gt;\nimport { Options, Vue } from 'vue-class-component';\nimport { Check, Close } from '@element-plus\/icons-vue';\nimport axios from 'axios'\n\n@Options({\n    \/\/ \u8fd9\u91cc\u53ef\u4ee5\u914d\u7f6eVue\u7ec4\u4ef6\u652f\u6301\u7684\u5404\u79cd\u9009\u9879\n    components: {\n        Check,\n        Close\n    },\n    data() {\n        return {\n          podData: &#91;],\n          tableData: &#91;],\n        }\n    },\n    mounted() {\n      this.pod();\n      this.show();\n    },\n    methods: {\n        say(){\n          console.log(\"say\");\n        },\n        pod(){\n          const path = \"http:\/\/127.0.0.1:8000\/api\/pod\";\n          \/\/\u672c\u5730\u8c03\u8bd5\u4f7f\u7528\uff0c\u5728\u670d\u52a1\u5668\u4e0a\u8fd8\u662f\u7528\u76f8\u5bf9\u8def\u5f84\n          \/\/ const path = \"http:\/\/127.0.0.1:8000\/node\";\n          \/\/ \u52a1\u5fc5\u4f7f\u7528\u7bad\u5934\u51fd\u6570\u7684\u65b9\u6cd5\uff0c\u8fd9\u6837this.id\u80fd\u76f4\u63a5\u5bf9\u4e0a\uff0c\u4e0d\u7136\u4f1a\u62a5\u9519\u63d0\u793aid\u6ca1\u627e\u5230\n          axios.get(path).then((response) =&gt; {\n            this.podData = response.data;\n          });\n        },\n        show() {\n        const path = \"http:\/\/127.0.0.1:8000\/api\/node\";\n        \/\/\u672c\u5730\u8c03\u8bd5\u4f7f\u7528\uff0c\u5728\u670d\u52a1\u5668\u4e0a\u8fd8\u662f\u7528\u76f8\u5bf9\u8def\u5f84\n        \/\/ const path = \"http:\/\/127.0.0.1:8000\/node\";\n        \/\/ \u52a1\u5fc5\u4f7f\u7528\u7bad\u5934\u51fd\u6570\u7684\u65b9\u6cd5\uff0c\u8fd9\u6837this.id\u80fd\u76f4\u63a5\u5bf9\u4e0a\uff0c\u4e0d\u7136\u4f1a\u62a5\u9519\u63d0\u793aid\u6ca1\u627e\u5230\n        axios.get(path).then((response) =&gt; {\n          this.tableData = response.data;\n        });\n      },\n    }\n})\nexport default class App extends Vue {\n}\n&lt;\/script&gt;\n\n&lt;style&gt;\n#app {\n  font-family: Avenir, Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: left;\n  color: #2c3e50;\n  margin-top: 60px;\n}\n&lt;\/style&gt;\n<\/code><\/pre>\n\n\n\n<p><strong>Dockerfile \u7528\u4e8e\u5236\u4f5c\u524d\u7aef\u955c\u50cf docker build -t k8s-frontend .<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM  node:14-alpine3.12 AS build\n\nLABEL maintainer=\"sunj@sfere-elec.com\"\n\nADD . \/build\/\n\nRUN set -eux \\\n    &amp;&amp; yarn config set registry https:\/\/mirrors.huaweicloud.com\/repository\/npm\/ \\\n    &amp;&amp; yarn config set sass_binary_site https:\/\/mirrors.huaweicloud.com\/node-sass \\\n    &amp;&amp; yarn config set python_mirror https:\/\/mirrors.huaweicloud.com\/python \\\n    &amp;&amp; yarn global add yrm \\\n    &amp;&amp; yrm add sfere http:\/\/repo.sfere.local:8081\/repository\/npm-group\/ \\\n    &amp;&amp; yrm use sfere \\\n    &amp;&amp; cd \/build \\\n    &amp;&amp; yarn install \\\n    &amp;&amp; yarn build\n\nFROM nginx:1.21.5-alpine\nLABEL zhenwei.li \"zhenwei.li@sfere-elec.com\"\nCOPY --from=build \/build\/dist\/ \/usr\/share\/nginx\/html\n# \u66b4\u9732\u7aef\u53e3\u6620\u5c04\nEXPOSE 80<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">HELM\u5305\u89e3\u8bf4<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"262\" height=\"318\" src=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-3.png\" alt=\"\" class=\"wp-image-1118\" srcset=\"https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-3.png 262w, https:\/\/www.yinyubo.com\/wp-content\/uploads\/2022\/01\/image-3-247x300.png 247w\" sizes=\"auto, (max-width: 262px) 100vw, 262px\" \/><\/figure>\n\n\n\n<p><strong>deployment.yaml \u628a\u4e24\u4e2adocker\u955c\u50cf\u653e\u5728\u540c\u4e00\u4e2adeployment\u91cc<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1\nkind: Deployment\nmetadata:\n  labels:\n    app: {{ .Release.Name }}\n  name: {{ .Release.Name }}\nspec:\n  replicas: 1\n  revisionHistoryLimit: 5\n  selector:\n    matchLabels:\n      app: {{ .Release.Name }}\n  strategy:\n    type: Recreate\n  template:\n    metadata:\n      labels:\n        app: {{ .Release.Name }}\n    spec:\n      containers:\n        - image: k8s-check-backend\n          imagePullPolicy: Always\n          name: server-check-backend\n          resources: {}\n        - image: k8s-check-frontend\n          imagePullPolicy: Always\n          name: server-check-frontend\n          resources: {}\n          volumeMounts:\n          - name: nginx-conf\n            mountPath: \/etc\/nginx\/conf.d\/default.conf\n            subPath: default.conf\n      restartPolicy: Always\n      volumes:\n        - name: nginx-conf\n          configMap:\n            name: {{ .Release.Name }}\n            items:\n            - key: default.conf\n              path: default.conf\n      serviceAccountName: {{ .Release.Name }}<\/code><\/pre>\n\n\n\n<p><strong>service.yaml \u628a\u524d\u7aef\u901a\u8fc7nodeport\u65b9\u5f0f\u66b4\u9732\u51fa\u53bb\uff0c\u65b9\u4fbf\u6d4b\u8bd5<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    app: {{ .Release.Name }}\n  name: {{ .Release.Name }}\nspec:\n  type: NodePort\n  ports:\n    - name: web\n      port: 80\n      targetPort: 80\n      nodePort: 32666\n  selector:\n    app: {{ .Release.Name }}<\/code><\/pre>\n\n\n\n<p><strong>configmap.yaml nginx\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u53cd\u5411\u4ee3\u7406\u540e\u7aef<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}\ndata:\n  default.conf: |\n    # \u5f53\u524d\u9879\u76eenginx\u914d\u7f6e\u6587\u4ef6,lzw\n    server {\n        listen       80;\n        server_name  _A;\n        gzip on;\n        error_page   500 502 503 504  \/50x.html;\n        location = \/50x.html {\n            root   \/usr\/share\/nginx\/html;\n        }\n\n        location \/ {\n            root \/usr\/share\/nginx\/html;\n            index index.html index.htm;\n\n            if (!-e $request_filename){\n                    rewrite ^\/.* \/index.html last;\n            }\n        }\n        location \/api {\n            proxy_pass          http:\/\/localhost:8000;\n            proxy_http_version 1.1;\n            proxy_set_header    X-Real-IP           $remote_addr;\n            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;\n        }\n\n        error_page   500 502 503 504  \/50x.html;\n    }\n<\/code><\/pre>\n\n\n\n<p><strong>rbac.yaml  \u6211\u4eec\u7684\u7a0b\u5e8f\u662f\u9700\u8981\u8bbf\u95eek8s\u8d44\u6e90\u7684\uff0c\u5982\u679c\u6ca1\u6709\u914d\u7f6erbac,\u8c03\u7528K8S\u7684API\u4f1a\u62a5403\u9519\u8bef<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: rbac.authorization.k8s.io\/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io\/name: {{ .Release.Name }}\n  name: {{ .Release.Name }}\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: {{ .Release.Name }}\nsubjects:\n- kind: ServiceAccount\n  name: {{ .Release.Name }}\n  namespace: {{ .Release.Namespace }}\n---\napiVersion: rbac.authorization.k8s.io\/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    app.kubernetes.io\/name: {{ .Release.Name }}\n  name: {{ .Release.Name }}\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - configmaps\n  - secrets\n  - nodes\n  - pods\n  - services\n  - resourcequotas\n  - replicationcontrollers\n  - limitranges\n  - persistentvolumeclaims\n  - persistentvolumes\n  - namespaces\n  - endpoints\n  verbs:\n  - list\n  - watch\n- apiGroups:\n  - extensions\n  resources:\n  - daemonsets\n  - deployments\n  - replicasets\n  - ingresses\n  verbs:\n  - list\n  - watch\n- apiGroups:\n  - apps\n  resources:\n  - statefulsets\n  - daemonsets\n  - deployments\n  - replicasets\n  verbs:\n  - list\n  - watch\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    app.kubernetes.io\/name: {{ .Release.Name }}\n  name: {{ .Release.Name }}\n  namespace: {{ .Release.Namespace }}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u7a0b\u5e8f\u5b89\u88c5<\/h2>\n\n\n\n<p>helm install k8s-check helm\/k8s-server-check<\/p>\n\n\n\n<p>\u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u901a\u8fc7http:\/\/masterip:32666\u8bbf\u95ee\u5373\u53ef<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u80cc\u666f \u6211\u4eec\u7ecf\u5e38\u4f1a\u5728\u7f51\u4e0a\u770b\u5230K8S\u548c\u5468\u8fb9\u5de5\u5177\u7684\u6559\u7a0b\uff0c\u4f8b\u5982HELM\u7684\u4f7f\u7528\uff0cdroneCI\u7684\u4f7f\u7528\uff0c\u4f46\u662f\u5f88\u5c11\u6709\u6587\u7ae0\u5199\uff0c [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,7],"tags":[],"class_list":["post-1111","post","type-post","status-publish","format-standard","hentry","category-k8s","category-7"],"_links":{"self":[{"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=\/wp\/v2\/posts\/1111","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1111"}],"version-history":[{"count":11,"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=\/wp\/v2\/posts\/1111\/revisions"}],"predecessor-version":[{"id":1129,"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=\/wp\/v2\/posts\/1111\/revisions\/1129"}],"wp:attachment":[{"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1111"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1111"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.yinyubo.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1111"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}