【GO】k8s 管理系统项目22[前端部分–工作负载-Deployment]

news2024/10/2 16:15:57

k8s 管理系统项目[前端部分–工作负载-Deployment]

1. Deployment页面设计

src/layout/Layout.vue

  1. 功能
    • 列表
    • 详情
    • 新增
    • 更新
    • 删除
    • 重启
    • 副本数
  2. Main的布局

请添加图片描述

2. 连接配置

src/views/common/Config.js

export default {
    //后端接口路径
    loginAuth: 'http://localhost:9091/api/login',
    k8sWorkflowCreate: 'http://localhost:9091/api/k8s/workflow/create',
    k8sWorkflowDetail: 'http://localhost:9091/api/k8s/workflow/detail',
    k8sWorkflowList: 'http://localhost:9091/api/k8s/workflows',
    k8sWorkflowDel: 'http://localhost:9091/api/k8s/workflow/del',
    k8sDeploymentList: 'http://localhost:9091/api/k8s/deployments',
    k8sDeploymentDetail: 'http://localhost:9091/api/k8s/deployment/detail',
    k8sDeploymentUpdate: 'http://localhost:9091/api/k8s/deployment/update',
    k8sDeploymentScale: 'http://localhost:9091/api/k8s/deployment/scale',
    k8sDeploymentRestart: 'http://localhost:9091/api/k8s/deployment/restart',
    k8sDeploymentDel: 'http://localhost:9091/api/k8s/deployment/del',
    k8sDeploymentCreate: 'http://localhost:9091/api/k8s/deployment/create',
    k8sDeploymentNumNp: 'http://localhost:9091/api/k8s/deployment/numnp',
    k8sPodList: 'http://localhost:9091/api/k8s/pods',
    k8sPodDetail: 'http://localhost:9091/api/k8s/pod/detail',
    k8sPodUpdate: 'http://localhost:9091/api/k8s/pod/update',
    k8sPodDel: 'http://localhost:9091/api/k8s/pod/del',
    k8sPodContainer: 'http://localhost:9091/api/k8s/pod/container',
    k8sPodLog: 'http://localhost:9091/api/k8s/pod/log',
    k8sPodNumNp: 'http://localhost:9091/api/k8s/pod/numnp',
    k8sDaemonSetList: 'http://localhost:9091/api/k8s/daemonsets',
    k8sDaemonSetDetail: 'http://localhost:9091/api/k8s/daemonset/detail',
    k8sDaemonSetUpdate: 'http://localhost:9091/api/k8s/daemonset/update',
    k8sDaemonSetDel: 'http://localhost:9091/api/k8s/daemonset/del',
    k8sStatefulSetList: 'http://localhost:9091/api/k8s/statefulsets',
    k8sStatefulSetDetail: 'http://localhost:9091/api/k8s/statefulset/detail',
    k8sStatefulSetUpdate: 'http://localhost:9091/api/k8s/statefulset/update',
    k8sStatefulSetDel: 'http://localhost:9091/api/k8s/statefulset/del',
    k8sServiceList: 'http://localhost:9091/api/k8s/services',
    k8sServiceDetail: 'http://localhost:9091/api/k8s/service/detail',
    k8sServiceUpdate: 'http://localhost:9091/api/k8s/service/update',
    k8sServiceDel: 'http://localhost:9091/api/k8s/service/del',
    k8sServiceCreate: 'http://localhost:9091/api/k8s/service/create',
    k8sIngressList: 'http://localhost:9091/api/k8s/ingresses',
    k8sIngressDetail: 'http://localhost:9091/api/k8s/ingress/detail',
    k8sIngressUpdate: 'http://localhost:9091/api/k8s/ingress/update',
    k8sIngressDel: 'http://localhost:9091/api/k8s/ingress/del',
    k8sIngressCreate: 'http://localhost:9091/api/k8s/ingress/create',
    k8sConfigMapList: 'http://localhost:9091/api/k8s/configmaps',
    k8sConfigMapDetail: 'http://localhost:9091/api/k8s/configmap/detail',
    k8sConfigMapUpdate: 'http://localhost:9091/api/k8s/configmap/update',
    k8sConfigMapDel: 'http://localhost:9091/api/k8s/configmap/del',
    k8sSecretList: 'http://localhost:9091/api/k8s/secrets',
    k8sSecretDetail: 'http://localhost:9091/api/k8s/secret/detail',
    k8sSecretUpdate: 'http://localhost:9091/api/k8s/secret/update',
    k8sSecretDel: 'http://localhost:9091/api/k8s/secret/del',
    k8sPvcList: 'http://localhost:9091/api/k8s/pvcs',
    k8sPvcDetail: 'http://localhost:9091/api/k8s/pvc/detail',
    k8sPvcUpdate: 'http://localhost:9091/api/k8s/pvc/update',
    k8sPvcDel: 'http://localhost:9091/api/k8s/pvc/del',
    k8sNodeList: 'http://localhost:9091/api/k8s/nodes',
    k8sNodeDetail: 'http://localhost:9091/api/k8s/node/detail',
    k8sNamespaceList: 'http://localhost:9091/api/k8s/namespaces',
    k8sNamespaceDetail: 'http://localhost:9091/api/k8s/namespace/detail',
    k8sNamespaceDel: 'http://localhost:9091/api/k8s/namespace/del',
    k8sPvList: 'http://localhost:9091/api/k8s/pvs',
    k8sPvDetail: 'http://localhost:9091/api/k8s/pv/detail',
    k8sTerminalWs: 'ws://localhost:8081/ws',
    //编辑器配置
    cmOptions: {
        // 语言及语法模式
        mode: 'text/yaml',
        // 主题
        theme: 'idea',
        // 显示行数
        lineNumbers: true,
        smartIndent: true, //智能缩进
        indentUnit: 4, // 智能缩进单元长度为 4 个空格
        styleActiveLine: true, // 显示选中行的样式
        matchBrackets: true, //每当光标位于匹配的方括号旁边时,都会使其高亮显示
        readOnly: false,
        lineWrapping: true //自动换行
    }
}

