在K8s中定义Pod中运行容器有两个维度的限制:
 1. 资源需求:即运行Pod的节点必须满足运行Pod的最基本需求才能运行Pod。
   如: Pod运行至少需要2G内存,1核CPU
    2. 资源限额:即运行Pod期间,可能内存使用量会增加,那最多能使用多少内存,这就是资源限额。

  

  1. # kubectl describe node node1.zcf.com
  2. .......................
  3. Allocated resources:
  4. (Total limits may be over percent, i.e., overcommitted.)
  5. Resource Requests Limits #这里显示的就是 资源的需求 和 限额
  6. -------- -------- ------
  7. cpu 250m (%) (%)
  8. memory (%) (%)
  9. ephemeral-storage (%) (%)
  10.  
  11. Requests: 就是需求限制,也叫软限制
  12. Limits:最大限制,也叫硬限制
  13. 通常来说:Limits >= Requests
  14. 并且requests limits 通常要一起配置,若只配置了requests,而不配置limits,则很可能导致Pod会吃掉所有资源。

需要注意:
  目前k8s在对资源限制方面还有欠缺,特别是Java应用,因为Pod运行起来后,它看到的资源是Node上全部的资源,虽然可通过requests和limits限制,但我们都知道JVM启动后,它要计算自己的堆内存中不同区域的大小,而这些大小通常是按比例划分的,假若JVM启动后,根据Node上实际的内存大小来计算堆内存中老年代,Eden,幸存区那肯定会出问题,因为,我们给它分片的内存肯定不够,所以这个要特别注意,而解决办法,只能是在启动Java应用前,配置JVM能使用的最大内存量。

在K8s的资源:
 CPU:
  我们知道2核2线程的CPU,可被系统识别为4个逻辑CPU,在K8s中对CPU的分配限制是对逻辑CPU做分片限制的。
  也就是说分配给容器一个CPU,实际是分配一个逻辑CPU。
  而且1个逻辑CPU还可被单独划分子单位,即 1个逻辑CPU,还可被划分为1000个millicore(毫核), 简单说就是1个逻辑CPU,继续逻辑分割为1000个豪核心。
  豪核:可简单理解为将CPU的时间片做逻辑分割,每一段时间片就是一个豪核心。
  所以:500m 就是500豪核心,即0.5个逻辑CPU.

 内存:
  K,M,G,T,P,E #通常这些单位是以1000为换算标准的。
  Ki, Mi, Gi, Ti, Pi, Ei #这些通常是以1024为换算标准的。

K8s中资源限制对调度Pod的影响:

  

cpu.limits: 是我们设置Pod运行时,最大可使用500m个CPU,但要保障Pod能在Node上成功启动起来,就必需能提供cpu.requests个CPU.
  当预选策略在选择备选Node时,会首先考虑当前Pod运行, 其所需资源是否足够, 来做为首要判断条件,假如某Node上已经运行了一些Pod,预选策略会获取当前所有Pod的cpu.requests ,ram.requests等,这里以cpu.requests来说明,比如说某Node上是2核2线程的CPU,所有容器的cpu.requests全部加起来假如已经3.9个CPU了,那么此Node在预选阶段就会被筛选掉。

资源限制配置:
  kubectl explain pods.spec.containers.resorces
    limits:<map[string]string>
    requests:<map[string]string>

  1. #以下压测时,若压测内存,可能导致登录容器都成问题,因此改为仅测试CPU。
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. name: pod-cpu-limits
  6. labels:
  7. app: test
  8. tier: frontend
  9. spec:
  10. containers:
  11. - name: myapp
  12. image: ikubernetes/stress-ng
  13. command: ["/usr/bin/stress-ng","-c 1","--metrics-brief"]
  14. resources:
  15. requests:
  16. cpu: "500m"
  17. memory: "512Mi"
  18. limits:
  19. cpu: "500m"
  20. memory: "512Mi"

QoS类型:
 Guranteed:
  每个容器的CPU,RAM资源都设置了相同值的requests 和 limits属性。
  简单说: cpu.limits = cpu.requests
      memory.limits = memory.requests
  这类Pod的运行优先级最高,但凡这样配置了cpu和内存的limits和requests,它会自动被归为此类。
  Burstable:
    每个容器至少定义了CPU,RAM的requests属性,这里说每个容器是指:一个Pod中可以运行多个容器。
    那么这类容器就会被自动归为burstable,而此类就属于中等优先级。
  BestEffort:
    没有一个容器设置了requests 或 limits,则会归为此类,而此类别是最低优先级。

QoS类型的作用:
  Node上会运行很多Pod,当运行一段时间后,发现Node上的资源紧张了,这时K8s就会根据QoS类别来选择Kill掉一部分Pod,那些会先被Kill掉?
  当然就是优先级最低的,也就是BestEffort,若BestEffort被Kill完了,还是紧张,接下来就是Kill中等优先级的,即Burstable,依次类推。

  这里有个问题,BestEffort因为没有设置requests和limits,可根据谁占用资源最多,就kill谁,但Burstable设置了requests和limits,它的kill标准是什么?
  若按照谁占资源多kill谁,那遇到这样的问题,怎么选择?
    PodA: 启动时设置了memory.request=512M , memory.limits=1G
    PodB: 设置为: memory.requests=1G, memory.limits=2G

    PodA: 运行了一段时间后,占用了500M了,它可能还有继续申请内存。
    PodB: 它则占用了512M内存了,但它可能也还需要申请内存。
    想想,现在Node资源紧张了,会先kill谁?
    其实,会优先kill PodA , 为啥?
    因为它启动时,说自己需要512M内存就够了,但你现在这么积极的申请内存,都快把你需求的内存吃完了,只能说明你太激进了,因此会先kill。
    而PodB,启动时需要1G,但目前才用了1半,说明它比较温和,因此不会先kill它。

K8s中Pod监控的指标有以下几类:
  1. Kubernetes系统指标
  2. 容器指标,即:容器使用的CPU,内存,存储等资源的统计用量的
  3. 应用指标,即业务应用的指标,如:接收了多少用户请求,正在处理的用户请求等等。

K8s中获取Node资源用量,Pod资源用量要如何实现?
  其实早期K8s中kubelet内封装了一个组件叫cAdvisor,它启动后,会监听在14041端口上,来对外提供单节点上Node和Pod的资源统计用量,但是由于安全性问题,后期就将kubelet上的cAdvisor改为不监听,而是会通过配置HeapSter Pod的访问cAdvisor的地址,将自己的统计数据发送给它,由它来负责存储这些统计数据,但HeapSter它默认是将数据存储在缓存中,不能持久存储,因此它需要借助InfluxDB来实现数据的持久化,这些资源统计用量被发给HeapSter后,若通过命令行工具来获取指定Node上的资源使用统计,以及Pod的资源使用统计时,可以用kubectl top   [node |pod] 来查看,但若想查看历史数据,就不能实现了,因为命令行工具只能从HeapSter来获取实时数据,而无法获取历史数据,若要获取历史数据,就必须借助另一个组件叫Grafana,它可以从InfluxDB中读取时序存储的数据,并通过图形界面来展示给用户。

  

  HeapSter 由于从Kubernetes1.11.1以后将被废弃,从11.2后将被彻底废弃。
  它被废弃的原因是,因为它自身的设计架构上,会去整合很多第三方开发的后端存储组件,其中InfluxDB就是其中之一,由于是第三方组织研发的,所以这就导致了一个问题,若那天第三方对此不感兴趣了,就会放弃对这些后端存储组件的维护,导致无法继续支持K8s后期版本的。另一个原因是在HeapSter中这些第三方存储组件也是作为其核心代码的一部分存在的,因此它带来的问题是,HeapSter的代码会越来越臃肿,而且配置也会越来越复杂,因而K8s才决定放弃HeapSter。

下面部署中使用了这样的版本组合:

 HeapSter-amd64:v1.5.4 + heapster-influxdb-amd64:v1.5 + heapster-grafana-amd64:v5.0.4
  #测试发现,不能正常工作,查看日志一切正常,但是无法正常获取监控指标数据。
使用下面这个旧版本的组合,是可以正常工作的,这个需要注意:
 HeapSter-amd64:v1.5.1 + heapster-influxdb-amd64:v1.3.3 + heapster-grafana-amd64:v4.4.3
  #这个组合中,grafana配置NodePort后,从外部访问,Grafana没有Web图像接口,但从日志上可以看到外部访问记录,也没有报错,怀疑其可能没有图像界面。
  #所以这个grafana组件可以不安装。另外,我测试将5.0.4的Grafana部署上,它可以连接到InfluxDB,应该是能获取数据,但因为没有默认面板,所以若想测试,需要自行到grafana官网去找一些模板测试。

构建上面三个组件的顺序:

  1. 先部署InfluxDB,因为它被HeapSter所依赖
    wget -c https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/influxdb.yaml

  2. 接着就可以直接应用此清单
    kubectl  apply  -f  influxdb.yaml
    若镜像下载失败,可尝试阿里云镜像的谷歌镜像仓库下载:
    docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/heapster-influxdb-amd64:v1.5.2

  3. 验证
    # kubectl  get  pod  -n  kube-system

     #kubectl describe pod  -n kube-system  monitoring-influxdb-xxxxx
    #从输出的信息中可以看到默认influxdb使用HTTP协议来对对外提供服务,你可以通过它的一些专用客户端工具来登入它,查看它所提供的服务。

   4. 接下来创建HeapSter,但创建HeapSter前需要先创建它所有依赖的RBAC配置,因为默认使用kubeasz部署的K8s集群是启用了RBAC的,因此需要先创建HeapSter所需的RBAC配置.
   wget -c https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/rbac/heapster-rbac.yaml

     kubectl  apply   heapster-rbac.yaml

    #创建完RBAC后,就可以创建heapster Pod了。
    wget https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/heapster.yaml

  1. #需要注意:
  2. apiVersion: v1
  3. kind: ServiceAccount #heapSter需要使用一个服务帐户,因为它需要能从所有Node上获取Pod的资源统计信息,因此它必须被授权.
  4. metadata:
  5. name: heapster
  6. namespace: kube-system
  7.  
  8. #在HeapSter容器定义部分可以看到它引用了上面创建的SA帐户
  9. spec:
  10. serviceAccountName: heapster
  11. containers:
  12. - name: heapster
  13. image: k8s.gcr.io/heapster-amd64:v1.5.4
  14. imagePullPolicy: IfNotPresent
  15. command:
  16. - /heapster
  17. - --source=kubernetes:https://kubernetes.default #这里是定义HeapSter从K8s内部访问APIServer的地址.
  18. - --sink=influxdb:http://monitoring-influxdb.kube-system.svc:8086
  19. #这是指明HeapSter访问InfluxDB的地址,因为InfluxDB是Pod,不能直接访问Pod的IP,因此这里访问的是InfluxDB前端的SerivseIP。
  20.  
  21. #另外还有注意,HeapSter也需要Serivce
  22. apiVersion: v1
  23. kind: Service
  24. .....
  25. name: heapster
  26. namespace: kube-system
  27. spec:
  28. ports:
  29. - port: #这里可以看到它在Node上暴露的端口是80
  30. targetPort: #HeapSter在Pod内部启动的端口为8082
  31. type: NodePort #若需要K8s外部访问HeapSter,可修改端口类型为NodePort
  32. selector:
  33. k8s-app: heapster

  #接着执行应用此清单
    kubectl  apply  -f   heapster.yaml

  #查看heapster的日志:

  kubectl  logs  -n kube-system   heapster-xxxxx

  

  5. 最后来部署Grafana
    wget https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/grafana.yaml

  1. #另外还有需要注意:
  2. volumeMounts:
  3. - mountPath: /etc/ssl/certs #它会自动挂载Node上的/etc/ssl/certs目录到容器中,并自动生成证书,因为它使用的HTTPS.
  4. name: ca-certificates
  5. readOnly: true
  6.  
  7. #Grafana启动时,会去连接数据源,默认是InfluxDB,这个配置是通过环境变量来传入的
  8. env:
  9. - name: INFLUXDB_HOST
  10. value: monitoring-influxdb #这里可看到,它将InfluxDB的Service名传递给Grafana了。
  11. - name: GF_SERVER_HTTP_PORT
  12. value: "" #默认Grafara在Pod内启动时,监听的端口也是通过环境变量传入的,默认是3000端口.
  13.  
  14. #在一个是,我们需要配置Grafana可以被外部直接访问
  15. ports:
  16. - port:
  17. targetPort:
  18. selector:
  19. k8s-app: grafana
  20. type: NodePort