3. Deployment

3.1 Deployment.vue

src/views/workload/Deployment.vue

<template>
  <div class="deploy">
    <el-row>
      <!-- 头部1 -->
      <el-col :span="24">
        <div>
          <!-- 包一层卡片 -->
          <el-card class="deploy-head-card" shadow="never" :body-style="{padding:'10px'}">
            <el-row>
              <!-- 命名空间的下拉框 -->
              <el-col :span="6">
                <div>
                  <span>命名空间:</span>
                  <!-- 下拉框 -->
                  <!-- filterable:带搜索功能 -->
                  <!-- placeholder 默认提示 -->
                  <!-- label 显示内容 -->
                  <!-- value 绑定到v-model的值中 -->
                  <el-select v-model="namespaceValue" filterable placeholder="请选择" class="deploy-head-card-select">
                    <el-option
                        v-for="(item, index) in namespaceList"
                        :key="index"
                        :label="item.metadata.name"
                        :value="item.metadata.name">
                    </el-option>
                  </el-select>
                </div>
              </el-col>
              <!-- 刷新按钮 -->
              <el-col :span="2" :offset="16">
                <div>
                  <!-- 每次刷新,都重新调一次list接口,刷新表格中的数据 -->
                  <el-button style="border-radius:2px;" icon="Refresh" plain @click="getDeployments()">刷新</el-button>
                </div>
              </el-col>
            </el-row>
          </el-card>
        </div>
      </el-col>
      <!-- 头部2 -->
      <el-col :span="24">
        <div>
          <!-- 包一层卡片 -->
          <el-card class="deploy-head-card" shadow="never" :body-style="{padding:'10px'}">
            <el-row>
              <!-- 创建按钮 -->
              <el-col :span="2">
                <div>
                  <!-- 点击后打开抽屉,填入创建deployment需要的数据 -->
                  <el-button style="border-radius:2px;" icon="Edit" type="primary" @click="createDeploymentDrawer = true" v-loading.fullscreen.lock="fullscreenLoading">创建</el-button>
                </div>
              </el-col>
              <!-- 搜索框和搜索按钮 -->
              <el-col :span="6">
                <div>
                  <el-input class="deploy-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
                  <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getDeployments()">搜索</el-button>
                </div>
              </el-col>
            </el-row>
          </el-card>
        </div>
      </el-col>
      <!-- 数据表格 -->
      <el-col :span="24">
        <div>
          <!-- 包一层卡片 -->
          <el-card class="deploy-body-card" shadow="never" :body-style="{padding:'5px'}">
            <!-- 数据表格 -->
            <!-- v-loading用于加载时的loading动画 -->
            <el-table
                style="width:100%;font-size:12px;margin-bottom:10px;"
                :data="deploymentList"
                v-loading="appLoading">
              <!-- 最左侧留出20px的宽度,更加没关 -->
              <el-table-column width="20"></el-table-column>
              <!-- deployment名字 -->
              <el-table-column align=left label="Deployment名">
                <!-- 插槽,scope.row获取当前行的数据 -->
                <template v-slot="scope">
                  <a class="deploy-body-deployname">{{ scope.row.metadata.name }}</a>
                </template>
              </el-table-column>
              <!-- 标签 -->
              <el-table-column align=center label="标签">
                <template v-slot="scope">
                  <!-- for循环,每个label只显示固定长度,鼠标悬停后气泡弹出框显示完整长度 -->
                  <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
                    <!-- 气泡弹出框 -->
                    <!-- placement 弹出位置 -->
                    <!-- trigger 触发条件 -->
                    <!-- content 弹出框内容 -->
                    <el-popover
                        placement="right"
                        :width="200"
                        trigger="hover"
                        :content="key + ':' + val">
                      <template #reference>
                        <!-- ellipsis方法用于剪裁字符串 -->
                        <el-tag style="margin-bottom: 5px" type="warning">{{ ellipsis(key + ":" + val) }}</el-tag>
                      </template>
                    </el-popover>
                  </div>
                </template>
              </el-table-column>
              <!-- 容器组 -->
              <el-table-column align=center label="容器组">
                <!-- 可用数量/总数量,三元运算,若值大于0则显示值,否则显示0 -->
                <template v-slot="scope">
                  <span>{{ scope.row.status.availableReplicas>0?scope.row.status.availableReplicas:0  }} / {{ scope.row.spec.replicas>0?scope.row.spec.replicas:0 }} </span>
                </template>
              </el-table-column>
              <!-- 创建时间 -->
              <el-table-column align=center min-width="100" label="创建时间">
                <!-- timeTrans函数用于将格林威治时间转成北京时间 -->
                <template v-slot="scope">
                  <el-tag type="info">{{ timeTrans(scope.row.metadata.creationTimestamp) }} </el-tag>
                </template>
              </el-table-column>
              <!-- 容器镜像 -->
              <el-table-column align=center label="镜像">
                <!-- 与label的显示逻辑一致 -->
                <template v-slot="scope">
                  <div v-for="(val, key) in scope.row.spec.template.spec.containers" :key="key">
                    <el-popover
                        placement="right"
                        :width="200"
                        trigger="hover"
                        :content="val.image">
                      <template #reference>
                        <el-tag style="margin-bottom: 5px">{{ ellipsis(val.image.split('/')[2]==undefined?val.image:val.image.split('/')[2]) }}</el-tag>
                      </template>
                    </el-popover>
                  </div>
                </template>
              </el-table-column>
              <!-- 操作列,放按钮 -->
              <el-table-column align=center label="操作" width="400">
                <template v-slot="scope">
                  <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getDeploymentDetail(scope)">YAML</el-button>
                  <el-button size="small" style="border-radius:2px;" icon="Plus" type="primary" @click="handleScale(scope)">扩缩</el-button>
                  <el-button size="small" style="border-radius:2px;" icon="RefreshLeft" type="primary" @click="handleConfirm(scope, '重启', restartDeployment)">重启</el-button>
                  <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delDeployment)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>
            <!-- 分页配置 -->
            <!-- background 背景色灰 -->
            <!-- size-change 单页大小改变后触发 -->
            <!-- current-change 页数改变后触发 -->
            <!-- current-page 当前页 -->
            <!-- page-size 单页大小 -->
            <!-- layout 分页器支持的功能 -->
            <!-- total 数据总条数 -->
            <el-pagination
                class="deploy-body-pagination"
                background
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="currentPage"
                :page-sizes="pagesizeList"
                :page-size="pagesize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="deploymentTotal">
            </el-pagination>
          </el-card>
        </div>
      </el-col>
    </el-row>
    <!-- 抽屉:创建Deployment的表单 -->
    <!-- v-model 值是bool,用于显示与隐藏 -->
    <!-- direction 显示的位置 -->
    <!-- before-close 关闭时触发,点击关闭或者点击空白都会触发 -->
    <el-drawer
        v-model="createDeploymentDrawer"
        :direction="direction"
        :before-close="handleClose">
      <!-- 插槽,抽屉标题 -->
      <template #title>
        <h4>创建Deployment</h4>
      </template>
      <!-- 插槽,抽屉body -->
      <template #default>
        <!-- flex布局,居中 -->
        <el-row type="flex" justify="center">
          <el-col :span="20">
            <!-- ref绑定控件后,js中才能用this.$ref获取该控件 -->
            <!-- rules 定义form表单校验规则 -->
            <el-form ref="createDeployment" :rules="createDeploymentRules" :model="createDeployment" label-width="80px">
              <!-- prop用于rules中的校验规则的key -->
              <el-form-item class="deploy-create-form" label="名称" prop="name">
                <el-input v-model="createDeployment.name"></el-input>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="命名空间" prop="namespace">
                <el-select v-model="createDeployment.namespace" filterable placeholder="请选择">
                  <el-option
                      v-for="(item, index) in namespaceList"
                      :key="index"
                      :label="item.metadata.name"
                      :value="item.metadata.name">
                  </el-option>
                </el-select>
              </el-form-item>
              <!-- 数字输入框,最小为1,最大为10 -->
              <el-form-item class="deploy-create-form" label="副本数" prop="replicas">
                <el-input-number v-model="createDeployment.replicas" :min="1" :max="10"></el-input-number>
                <!-- 气泡弹出框用于提醒上限 -->
                <el-popover
                    placement="top"
                    :width="100"
                    trigger="hover"
                    content="申请副本数上限为10个">
                  <template #reference>
                    <el-icon style="width:2em;font-size:18px;color:#4795EE"><WarningFilled/></el-icon>
                  </template>
                </el-popover>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="镜像" prop="image">
                <el-input v-model="createDeployment.image"></el-input>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="标签" prop="label_str">
                <el-input v-model="createDeployment.label_str" placeholder="示例: project=ms,app=gateway"></el-input>
              </el-form-item>
              <!-- 下拉框,用于规格的选择,之后用/分割,得到cpu和内存 -->
              <el-form-item class="deploy-create-form" label="资源配额" prop="resource">
                <el-select v-model="createDeployment.resource" placeholder="请选择">
                  <el-option value="0.5/1" label="0.5C1G"></el-option>
                  <el-option value="1/2" label="1C2G"></el-option>
                  <el-option value="2/4" label="2C4G"></el-option>
                  <el-option value="4/8" label="4C8G"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="容器端口" prop="container_port">
                <el-input v-model="createDeployment.container_port" placeholder="示例: 80"></el-input>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="健康检查" prop="health">
                <el-switch v-model="createDeployment.health_check" />
              </el-form-item>
              <el-form-item class="deploy-create-form" label="检查路径" prop="healthPath">
                <el-input v-model="createDeployment.health_path" placeholder="示例: /health"></el-input>
              </el-form-item>
            </el-form>
          </el-col>
        </el-row>
      </template>
      <!-- 插槽,抽屉footer -->
      <template #footer>
        <!-- 点击后赋值false,隐藏抽屉 -->
        <el-button @click="createDeploymentDrawer = false">取消</el-button>
        <el-button type="primary" @click="submitForm('createDeployment')">立即创建</el-button>
      </template>
    </el-drawer>
    <!-- 展示YAML信息的弹框 -->
    <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="2%">
      <!-- codemirror编辑器 -->
      <!-- border 带边框 -->
      <!-- options  编辑器配置 -->
      <!-- change 编辑器中的内容变化时触发 -->
      <codemirror
          :value="contentYaml"
          border
          :options="cmOptions"
          height="500"
          style="font-size:14px;"
          @change="onChange"
      ></codemirror>
      <template #footer>
                <span class="dialog-footer">
                    <el-button @click="this.yamlDialog = false">取 消</el-button>
                    <el-button type="primary" @click="updateDeployment()">更 新</el-button>
                </span>
      </template>
    </el-dialog>
    <!-- 调整副本数的弹框 -->
    <el-dialog title="副本数调整" v-model="scaleDialog" width="25%">
      <div style="text-align:center">
        <span>实例数: </span>
        <el-input-number :step="1" v-model="scaleNum" :min="0" :max="30" label="描述文字"></el-input-number>
      </div>
      <template #footer>
                <span class="dialog-footer">
                    <el-button @click="scaleDialog = false">取 消</el-button>
                    <el-button type="primary" @click="scaleDeployment()">更 新</el-button>
                </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import common from "../common/Config.js";
import httpClient from '../../utils/request';
import yaml2obj from 'js-yaml';
import json2yaml from 'json2yaml';
export default {
  data() {
    return {
      //编辑器配置
      cmOptions: common.cmOptions,
      contentYaml: '',
      //分页
      currentPage: 1,
      pagesize: 10,
      pagesizeList: [10, 20, 30],
      //搜索框内容
      searchInput: '',
      //命名空间
      namespaceValue: 'default',
      namespaceList: [],
      namespaceListUrl: common.k8sNamespaceList,
      //列表
      appLoading: false,
      deploymentList: [],
      deploymentTotal: 0,
      getDeploymentsData: {
        url: common.k8sDeploymentList,
        params: {
          filter_name: '',
          namespace: '',
          page: '',
          limit: '',
        }
      },
      //创建
      fullscreenLoading: false,
      direction: 'rtl',
      createDeploymentDrawer: false,
      createDeployment: {
        name: '',
        namespace: '',
        replicas: 1,
        image: '',
        resource: '',
        health_check: false,
        health_path: '',
        label_str: '',
        label: {},
        container_port: ''
      },
      //创建请求的参数
      createDeploymentData: {
        url: common.k8sDeploymentCreate,
        params: {}
      },
      //创建deployment的表单校验规则
      createDeploymentRules: {
        name: [{
          required: true,
          message: '请填写名称',
          trigger: 'change'
        }],
        image: [{
          required: true,
          message: '请填写镜像',
          trigger: 'change'
        }],
        namespace: [{
          required: true,
          message: '请选择命名空间',
          trigger: 'change'
        }],
        resource: [{
          required: true,
          message: '请选择配额',
          trigger: 'change'
        }],
        label_str: [{
          required: true,
          message: '请填写标签',
          trigger: 'change'
        }],
        container_port: [{
          required: true,
          message: '请填写容器端口',
          trigger: 'change'
        }],
      },
      //详情
      deploymentDetail: {},
      getDeploymentDetailData: {
        url: common.k8sDeploymentDetail,
        params: {
          deployment_name: '',
          namespace: ''
        }
      },
      //yaml更新
      yamlDialog: false,
      updateDeploymentData: {
        url: common.k8sDeploymentUpdate,
        params: {
          namespace: '',
          content: ''
        }
      },
      //扩缩容
      scaleNum: 0,
      scaleDialog: false,
      scaleDeploymentData: {
        url: common.k8sDeploymentScale,
        params: {
          deployment_name: '',
          namespace: '',
          scale_num: ''
        }
      },
      //重启
      restartDeploymentData: {
        url: common.k8sDeploymentRestart,
        params: {
          deployment_name: '',
          namespace: '',
        }
      },
      //删除
      delDeploymentData: {
        url: common.k8sDeploymentDel,
        params: {
          deployment_name: '',
          namespace: '',
        }
      },
    }
  },
  methods: {
    //json转yaml方法
    transYaml(content) {
      return json2yaml.stringify(content)
    },
    //yaml转对象
    transObj(content) {
      return yaml2obj.load(content)
    },
    //编辑器内容变化时触发的方式,用于将更新的内容复制到变量中
    onChange(val) {
      this.contentYaml = val
    },
    //页面大小发生变化时触发,赋值并重新获取列表
    handleSizeChange(size) {
      this.pagesize = size;
      this.getDeployments()
    },
    //页数发生变化时触发,复制并重新获取列表
    handleCurrentChange(currentPage) {
      this.currentPage = currentPage;
      this.getDeployments()
    },
    //处理抽屉的关闭,增加体验感
    handleClose(done) {
      this.$confirm('确认关闭?')
          .then(() => {
            done();
          })
          .catch(() => {});
    },
    //字符串截取、拼接并返回
    ellipsis(value) {
      return value.length>15?value.substring(0,15)+'...':value
    },
    //格林威治时间转为北京时间
    timeTrans(timestamp) {
      let date = new Date(new Date(timestamp).getTime() + 8 * 3600 * 1000)
      date = date.toJSON();
      date = date.substring(0, 19).replace('T', ' ')
      return date
    },
    //获取Namespace列表
    getNamespaces() {
      httpClient.get(this.namespaceListUrl)
          .then(res => {
            this.namespaceList = res.data.items
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //获取Deployment列表
    getDeployments() {
      //表格加载动画开启
      this.appLoading = true
      //getDeploymentsData是用于发起deployment列表请求的专用的对象,里面有url和params参数,以下是赋值
      this.getDeploymentsData.params.filter_name = this.searchInput
      this.getDeploymentsData.params.namespace = this.namespaceValue
      this.getDeploymentsData.params.page = this.currentPage
      this.getDeploymentsData.params.limit = this.pagesize
      httpClient.get(this.getDeploymentsData.url, {params: this.getDeploymentsData.params})
          .then(res => {
            //响应成功,获取deployment列表和total
            this.deploymentList = res.data.items
            this.deploymentTotal = res.data.total
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //加载动画关闭
      this.appLoading = false
    },
    //获取deployment详情,e参数标识传入的scope插槽,.row是该行的数据
    getDeploymentDetail(e) {
      this.getDeploymentDetailData.params.deployment_name = e.row.metadata.name
      this.getDeploymentDetailData.params.namespace = this.namespaceValue
      httpClient.get(this.getDeploymentDetailData.url, {params: this.getDeploymentDetailData.params})
          .then(res => {
            this.contentYaml = this.transYaml(res.data)
            //打开弹出框
            this.yamlDialog = true
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //更新deployment
    updateDeployment() {
      //将yaml格式的deployment对象转为json
      let content = JSON.stringify(this.transObj(this.contentYaml))
      this.updateDeploymentData.params.namespace = this.namespaceValue
      this.updateDeploymentData.params.content = content
      httpClient.put(this.updateDeploymentData.url, this.updateDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            //更新后重新获取列表
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //关闭弹出框
      this.yamlDialog = false
    },
    //扩缩容的中间方法,用于赋值及打开弹出框
    handleScale(e) {
      this.scaleDialog = true
      this.deploymentDetail = e.row
      this.scaleNum = e.row.spec.replicas
    },
    //扩缩容deployment
    scaleDeployment() {
      this.scaleDeploymentData.params.deployment_name = this.deploymentDetail.metadata.name
      this.scaleDeploymentData.params.namespace = this.namespaceValue
      this.scaleDeploymentData.params.scale_num = this.scaleNum
      httpClient.put(this.scaleDeploymentData.url, this.scaleDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            //更新后重新获取列表
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //关闭弹出框
      this.scaleDialog = false
    },
    //重启deployment
    restartDeployment(e) {
      this.restartDeploymentData.params.deployment_name = e.row.metadata.name
      this.restartDeploymentData.params.namespace = this.namespaceValue
      httpClient.put(this.restartDeploymentData.url, this.restartDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //删除deployment
    delDeployment(e) {
      this.delDeploymentData.params.deployment_name = e.row.metadata.name
      this.delDeploymentData.params.namespace = this.namespaceValue
      httpClient.delete(this.delDeploymentData.url, {data: this.delDeploymentData.params})
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //弹出确认框,用于危险操作的double check
    //obj是行数据,opeateName是操作名,fn是操作的方法
    handleConfirm(obj, operateName, fn) {
      this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
      //$confirm用于弹出确认框
      this.$confirm(this.confirmContent,'提示',{
        confirmButtonText: '确定',
        cancelButtonText: '取消',
      })
          .then(() => {
            fn(obj)
          })
          .catch(() => {
            this.$message.info({
              message: '已取消操作'
            })
          })
    },
    //创建deployment,加Func的原因是因为createDeploy用于属性了
    createDeployFunc() {
      //正则匹配,验证label的合法性
      let reg = new RegExp("(^[A-Za-z]+=[A-Za-z0-9]+).*")
      if (!reg.test(this.createDeployment.label_str)) {
        this.$message.warning({
          message: "标签填写异常,请确认后重新填写"
        })
        return
      }
      //加载loading动画
      this.fullscreenLoading = true
      //定义label、cpu和memory变量
      let label = new Map()
      let cpu, memory
      //将label字符串转成数组
      let a = (this.createDeployment.label_str).split(",")
      //将数组转成map
      a.forEach(item => {
        let b = item.split("=")
        label[b[0]] = b[1]
      })
      //将deployment的规格转成cpu和memory
      let resourceList = this.createDeployment.resource.split("/")
      cpu = resourceList[0]
      memory = resourceList[1] + "Gi"
      //赋值
      this.createDeploymentData.params = this.createDeployment
      this.createDeploymentData.params.container_port = parseInt(this.createDeployment.container_port)
      this.createDeploymentData.params.label = label
      this.createDeploymentData.params.cpu = cpu
      this.createDeploymentData.params.memory = memory
      httpClient.post(this.createDeploymentData.url, this.createDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            //创建后重新获取列表
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //重置表单
      this.resetForm('createDeployment')
      //关闭加载动画
      this.fullscreenLoading = false
      //关闭抽屉
      this.createDeploymentDrawer = false
    },
    //重置表单方法,element plus课程讲过的
    resetForm(formName) {
      this.$refs[formName].resetFields()
    },
    //提交表单,校验参数合法性
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.createDeployFunc()
        } else {
          return false;
        }
      })
    }
  },
  watch: {
    //监听namespace的值,若发生变化,则执行handler方法中的内容
    namespaceValue: {
      handler() {
        //将namespace的值存入本地,用于path切换时依旧能获取得到
        localStorage.setItem('namespace', this.namespaceValue)
        //重置当前页为1
        this.currentPage = 1
        //获取deployment列表
        this.getDeployments()
      }
    },
  },
  beforeMount() {
    //加载页面时先获取localStorage中的namespace值,若获取不到则默认default
    if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
      this.namespaceValue = localStorage.getItem('namespace')
    }
    this.getNamespaces()
    this.getDeployments()
  }
}
</script>


<style scoped>
/* 卡片属性 */
.deploy-head-card,.deploy-body-card {
  border-radius: 5px;
  margin-bottom: 5px;
}
.deploy-head-card-select {
  margin-left: 10px;
}
/* 搜索框 */
.deploy-head-search {
  width:160px;
  margin-right:10px;
}
/* 数据表格deployment名颜色 */
.deploy-body-deployname {
  color: #4795EE;
}
/* deployment名鼠标悬停 */
.deploy-body-deployname:hover {
  color: rgb(84, 138, 238);
  cursor: pointer;
  font-weight: bold;
}
</style>

3.2 main.js

src/main.js中引入codemirror

//codemirror编辑器
import { GlobalCmComponent } from "codemirror-editor-vue3";
// 引入主题
import 'codemirror/theme/idea.css'
// 引入yaml
import 'codemirror/mode/yaml/yaml.js'

4. 测试

4.1 显示命名空间下的deployment

请添加图片描述

4.2 创建Deployment

请添加图片描述

请添加图片描述

命令行下确认

请添加图片描述

4.3 显示yaml

通过修改yaml给deployment增加标签

请添加图片描述

请添加图片描述

请添加图片描述

4.4 删除deployment

请添加图片描述

命令行下确认

请添加图片描述

4.5 扩缩容

4.5.1 扩容

请添加图片描述

请添加图片描述

命令行确认

请添加图片描述

4.5.2 缩容

请添加图片描述
请添加图片描述

命令行

请添加图片描述

4.6 重启

请添加图片描述

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/374277.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RCEE: Event Extraction as Machine Reading Comprehension 论文解读

RCEE: Event Extraction as Machine Reading Comprehension 论文&#xff1a;Event Extraction as Machine Reading Comprehension (aclanthology.org) 代码&#xff1a;jianliu-ml/EEasMRC (github.com) 期刊/会议&#xff1a;EMNLP 2020 摘要 事件提取(Event extraction,…

Slurm集群调度策略详解(2)-回填调度

1. slurm集群调度系统简介 作业调度系统其实就是指按一定策略把并行程序的各子任务或者是面向多用户的一组作业按一定的选择策略使之与各计算节点的空闲资源相对应&#xff0c;让其在对应的资源上运行&#xff0c;所以作业调度系统是联系上层应用和下层资源的中枢。一个集群资…

纯x86汇编实现的多线程操作系统实践 - 第六章 AP1的用户进程

AP1用户进程的代码为task1.asm。该用户进程将调用0x80系统中断在界面上显示一张BMP格式的图片。用户进程还使用了彩色转灰色技术&#xff0c;轮流显示该图片的彩色和灰色图。代码解释如下&#xff1a;调用0x39号系统中断&#xff0c;从300号扇区获得一个扇区的数据&#xff08;…

【华为OD机试模拟题】用 C++ 实现 - 身高排序(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明身高排序题目输入输出示例一输入输出Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:ht…

每日学术速递2.27

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CL 1.FiTs: Fine-grained Two-stage Training for Knowledge-aware Question Answering 标题&#xff1a;FiTs&#xff1a;用于知识感知问答的细粒度两阶段训练 作者&#xff1a;Qichen…

JavaWeb JavaBean,MVC三层架构

9、JavaBean 实体类 JavaBean有特定的写法&#xff1a; 必须要有一个无参构造属性必须私有化必须有对应的get/set方法&#xff1b; 一般用来和数据库的字段做映射 ORM&#xff1b; ORM &#xff1a;对象关系映射 表—>类字段–>属性行记录---->对象 people表 …

Qt 小项目 图片浏览系统

引言 本系统支持&#xff0c;自动播放&#xff0c;左右拖动切换&#xff0c;点击列表切换&#xff0c;点击按钮切换&#xff1b;是一个标准的图像浏览软件。 Windows 图片浏览器&#xff0c;可以查看当前文件夹下的图片&#xff0c;往上翻、往下翻并且自动播放&#xff1b; …

这只乌龟,当然离不开函数了!

什么是函数&#xff1f;函数就是执行特定任务和以完成特定功能的一段代码为什么需要函数&#xff1f;复用代码隐藏实现细节提高可维护性提高可读性便于调试函数的创建def 函数名 ([输入参数]) :函数体[return xxx]函数名需要遵循字母、数字、下划线# 这里的a&#xff0c;b是形式…

03 流程控制

3.1 条件判断3.2 循环控制3.3 中断循环 3.1 条件判断 if 条件判断 &#xff1a;单分支&#xff08;if&#xff09;、双分支&#xff08;if…else…&#xff09;、多分支&#xff08;if … else if … else&#xff09;Switch&#xff08;Scala并没有 switch&#xff0c;用的是…

2023年鞋服配饰行业如何玩转全域经营?

2023年&#xff0c;鞋服配饰行业私域已进入深水区&#xff0c;这就对私域运营提出了更高的挑战和目标&#xff0c;企业纷纷发力以私域为基石、以消费者为核心的全域经营。 不过&#xff0c;虽然鞋服配饰行业私域起步早&#xff0c;玩法多。但在迈向全域经营的过程中&#xff0…

全网详细介绍nginx的反向代理、正向代理配置,location的指令说明,反向代理的两个示例代码以及全局块,events块和http快的说明。

文章目录1. 文章引言2. 何谓反向代理3. 解析nginx的配置文件3.1 全局块(global block)3.2 events块(events block)3.3 http块(http block)4. 如何配置反向代理4.1 反向代理示例14.2 反向代理示例25. 补充说明5.1 location指令说明5.2 nginx完整配置文件1. 文章引言 如果你的服务…

聚合效度全流程

聚合效度分析流程如下&#xff1a; 一、聚合效度定义 聚合效度&#xff08;convergent validity&#xff09;&#xff0c;又称收敛效度&#xff0c;是指测量同一变量的测量项会落在同一因子上&#xff0c;强调本应该在同一因子下的测量项&#xff0c;确实在同一因子下。即一个…

基于nodejs+vue地方特色的风景文化宣传网站vscode

管理员可以根据系统给定的账号进行登录&#xff0c;登录后可以进入木里风景文化管理平台对木里风景文化所有模块进行管理。包括查看和修改自己的个人信息以及登录密码。 该系统为每一个用户都分配了一个用户账号&#xff0c;用户通过账号的登录可以在系统中查看木里风景文化信息…

怎么依靠网络赚钱,网上可以做什么副业

如今&#xff0c;网上赚钱已经成为许多人职业生涯的选择之一。网上有很多可靠的兼职&#xff0c;让你在家里轻松赚钱。今天给大家推荐五份可靠的网上兼职。一、怎样选择可靠的网络兼职可靠的网络兼职一般是指在家通过网络平台完成兼职任务&#xff0c;完成任务后即可获得报酬。…

JVM中TLAB(Thread Local Allocation Buffer)+逃逸分析

1、为什么有TLAB&#xff08;Thread Local Allocation Buffer&#xff09;堆区是线程共享区域&#xff0c;任何线程都可以访问到堆区中的共享数据 由于对象实例的创建在JVM中非常频繁&#xff0c;因此在并发环境下从堆区中划分内存空间是线程不安全的 为避免多个线程操作同一地…

java地图导出——添加经纬线

概述 前面的文章Node实现切片的拼接和地图的导出和Java实现地图的导出分别讲述可如何在node和java中实现切片的拼接以及地图的导出。本文&#xff0c;书接前文&#xff0c;实现java导出时经纬度的添加。 实现后效果 实现 完整的实现思路流程如下图&#xff1a; 1. 根据切片…

什么是Makefile?如何编写Makefile?

&#x1f947;今日学习目标&#xff1a;什么是Makefile&#xff1f;如何编写Makefile&#xff1f; &#x1f935;‍♂️ 创作者&#xff1a;JamesBin ⏰预计时间&#xff1a;10分钟 &#x1f389;个人主页&#xff1a;嵌入式悦翔园个人主页 &#x1f341;专栏介绍&#xff1a;L…

RabbitMQ实现死信队列

目录死信队列是什么怎样实现一个死信队列说明实现过程导入依赖添加配置编写mq配置类添加业务队列的消费者添加死信队列的消费者添加消息发送者添加消息测试类测试死信队列的应用场景总结死信队列是什么 “死信”是RabbitMQ中的一种消息机制&#xff0c;当你在消费消息时&#…

单调栈(C/C++)

目录 1. 单调栈的定义 2. 单调栈的常见用途 3. 案例分析 3.1 暴力解法 3.2 单调栈 4. 单调栈总结 1. 单调栈的定义 单调栈顾名思义&#xff0c;就是栈内的元素是单调的。根据栈内元素的单调性的不同&#xff0c;可以分为&#xff1a; 单调递增栈&#xff1a;栈内元素是单…

LeetCode 105. 从前序与中序遍历序列构造二叉树 106. 从中序与后序遍历序列构造二叉树

为什么前序和中序或者中序和后序&#xff0c;两两组合能构建一个二叉树&#xff1f; 因为前序和后序可以确定根&#xff0c;而中序可以划分出左右区间。 文章目录从前序与中序遍历序列构造二叉树从中序与后序遍历序列构造二叉树从前序与中序遍历序列构造二叉树 难度 中等 题目链…