部署完成后,可登录Dashboard查看资源状态统计信息

  

自定义资源:
  在K8s中支持用户根据自己业务的特殊需求去自定义服务组件,来扩展K8s原始的Service,headless等,这种被称为 自制资源定义(CRD)。
  另外在K8s中也可自己开发一个新的APIServer,它里面可提供自己所需要的API接口,然后在通过K8s 中的所谓的API聚合器将自己开发的APIServer和K8s自己的APIServer聚合在一起来使用它;在不然就是自己修改K8s源码,来新增需要的功能定义。

  K8s从1.8开始引入资源指标API,它将资源的内容也当作API接口中的数据直接进行获取,而不像早期HeapSter,需要先部署HeapSter,然后从HeapSter中获取资源指标数据,这样带来的不便是,我们获取数据就需要通过两个地方获取,当获取API资源(Pod, Service,...)是通过APIServer获取,而获取监控资源指标时,就必须从HeapSter中获取,而在新版的K8s中,引入资源指标API就是想避免这种麻烦,让用户再来获取数据时,全部从APIServer来获取,而要实现这个功能,它引入了一个API聚合器,因为资源监控指标API是允许用户自定义开发的,而开发出来的资源指标API通过一个类似代理层的API聚合器 将这些用户开发的资源指标API 和 原始的APIServer联合起来,用户通过访问API聚合器,来获取自己需要的数据,而API聚合器会根据用户的请求,自动将请求转发给APIServer或资源指标API。
  需要说明的是 资源指标API 分为两类,一类是核心指标,另一类是非核心指标,核心指标是metrics-server提供的,它也是一个Pod。
  HPA:它是水平Pod自动伸缩器,它也是需要获取资源指标来判断,并作出一些预定义动作,如:判断CPU使用率已经80%了,则会自动增加一个Pod,若发现某个Pod的资源使用率很低,一直维持在比如说5%,它可以自动关闭几个该Pod,以便腾出资源供其它Pod使用等。
  kubectl top .... 这个命令 和 HPA功能在早期都是需要依赖HeapSter来工作的,但是HeapSter有个很多的缺陷,它只能统计CPU,内存,磁盘等的资源用量,但无法获取其它更多资源指标,这就限制了我们想获取更多信息的途径,另外也使得HPA的功能受到了限制,例如有时候,Pod的CPU,内存等占有率不高,但其访问量却非常高,这时我们也希望能自动创建Pod来分担并发压力,但HeapSter就无法帮我们做的,因此才导致新的资源指标API的出现,以及后来又引入了自定义资源指标的模型。

Prometheus:它可以收集基本指标,同时还可以收集网络报文的收发速率,网络连接的数量,内存,包括进程的新建和回收的速率等等,而这些K8s早期是不支持的,它让我们可以使用这些功能来增强我们的HPA能力。它即作为监控组件使用,也作为一些特殊指标的资源提供者来提供,但这些不是内建的标准核心指标,这些我们统称为自定义指标。
需要注意Prometheus要想将它监控采集到的数据,转化为指标格式,需要一个特殊的组件,它叫 k8s-prometheus-adapter

K8s新一代监控指标架构由两部分组成:

  • 核心指标流水线:由Kubelet资源评估器,metrics-server,以及由APIServer提供的API组成,它里面主要提供最核心的监控指标。主要是通过它让Kubernetes自身的组件来了解内部组件和核心使用程序的指标,目前主要包含,CPU(CPU的累积使用率),内存的实时使用率,Pod的资源占用率和容器的磁盘占用率。【累积使用率:指一个进程累积使用CPU的总时长比例】
  • 监控流水线:用于从系统收集各种指标数据并提供给用户,存储,系统以及HPA来使用。 它包含核心指标,同时也包含许多非核心指标;非核心指标不一定能被K8s所理解,简单说:prometheus采集的数据,k8s可能不理解,因为这些数据定义只有在Prometheus的语境中才有定义,因此才需要一个中间组件叫 k8s-prometheus-adapter来将其转化为k8s能理解的监控指标定义。

metrics-server:
  它主要用于提供监控指标API,但它通常是由用户提供的API服务,它本身不是k8s的核心组件,它仅是K8s上的一个Pod,因此为了能让用户无缝的使用metrics-server上提供的API,因此就必须使用kube-aggregator。当然kube-aggregator不仅仅可以聚合传统APIServer和metrics-server,它还可以聚合很多用户自定义的API服务。

/apps/metrics.k8s.io/v1beta1:
  这个群组默认是不包含在创建API Server中的,因此你通过 kubectl api-versions 查看,是没有这个群组的,这个群组实际是由 metrics-server 来提供的,而我们需要做的是使用kube-aggregator将这个API群组合并到API Server中去,这样用户再去访问API Server时,就可以访问到此API群组了。

  1. #需要修改两个文件:
  2. #第一个文件: metrics-server-deployment.yaml
  3. #此清单文件定义了metrics-server镜像和metrics-server-nanny容器启动的参数,这些参数有些需要修改
  4. #metrics-server容器:
  5. command:
  6. - /metrics-server
  7. - --metric-resolution=30s
  8. #- --kubelet-insecure-tls
  9. #网上很多文章都说必须加上此参数, 此参数含义:
  10. #若不能做TLS加密认证,使用不安全的通信也可以.但我测试时,不加也能正常工作,仅做借鉴
  11. # These are needed for GKE, which doesn't support secure communication yet.
  12. # Remove these lines for non-GKE clusters, and when GKE supports token-based auth.
  13. - --kubelet-port=
  14. - --deprecated-kubelet-completely-insecure=true
  15. - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
  16.  
  17. #metrics-server-nanny容器:
  18. command:
  19. - /pod_nanny
  20. - --config-dir=/etc/config
  21. #下面这些{{....}} 这些若不替换,启动metrics-server-nanny容器时会报错,但从报错日志中可以到它们的简单说明
  22. - --cpu={{ base_metrics_server_cpu }} #设置metrics-server基本运行可用CPU豪核数量,测试设置100m
  23. - --extra-cpu=0.5m
  24. - --memory={{ base_metrics_server_memory }} #分配给metrics-server基本运行的内存大小, 测试设置 150Mi
  25. - --extra-memory={{ metrics_server_memory_per_node }}Mi #每个节点上的metrics-server额外分配内存大小,测试50Mi
  26. - --threshold=
  27. - --deployment=metrics-server-v0.3.3
  28. - --container=metrics-server
  29. - --poll-period=
  30. - --estimator=exponential
  31. # Specifies the smallest cluster (defined in number of nodes)
  32. # resources will be scaled to.
  33. #- --minClusterSize={{ metrics_server_min_cluster_size }}
  34. #这里字面意思似乎是 设置启动几组Metrics-server,选项说明提示默认是16组. 但这我注释掉了。
  35.  
  36. #第二个文件:resource-reader.yaml
  37. rules:
  38. - apiGroups:
  39. - ""
  40. resources:
  41. - pods
  42. - nodes
  43. - nodes/stats
  44. #这里需要注意:默认是没有添加的,若只添加nodes,它是获取不到nodes/stats的状态信息的,
  45. # 因为nodes/stats和nodes是两个不同的资源. nodes/stats是获取节点监控数据的专用资源.
  46. - namespaces
  47.  
  48. #以上两个文件修改好后,就可执行应用了
  49. kubectl apply -f ./
  50.  
  51. #在应用使用,可查看kube-system名称空间中 metrics-server pod的创建
  52. kubectl get pod -n kube-system -w #会发现metrics-server先创建一组,等第二组启动为running后,第一组就会自动终止。目前还没有弄明白是什么逻辑。
  53.  
  54. #上面修改好后,测试发现还是会报错,但已经不报参数无效的错误了
  55. # kubectl get pod -n kube-system
  56. NAME READY STATUS RESTARTS AGE
  57. ................
  58. metrics-server-v0.3.3-7d598d5c9d-qngp7 / Running 49s
  59.  
  60. # kubectl logs -n kube-system metrics-server-v0.3.3-7d598d5c9d-qngp7 -c metrics-server-nanny
  61. ERROR: logging before flag.Parse: I0729 ::42.923342 pod_nanny.go:] Invoked by [/pod_nanny --config-dir=/etc/config --cpu=100m --extra-cpu=0.5m --memory=300Mi --extra-memory=50Mi --threshold= --deployment=metrics-server-v0.3.3 --container=metrics-server --poll-period= --estimator=exponential]
  62. ERROR: logging before flag.Parse: I0729 ::42.923611 pod_nanny.go:] Watching namespace: kube-system, pod: metrics-server-v0.3.3-7d598d5c9d-qngp7, container: metrics-server.
  63. ERROR: logging before flag.Parse: I0729 ::42.923642 pod_nanny.go:] storage: MISSING, extra_storage: 0Gi
  64. ERROR: logging before flag.Parse: I0729 ::42.927214 pod_nanny.go:] cpu: 100m, extra_cpu: 0.5m, memory: 300Mi, extra_memory: 50Mi
  65. ERROR: logging before flag.Parse: I0729 ::42.927362 pod_nanny.go:] Resources: [{Base:{i:{value: scale:-} d:{Dec:<nil>} s:100m Format:DecimalSI} ExtraPerNode:{i:{value: scale:-} d:{Dec:<nil>} s: Format:DecimalSI} Name:cpu} {Base:{i:{value: scale:} d:{Dec:<nil>} s:300Mi Format:BinarySI} ExtraPerNode:{i:{value: scale:} d:{Dec:<nil>} s:50Mi Format:BinarySI} Name:memory}]
  66.  
  67. #上面准备就绪后,就可做以下测试
  68. . 查看api-versions是否多出了一个 metrics.k8s.io/v1beta1
  69. # kubectl api-versions
  70. .............
  71. metrics.k8s.io/v1beta1
  72.  
  73. . 若以上验证都通过了,则可做以下测试
  74. kubectl proxy --ports=
  75.  
  76. . 在另一个终端访问8080
  77. curl http://localhost:8080/apis/metrics.k8s.io/v1beta1
  78. {
  79. "kind": "APIResourceList",
  80. "apiVersion": "v1",
  81. "groupVersion": "metrics.k8s.io/v1beta1",
  82. "resources": [
  83. {
  84. "name": "nodes",
  85. "singularName": "",
  86. "namespaced": false,
  87. "kind": "NodeMetrics",
  88. "verbs": [
  89. "get",
  90. "list"
  91. ........................
  92. }
  93.  
  94. #查看收集到的Pods 和 node监控数据
  95. curl http://localhost:8080/apis/metrics.k8s.io/v1beta1/node

#查看是否能获取Node 和 Pod的资源使用情况:

  

通过上面部署metrics-server,我们可以获取到核心资源信息了,但是若想获取更多监控资源数据,就必须借助另一个Addons组件来获取,而这个Addons就是prometheus

prometheus

  它本身就是一个监控系统,它类似于Zabbix,它也需要在Node上安装Agent,而prometheus将自己的Agent称为node_exporter, 但这个node_exporter它仅是用于给Prometheus提供Node的系统级监控指标数据的,因此,若你想采集MySQL的监控数据,你还需要自己部署一个MySQL_exporter,才能采集mySQL的监控数据,而且Prometheus还有很多其它重量级的应用exporter,可在用到时自行学习。

  我们需要知道,若你能获取一个node上的监控指标数据,那么去获取该node上运行的Pod的指标数据就非常容易了。因此Prometheus,就是通过metrics URL来获取node上的监控指标数据的,当然我们还可以通过在Pod上定义一些监控指标数据,然后,定义annotations中定义允许 Prometheus来抓取监控指标数据,它就可以直接获取Pod上的监控指标数据了。

PromQL:
  这是Prometheus提供的一个RESTful风格的,强大的查询接口,这也是它对外提供的访问自己采集数据的接口。
  但是Prometheus采集的数据接口与k8s API Server资源指标数据格式不兼容,因此API Server是不能直接使用Prometheus采集的数据的,需要借助一个第三方开发的k8s-prometheus-adapter来解析prometheus采集到的数据, 这个第三方插件就是通过PromQL接口,获取Prometheus采集的监控数据,然后,将其转化为API Server能识别的监控指标数据格式,但是我们要想通过kubectl来查看这些转化后的Prometheus监控数据,还需要将k8s-prometheus-adpater聚合到API Server中,才能实现直接通过kubectl获取数据 。

#接下来部署Prometheus的步骤大致为:
  1. 部署Prometheus
  2. 配置Prometheus能够获取Pod的监控指标数据
  3. 在K8s上部署一个k8s-prometheus-adpater Pod
  4. 此Pod部署成功后,还需要将其聚合到APIServer中

  

说明:
  Prometheus它本身就是一个时序数据库,因为它内建了一个存储 所有eporter 或 主动上报监控指标数据给Prometheus的Push Gateway的数据 存储到自己的内建时序数据库中,因此它不需要想InfluxDB这种外部数据库来存数据。
  Prometheus在K8s中通过Service Discovery来找到需要监控的目标主机,然后通过想Grafana来展示自己收集到的所有监控指标数据,另外它还可以通过Web UI 或 APIClients(PromQL)来获取其中的数据。
  Prometheus自身没有提供报警功能,它会将自己的报警需求专给另一个组件Alertmanger来实现报警功能。

#在K8s上部署Prometheus需要注意,因为Prometheus本身是一个有状态数据集,因此建议使用statefulSet来部署并控制它,但是若你只打算部署一个副本,那么使用deployment和statefulSet就不重要了。但是你若需要后期进行纵向或横向扩展它,那你就只能使用StatefulSet来部署了。

部署K8s Prometheus
需要注意,这是马哥自己做的简版Prometheus,他没有使用PVC,若需要部署使用PVC的Prometheus,可使用kubernetes官方的Addons中的清单来创建。
官方地址:https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/prometheus
马哥版的地址:https://github.com/iKubernetes/k8s-prom

  1. 下面以马哥版本来做说明:
  2. . 先部署名称空间:
  3. kubectl apply -f namespace.yaml
  4. ---
  5. apiVersion: v1
  6. kind: Namespace
  7. metadata:
  8. name: prom #这里需要注意: 他是先创建了一个prom的名称空间,然后,将所有Prometheus的应用都放到这个名称空间了。
  9.  
  10. . 先创建node_exporter:
  11. cd node_exporter
  12. #需要注意:
  13. apiVersion: apps/v1
  14. kind: DaemonSet
  15. metadata:
  16. name: prometheus-node-exporter
  17. namespace: prom
  18. .......
  19. spec:
  20. tolerations: #这里需要注意:你要保障此Pod运行起来后,它能容忍Master上的污点.这里仅容忍了默认Master的污点.这里需要根据实际情况做确认。
  21. - effect: NoSchedule
  22. key: node-role.kubernetes.io/master
  23. containers:
  24. - image: prom/node-exporter:v0.15.2 #这里使用的node-exporter的镜像版本。
  25. name: prometheus-node-exporter
  26.  
  27. #应用这些清单
  28. kubectl apply -f ./

#应用完成后,查看Pod

  

  1. #接着进入Prometheus的清单目录
  2. cd prometheus
  3.  
  4. #prometheus-deploy.yaml 它需要的镜像文件可从hub.docker.com中下载,若网速慢的话。
  5.  
  6. #prometheus-rbac.yaml
  7. apiVersion: rbac.authorization.k8s.io/v1beta1
  8. kind: ClusterRole
  9. metadata:
  10. name: prometheus
  11. rules:
  12. - apiGroups: [""]
  13. resources:
  14. - nodes
  15. - nodes/proxy
  16. - services
  17. - endpoints
  18. - pods
  19. verbs: ["get", "list", "watch"]
  20. - apiGroups:
  21. - extensions
  22. resources:
  23. - ingresses
  24. verbs: ["get", "list", "watch"]
  25. - nonResourceURLs: ["/metrics"]
  26. verbs: ["get"]
  27.  
  28. #prometheus-deploy.yaml
  29. resources:
  30. #这里做了一个资源使用限制,需要确认你每个节点上要能满足2G的可用内存的需求,若你的Node上不能满足这个limits,就将这部分删除,然后做测试。
  31. limits:
  32. memory: 2Gi
  33.  
  34. #接着开始应用这些清单:
  35. kubectl apply -f ./

#应用完成后查看:

  kubectl  get  all  -n  prom

  1. #现在来部署,让K8s能获取Prometheus的监控数据
  2. cd kube-state-metrics
  3. #此清单中的镜像若不能从google仓库中获取,可到hub.docker.com中搜索镜像名,下载其他人做的测试
  4.  
  5. #K8s需要通过kube-state-metrics这个组件来进行格式转化,实现将Prometheus的监控数据转换为K8s API Server能识别的格式。
  6. #但是kube-state-metrics转化后,还是不能直接被K8s所使用,它还需要借助k8s-prometheus-adpater来将kube-state-metrics聚合到k8s的API Server里面,这样才能通过K8s API Server来访问这些资源数据。

  7. #应用kube-state-metrics的清单文件
  8.   kubectl apply -f ./
  1. #应用完成后,再次验证

  

  1. #以上创建好以后,可先到k8s-prometheus-adapter的开发者github上下载最新的k8s-prometheus-adapter的清单文件
  2.   https://github.com/DirectXMan12/k8s-prometheus-adapter/tree/master/deploy/manifests

  3. #注意:
    # !!!!!!!!!
    # 使用上面新版本的k8s-prometheus-adapter的话,并且是和马哥版的metrics-
    server结合使用,需要修改清单文件中的名称空间为prom
    # !!!!!!!!!!!!!!!

  4. # 但下面这个文件要特别注意:
  5. custom-metrics-apiserver-auth-reader-role-binding.yaml
  6. piVersion: rbac.authorization.k8s.io/v1
  7. kind: RoleBinding
  8. metadata:
  9. name: custom-metrics-auth-reader
  10. namespace: kube-system #这个custom-metrics-auth-reader必须创建在kube-system名称空间中,因为它要绑到这个名称空间中的Role上
  11. roleRef:
  12. apiGroup: rbac.authorization.k8s.io
  13. kind: Role #此角色是用于外部APIServer认证读的角色
  14. name: extension-apiserver-authentication-reader
  15. subjects:
  16. - kind: ServiceAccount
  17. name: custom-metrics-apiserver #这是我们自己创建的SA账号
  18. namespace: prom #这些需要注意:要修改为prom

  19. #以上清单文件下载完成后,需要先修改这些清单文件中的namespace为prom,因为我们要部署的Prometheus都在prom这个名称空间中.
  20. 之后就可以正常直接应用了
  21.   kubectl apply -f ./

# 应用完成后,需要检查
  kubectl get all -n prom #查看所有Pod都已经正常运行后。。

# 查看api-versions中是否已经包含了 custom.metrics.k8s.io/v1beta1, 若包含,则说明部署成功
  kubectl api-versions

# 测试获取custom.metrics.k8s.io/v1beta1的监控数据
  curl   http://localhost:8080/custom.metrics.k8s.io/v1beta1/

  1. 下面测试将Grafana部署起来,并且让GrafanaPrometheus中获取数据
  2.  
  3. #部署Grafana,这里部署方法和上面部署HeapSter一样,只是这里仅部署Grafana
  4. wget https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/grafana.yaml
  5.  
  6. #此清单若需要修改apiVersion,也要向上面修改一样,配置其seletor。
  7.  
  8. #另外还有需要注意:
  9. volumeMounts:
  10. - mountPath: /etc/ssl/certs #它会自动挂载Node上的/etc/ssl/certs目录到容器中,并自动生成证书,因为它使用的HTTPS.
  11. name: ca-certificates
  12. readOnly: true
  13.  
  14. #Grafana启动时,会去连接数据源,默认是InfluxDB,这个配置是通过环境变量来传入的
  15. env:
  16. #- name: INFLUXDB_HOST
  17. # value: monitoring-influxdb
  18. #这里可看到,它将InfluxDB的Service名传递给Grafana了。
  19. #需要特别注意:因为这里要将Grafana的数据源指定为Prometheus,所以这里需要将InfluxDB做为数据源给关闭,若你知道如何定义prometheus的配置,
  20. #也可直接修改,不修改也可以,那就直接注释掉,然后部署完成后,登录Grafana后,在修改它的数据源获取地址。
  21. - name: GF_SERVER_HTTP_PORT
  22. value: ""
  23. #默认Grafara在Pod内启动时,监听的端口也是通过环境变量传入的,默认是3000端口.
  24.  
  25. #在一个是,我们需要配置Grafana可以被外部直接访问
  26. ports:
  27. - port:
  28. targetPort:
  29. selector:
  30. k8s-app: grafana
  31. type: NodePort
  32.  
  33. #配置完成后,进行apply
  34. kubectl apply -f grafana.yaml
  35.  
  36. #然后查看service对集群外暴露的访问端口
  37. kubectl get svc -n prom

#随后打开浏览器,做以下修改

  

#接着,你可以查找一个,如何导入第三方做好的模板,然后,从grafana官网下载一个模板,导入就可以获取一个漂亮的监控界面了。
  #获取Prometheus的模板文件,可从这个网站获取
  https://grafana.com/grafana/dashboards?search=kubernetes

  

HPA功能:
  正如前面所说,它可根据我们所设定的规则,监控当前Pod整体使用率是否超过我们设置的规则,若超过则设置的根据比例动态增加Pod数量。
  举个简单的例子:
  假如有3个Pod,我们规定其最大使用率不能高于60%,但现在三个Pod每个CPU使用率都到达90%了,那该增加几个Pod的?
  HPA的计算方式是:
    90% × 3 = 270% , 那在除以60,就是需要增加的Pod数量, 270 / 60 = 4.5 ,也就是5个Pod

#HPA示例:
  kubectl run myapp --image=harbor.zcf.com/k8s/myapp:v1 --replicas=1 \
    --requests='cpu=50m,memory=256Mi' --limits='cpu=50m,memory=256Mi' \
    --labels='app=myapp' --expose --port=50

#修改myapp的svcPort类型为NodePort,让K8s集群外部可以访问myapp,这样方便压力测试,让Pod的CPU使用率上升,然后,查看HPA自动创建Pod.
  kubectl patch svc myapp -p '{"spec":{"type":"NodePort"}}'

  # kubectl get pods

  

  #这里目前只有一个Pod!!

  kubectl describe pod myapp-xxxx    #可查看到它当前的QoS类别为: Guranteed

#创建HPA,根据CPU利用率来自动伸缩Pod
  kubectl autoscale deployment myapp --min=1 --max=8 --cpu-percent=40

  

  1. #查看当前Pod是Service:
  2. # kubectl get svc
  3. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  4. ..................
  5. myapp NodePort 172.30.162.48 <none> :/TCP 103m
  6.  
  7. #创建成功后,就可以通过ab等压测工具来测试自动伸缩
  8. #apt-get install apache2-utils
  9. #
  10. # ab -c -n http://192.168.111.84:50113
  11.  
  12. #查看HPA自动伸缩情况
  13. # kubectl describe hpa
  14. Name: myapp
  15. Namespace: default
  16. ............................
  17. resource cpu on pods (as a percentage of request): % (38m) / %
  18. Min replicas:
  19. Max replicas:
  20. Deployment pods: current / desired #这里可看到现在已经启动6个Pod
  21.  
  22. #创建一个HPA v2版本的自动伸缩其
  23. #完整配置清单:
  24. vim hpa-pod-demo-v2.yaml
  25. apiVersion: v1
  26. kind: Service
  27. metadata:
  28. labels:
  29. app: myapp
  30. name: myapp-v2
  31. spec:
  32. clusterIP: 172.30.10.98
  33. ports:
  34. - port:
  35. protocol: TCP
  36. targetPort:
  37. type: NodePort
  38. selector:
  39. app: myapp
  40. ---
  41. apiVersion: apps/v1
  42. kind: Deployment
  43. metadata:
  44. labels:
  45. app: myapp
  46. name: myapp-v2
  47. spec:
  48. replicas:
  49. selector:
  50. matchLabels:
  51. app: myapp
  52. strategy: {}
  53. template:
  54. metadata:
  55. labels:
  56. app: myapp
  57. spec:
  58. containers:
  59. - image: harbor.zcf.com/k8s/myapp:v1
  60. name: myapp-v2
  61. ports:
  62. - containerPort:
  63. resources:
  64. limits:
  65. cpu: 50m
  66. memory: 256Mi
  67. requests:
  68. cpu: 50m
  69. memory: 256Mi
  70.  
  71. ---
  72. apiVersion: autoscaling/v2beta1
  73. kind: HorizontalPodAutoscaler
  74. metadata:
  75. name: myapp-v2
  76. spec:
  77. maxReplicas:
  78. minReplicas:
  79. scaleTargetRef:
  80. apiVersion: extensions/v1beta1
  81. kind: Deployment
  82. name: myapp
  83. metrics:
  84. - type: Resource
  85. resource:
  86. name: cpu
  87. targetAverageUtilization:
  88. - type: Resource
  89. resource:
  90. name: memory
  91. targetAverageValue: 50Mi

#压测方便和上面一样。这个配置清单中定义了CPU和内存的资源监控指标,V2是支持内存监控指标的,但V1是不支持的。

  

#若以后自己程序员开发的Pod,能通过Prometheus导出Pod的资源指标,比如:HTTP的访问量,连接数,我们就可以根据HTTP的访问量或者连接数来做自动伸缩。
 在那个Pod上的那些指标可用,是取决于你的Prometheus能够从你的Pod的应用程序中获取到什么样的指标的,但是Prometheus能获取的指标是由一定语法要求的,开发要依据  Prometheus支持的RESTful风格的接口,去输出一些指标数据,这指标记录当前系统上Web应用程序所承载的最大访问数等一些指标数据,那我们就可基于这些输出的指标数据,来完成HPA自动伸缩的扩展。

#自定义资源指标来创建HPA,实现根据Pod中输出的最大连接数来自动扩缩容Pod
#下面是一个HPA的定义,你还需要创建一个能输出http_requests这个自定义资源指标的Pod,然后才能使用下面的HPA的清单。

下面清单是使用自定义资源监控指标 http_requests 来实现自动扩缩容:
  docker pull ikubernetes/metrics-app   #可从这里获取metrics-app镜像

  1. vim hpa-http-requests.yaml
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5. labels:
  6. app: myapp
  7. name: myapp-hpa-http-requests
  8. spec:
  9. clusterIP: 172.30.10.99 #要根据实际情况修改为其集群IP
  10. ports:
  11. - port:
  12. protocol: TCP
  13. targetPort:
  14. type: NodePort #若需要集群外访问,可添加
  15. selector:
  16. app: myapp
  17. ---
  18. apiVersion: apps/v1
  19. kind: Deployment
  20. metadata:
  21. labels:
  22. app: myapp
  23. name: myapp-hpa-http-requests
  24. spec:
  25. replicas: #这里指定Pod副本数量为1
  26. selector:
  27. matchLabels:
  28. app: myapp
  29. strategy: {}
  30. template:
  31. metadata:
  32. labels:
  33. app: myapp
  34. annotations: #annotations一定要,并且要定义在容器中!!
  35. prometheus.io/scrape: "true" #这是允许Prometheus到容器中抓取监控指标数据
  36. prometheus.io/port: ""
  37. prometheus.io/path: "/metrics" #这是指定从那个URL路径中获取监控指标数据
  38. spec:
  39. containers:
  40. - image: harbor.zcf.com/k8s/metrics-app #此镜像中包含了做好的,能输出符合Prometheus监控指标格式的数据定义。
  41. name: myapp-metrics
  42. ports:
  43. - containerPort:
  44. resources:
  45. limits:
  46. cpu: 50m
  47. memory: 256Mi
  48. requests:
  49. cpu: 50m
  50. memory: 256Mi
  51.  
  52. ---
  53. apiVersion: autoscaling/v2beta1
  54. kind: HorizontalPodAutoscaler
  55. metadata:
  56. name: myapp-hpa-http-requests
  57. spec:
  58. maxReplicas:
  59. minReplicas:
  60. scaleTargetRef: #这指定要伸缩那些类型的Pod。
  61. apiVersion: extensions/v1beta1
  62. kind: Deployment #这里指定对名为 myapp-hpa-http-requests这个 Deployment控制器 下的所有Pod做自动伸缩.
  63. name: myapp-hpa-http-requests
  64. metrics:
  65. - type: Pods #设置监控指标是从那种类型的资源上获取:它支持Resource,Object,Pods ;
  66. #resource:核心指标如:cpu,内存可指定此类型,若监控的资源指标是从Pod中获取,那类型就是Pods
  67. pods:
  68. metricName: http_requests #http_requests就是自定义的监控指标,它是Prometheus中Pod中获取的。
  69. targetAverageValue: 800m #800m:是800个并发请求,因为一个并发请求,就需要一个CPU核心来处理,所以是800个豪核,就是800个并发请求。
  70.  
  71. # curl http://192.168.111.84:55066/metrics
  72. #注意:Prometheus抓取数据时,它要求获取资源指标的数据格式如下:
  73. # HELP http_requests_total The amount of requests in total #HELP:告诉Prometheus这个数据的描述信息
  74. # TYPE http_requests_total counter #TYPE: 告诉Prometheus这个数据的类型
  75. http_requests_total #告诉Prometheus这个数据的值是多少。
  76.  
  77. # HELP http_requests_per_second The amount of requests per second the latest ten seconds
  78. # TYPE http_requests_per_second gauge
  79. http_requests_per_second 0.1
  80.  
  81. # 测试方法:
  82. . 先在一个终端上执行:
  83. for i in `seq `; do curl http://K8S_CLUSTER_NODE_IP:SERVER_NODE_PORT/ ; done
  84.  
  85. . 查看hpa的状态
  86. # kubectl describe hpa
  87. Name: myapp-hpa-http-requests
  88. Namespace: default
  89. .........
  90. Reference: Deployment/myapp-hpa-http-requests
  91. Metrics: ( current / target )
  92. "http_requests" on pods: 4366m / 800m
  93. Min replicas:
  94. Max replicas:
  95. Deployment pods: current / desired
  96. ........................
  97. Events:
  98. Type Reason Age From Message
  99. ---- ------ ---- ---- -------
  100. .....................
  101. Normal SuccessfulRescale 51s horizontal-pod-autoscaler New size: ; reason: pods metric http_requests above target
  102. Normal SuccessfulRescale 36s horizontal-pod-autoscaler New size: ; reason: pods metric http_requests above target
  103.  
  104. . 查看Pod
  105. # kubectl get pod
  106. NAME READY STATUS RESTARTS AGE
  107. myapp-hpa-http-requests-69c9968cdf-844lb / Running 24s
  108. myapp-hpa-http-requests-69c9968cdf-8hcjl / Running 24s
  109. myapp-hpa-http-requests-69c9968cdf-8lx9t / Running 39s
  110. myapp-hpa-http-requests-69c9968cdf-d4xdr / Running 24s
  111. myapp-hpa-http-requests-69c9968cdf-k4v6h / Running 114s
  112. myapp-hpa-http-requests-69c9968cdf-px2rl / Running 39s
  113. myapp-hpa-http-requests-69c9968cdf-t52xr / Running 39s
  114. myapp-hpa-http-requests-69c9968cdf-whjl6 / Running 24s

K8s容器资源限制的更多相关文章

  1. 超大规模商用 K8s 场景下,阿里巴巴如何动态解决容器资源的按需分配问题?

    作者 | 张晓宇(衷源)  阿里云容器平台技术专家 关注『阿里巴巴云原生』公众号,回复关键词"1010",可获取本文 PPT. 导读:资源利用率一直是很多平台管理和研发人员关心的话 ...

  2. K8s容器编排

    K8s容器编排 Kubernetes(k8s)具有完备的集群管理能力: 包括多层次的安全防护和准入机制 多租户应用支撑能力 透明的服务注册和服务发现机制 内建智能负载均衡器 强大的故障发现和自我修复能 ...

  3. k8s控制器资源(五)

    Pod pod在之前说过,pod是kubernetes集群中是最小的调度单元,pod中可以运行多个容器,而node又可以包含多个pod,关系如下图: 在对pod的用法进行说明之前,有必要先对docke ...

  4. Kubernetes 学习22 kubernetes容器资源需求资源限制及HeapSter(翻车章节)

    一.概述 1.接下来介绍在k8s上运行pod对象时我们如何去监控我们系统级的资源指标以及业务级别的资源指标.数据如何获取和监控.在此之前先介绍一下Pod对象的资源请求和资源限制.即容器的资源需求和资源 ...

  5. Kubernetes K8S之资源控制器StatefulSets详解

    Kubernetes的资源控制器StatefulSet详解与示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master CentOS7.7 2 ...

  6. 8.深入k8s:资源控制Qos和eviction及其源码分析

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com,源码版本是1.19 又是一个周末,可以愉快的坐下来静静的品味一段源码,这一篇涉及到资源的 ...

  7. Kubernetes K8S之资源控制器Job和CronJob详解

    Kubernetes的资源控制器Job和CronJob详解与示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master CentOS7.7 2 ...

  8. k8s控制器资源

    k8s控制器资源   Pod pod在之前说过,pod是kubernetes集群中是最小的调度单元,pod中可以运行多个容器,而node又可以包含多个pod,关系如下图: 在对pod的用法进行说明之前 ...

  9. k8s核心资源之Pod概念&入门使用讲解(三)

    目录 1. k8s核心资源之Pod 1.1 什么是Pod? 1.2 Pod如何管理多个容器? 1.3 Pod网络 1.4 Pod存储 1.5 Pod工作方式 1.5.1 自主式Pod 1.5.2 控制 ...

随机推荐

  1. Skywalking入门介绍,skywalking6.5.0 +mysql (windows) 搭建

    一. 介绍 1. 基本信息 SkyWalking 创建于2015年,提供分布式追踪功能.从5.x开始,项目进化为一个完成功能的Application Performance Monitoring系统. ...

  2. R与金钱游戏:均线黄金交叉1

    双11临近的我发现自己真的很穷很穷很穷(重要的问题说三遍)-- 贫穷催人上进.于是我就寻思着在空闲时间自己捣鼓一下钱生钱的游戏是怎么玩的,毕竟就算注定做韭菜也要做一根有知识有理想的韭菜. 第一个要玩的 ...

  3. lua中,两种json和table互转方法的效率比较

    lua中json和table的互转,是我们在平时开发过程中经常用到的.比如: 在用lua编写的服务器中,如果客户端发送json格式的数据,那么在lua处理业务逻辑的时候,必然需要转换成lua自己的数据 ...

  4. K8s 学习者绝对不能错过的最全知识图谱(内含 58个知识点链接)

    作者 | 平名 阿里服务端开发技术专家 导读:Kubernetes 作为云原生时代的“操作系统”,熟悉和使用它是每名用户的必备技能.本篇文章概述了容器服务 Kubernetes 的知识图谱,部分内容参 ...

  5. Linux 笔记 - 第二十二章 Nginx 配置 SSL

    一.前言 基础知识 1.1 公钥密码体制(public-key cryptography) 公钥密码体制分为三个部分,公钥.私钥.加密解密算法,它的加密解密过程如下: 加密:通过加密算法和公钥对内容( ...

  6. HTTP STATUS 400 – BAD REQUEST ,SPRINGMVC错误

    400大多为前台传的数据于后台接受数据不符合,注意Date数据类型最容易错. 然后需要调用实体类的空参构造方法,,注意创建了有参构造方法后,创建一个空参构造方法.

  7. js中this绑定方式及如何改变this指向

    this的绑定方式基本有以下几种: 隐式绑定 显式绑定 new 绑定 window 绑定 箭头函数绑定 隐式绑定 第一个也是最常见的规则称为 隐式绑定. var a = { str: 'hello', ...

  8. Gin-Go学习笔记五:Gin-Web框架 文件的操作

    文件的操作 1>     文件的创建,删除,写入内容,读取内容.(此实例使用的是text文件) 2>     Gin 并没有提供文件的创建,删除,读写这个操作的专门的接口,所以采用的是常用 ...

  9. SVG跟随父级DIV自适应

    后台返回过来的是这样的SVG标签 <svg width="100%" height="100%" version="1.1" xmln ...

  10. vue-router 在新窗口打开页面的功能

    项目中,需要点击链接后再新窗口打开页面,大家知道vue是单页面应用开发框架,那么也不是不可以实现这个功能 很简单,详情看下面 1.<router-link>标签实现新窗口打开 <ro ...