美文网首页k8s程序员Kuberne...
③k8s部署应用的流程与管理

③k8s部署应用的流程与管理

作者: Linux丶晨星 | 来源:发表于2020-07-24 18:22 被阅读0次

    适用于大部分项目(大同小异)


    一、 项目迁移到K8S平台是怎样的流程

    image
    • 要以镜像作为交付对象,不再以jar包、war包形式
    • 在docker可以直接上传镜像运行容器,在k8s需要编写yaml文件,通过控制器去管理镜像
    • 部署完成后要将容器或pod暴露出去
    • 例如前后端分离在k8s中是两个镜像,分别需要让外部用户能够访问到此pod或容器
    • 对应用pod进行一下日志的采集和监控,方便做数据分析、历史资源利用率检查和告警等

    镜像的分类

    • 基础镜像:Docker Hub仓库上,CentOS,Ubuntu、Alpine

    • 运行镜像:JDK、PHP、Java

    • 项目镜像:将项目代码镜像打包到运行环境镜像中

    二、 示例:在k8s中部署Java应用

    学习案例使用为一位k8s大牛的案例

    tomcat镜像包链接: https://pan.baidu.com/s/1v4EHVaSs2D38NhP0W5JE8A 提取码: n5qc

    [root@k8s-master ~]# unzip tomcat-java-demo-master.zip
    [root@k8s-master ~]# ll tomcat-java-demo-master
    total 24
    drwxr-xr-x 2 root root    34 Aug  5  2019 db    #sql测试文件
    -rw-r--r-- 1 root root   148 Aug  5  2019 Dockerfile    #构建打包项目镜像
    -rw-r--r-- 1 root root 11357 Aug  5  2019 LICENSE
    -rw-r--r-- 1 root root  1930 Aug  5  2019 pom.xml   #java编译环境
    -rw-r--r-- 1 root root   270 Aug  5  2019 README.md
    drwxr-xr-x 3 root root    18 Aug  5  2019 src       #源码目录
    

    提前准备一台数据库测试环境

    # IP 192.168.0.40
    [root@k8s-mariadb ~]# mysql --version
    mysql  Ver 15.1 Distrib 5.5.65-MariaDB, for Linux (x86_64) using readline 5.1
    

    将sql测试数据导入到数据库中

    scp -rp db/tables_ly_tomcat.sql root@192.168.0.40:~
    
    #进入到数据库导入数据
    MariaDB [test]> use test;
    MariaDB [test]> source /root/tables_ly_tomcat.sql;
    MariaDB [test]> show tables;
    +----------------+
    | Tables_in_test |
    +----------------+
    | user           |
    +----------------+
    1 row in set (0.00 sec)
    
    #授权
    MariaDB [test]> grant all on test.* to 'test'@'%' identified by '123456';
    

    在其他节点上测试数据库是否可以连接

    [root@k8s-node02 ~]# mysql -h192.168.0.40 -utest -p
    Enter password: 
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 9
    Server version: 5.5.65-MariaDB MariaDB Server
    
    Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    MariaDB [(none)]> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | test               |
    +--------------------+
    2 rows in set (0.00 sec)
    

    1. 下载java编译环境进行构建

    yum install openjdk-1.8.0-java maven -y
    mvn clean package -Dmaven.test.skup=true
    
    #生成target目录,和下面的war包
    [root@k8s-master tomcat-java-demo-master]# ls target/
    classes            ly-simple-tomcat-0.0.1-SNAPSHOT      maven-archiver
    generated-sources  ly-simple-tomcat-0.0.1-SNAPSHOT.war  maven-status
    

    2. 修改连接数据库的配置

    #mysql地址修改为提前准备的mysql测试环境IP,test用户和密码
    [root@k8s-master tomcat-java-demo-master]# vim src/main/resources/application.yml
    url: jdbc:mysql://192.168.0.40:3306/test?characterEncoding=utf-8
    username: test
    password: 123456
    

    3. 重新构建

    mvn clean package -Dmaven.test.skup=true
    

    4. 查看Dcokerfile文件

    [root@k8s-master tomcat-java-demo-master]# cat Dockerfile 
    FROM 245684979/tomcat #镜像
    LABEL maintainer www.ctnrs.com  #标签作者
    RUN rm -rf /usr/local/tomcat/webapps/*  #删除tomcat镜像中默认程序
    ADD target/*.war /usr/local/tomcat/webapps/ROOT.war  #添加war包,当前目录下生成的
    

    5. 使用doclerfile构建镜像

    # Dockerfile文件名格式可以识别所以不需要-f指定
    [root@k8s-master tomcat-java-demo-master]# docker build -t 245684979/java-demo .
    ...
    Successfully tagged 245684979/java-demo:latest
    

    6. 推送到镜像仓库

    #推送到DockerHub,需要登录账号
    docker push 245684979/java-demo:latest
    
    #建议搭建一个私有镜像仓库
    

    7. 其他node节点可以提前pull镜像

    docker pull  245684979/tomcat
    

    8. master节点生成yaml文件

    kubectl create deployment java-demo --image=245684979/java-demo --dry-run=client -o yaml >deploy.yaml
    
    #进行修改,副本数改为3,删除一些多余项
    [root@k8s-master ~]# cat deploy.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: java-demo
      name: java-demo
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: java-demo
      template:
        metadata:
          labels:
            app: java-demo
        spec:
          containers:
          - image: 245684979/java-demo
            name: java-demo
    

    9. 创建pod

    [root@k8s-master ~]# kubectl apply -f deploy.yaml 
    deployment.apps/java-demo created
    
    [root@k8s-master ~]# kubectl get pods
    NAME                        READY   STATUS    RESTARTS   AGE
    java-demo-b57dd87fb-5rlsl   1/1     Running   0          65s
    java-demo-b57dd87fb-hr4ch   1/1     Running   0          65s
    java-demo-b57dd87fb-m5dzg   1/1     Running   0          65s
    

    10. 检查状态

    #现在只是pod的状态成功了,容器内是否成功可以通过日志查看某个pod
    [root@k8s-master ~]# kubectl logs java-demo-b57dd87fb-5rlsl
    ...
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.0.1.RELEASE)
    ...
    21-Jul-2020 10:55:51.099 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 26598 ms
    

    11. 暴露应用端口

    # --port:集群内部service之间访问端口
    # --target-port:pod内应用程序访问端口
    # --type=NodePort:生成集群外部访问端口
    [root@k8s-master ~]#  kubectl expose deployment java-demo --port=80 --target-port=8080 --type=NodePort -o yaml --dry-run >svc.yaml
    
    [root@k8s-master ~]# cat svc.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: java-demo
      name: java-demo
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: java-demo
      type: NodePort
      
    #构建svc
    [root@k8s-master ~]# kubectl apply -f svc.yaml 
    service/java-demo created
    
    #查看
    [root@k8s-master ~]# kubectl get svc
    NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
    service/java-demo    NodePort    10.10.17.207   <none>        80:32433/TCP   72s
    service/kubernetes   ClusterIP   10.10.0.1      <none>        443/TCP        3d17h
    

    12. 进行访问暴露端口成功的应用

    http://192.168.0.10:32433/
    
    image

    13. 进行添加数据

    image
    image

    14. 在测试数据库中查看数据

    MariaDB [test]> select * from user;
    +----+-----------+-----+------+
    | id | name      | age | sex  |
    +----+-----------+-----+------+
    |  1 | 高圆圆    |  18 | F    |
    |  2 | 蔡徐坤    |  20 | M    |
    |  3 | 刘芳      |  16 | F    |
    |  4 | 刘芳      |  18 | F    |
    |  5 | 貂蝉      | 800 | F    |
    |  6 | 范冰冰    |  40 | F    |
    |  7 | 金星      |  45 | Y    |
    +----+-----------+-----+------+
    7 rows in set (0.00 sec)
    

    三、 Pod对象的理解

    1. Pod的基本概念:one:

    • 最小的部署单元

    • 一组容器的集合

    • 一个Pod中的容器共享网络命名空间和存储

    • Pod是短暂的

    2. Pod存在的意义:two:

    • Pod为亲密性应用而存在

    • 亲密性应用场景:

      • 两个应用直接发送文件交互
      • 两个应用需要通过127.0.0.1或者socket通信
      • 两个应用需要发生频发的调用

    3. Pod实现机制:three:

    • 共享网络
      • 多个容器在一个网络命名空间里
    • 共享存储
      • 数据卷中存储临时数据、日志、业务数据
      • emtmyDir,多个容器之间数据共享

    测试Pod共享存储的机制

    #编写yaml文件,一个读一个写,都挂载到/data目录下
    [root@k8s-master ~]# cat emtydir.yaml
    apiVersion: v1  
    kind: Pod  
    metadata:  
      name: my-pod  
    spec:  
      containers:
      - name: write  
        image: centos
        command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]  
        volumeMounts:
          - name: data  
            mountPath: /data
            
      - name: read  
        image: centos
        command: ["bash","-c","tail -f /data/hello"]  
        volumeMounts:
          - name: data 
            mountPath: /data
    
      volumes:
      - name: data  
        emptyDir: {}
        
    #进行构建
    [root@k8s-master ~]# kubectl apply -f emtydir.yaml
    
    #访问Pod查看write写容器
    [root@k8s-master ~]# kubectl exec -it my-pod -c write bash
    [root@my-pod /ls /data/
    hello
    [root@my-pod /]# tail -f /data/hello 
    59
    60
    61
    62
    63
    
    #访问Pod查看read读容器
    [root@k8s-master ~]# kubectl logs my-pod -c read
    1
    2
    3
    ...
    97
    98
    99
    100
    

    4. Pod容器分类与设计模式:four:

    • Infrastructure Container:基础容器
      维护整个Pod网络空间
    • InitContainers:初始化容器
      先于业务容器开始执行
    • Containers:业务容器
      并行启动

    Pod Template常用功能字段解析

    • 变量
    • 拉取镜像
    • 资源限制
    • 健康检查

    5. 健康检查

    探针的种类
    livenessProbe:健康状态检查,周期性检查服务是否存活,检查结果失败,将重启容器
    readinessProbe:可用性检查,周期性检查服务是否可用,不可用将从service的endpoints中移除

    探针的检测方法

    • exec:执行一段命令
    • httpGet:检测某个 http 请求的返回状态码
    • tcpSocket:测试某个端口是否能够连接

    四、 Deployment 控制器(无状态应用)

    Deployment同样也是Kubernetes系统的一个核心概念,主要职责和RC一样的都是保证Pod的数量和健康,二者大部分功能都是完全一致的,我们可以看成是一个升级版的RC控制器。

    Deployment具备的新特性

    • RC的全部功能:Deployment具备上面描述的RC的全部功能
    • 事件和状态查看:可以查看Deployment的升级详细进度和状态
    • 回滚:当升级Pod的时候如果出现问题,可以使用回滚操作回滚到之前的任一版本
    • 版本记录:每一次对Deployment的操作,都能够保存下来,这也是保证可以回滚到任一版本的基础
    • 暂停和启动:对于每一次升级都能够随时暂停和启动

    Deployment作为新一代的RC,不仅在功能上更为丰富了,同时我们也说过现在官方也都是推荐使用Deployment来管理Pod的,比如一些官方组件kube-dnskube-proxy也都是使用的Deployment来管理的,所以最好使用Deployment来管理Pod

    image

    可以看出一个Deployment拥有多个Replica Set,而一个Replica Set拥有一个或多个Pod。一个Deployment控制多个rs主要是为了支持回滚机制,每当Deployment操作时,Kubernetes会重新生成一个Replica Set并保留,以后有需要的话就可以回滚至之前的状态。

    Replica Set的作用就是副本数记录和历史版本记录

    1. Pod 与 controllers 的关系

    controllers:在集群上管理和运行容器的对象
    通过label-selector相关联
    Pod通过控制器实现应用的运维,如伸缩,滚动升级等

    2. Deployment功能与应用场景

    部署"无状态应用"
    管理Pod和ReplicaSet
    具有上线部署、副本设定、滚动升级、回滚等功能
    提供声明式更新,例如只更新一个新的 image

    应用场景:Web服务,微服务

    3. YAML字段解析

    image

    4. 使用Deployment部署一个Java应用

    4.1 创建

    生成yaml文件

    kubectl create deployment web --image=245684979/java-demo --dry-run -o yaml >web.yaml
    

    修改yaml文件

    #使用准备好的docker hub上的java镜像:245684979/java-demo
    #修改为3个副本
    [root@k8s-master ~]# cat web.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: web
      name: web
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: web
      template:
        metadata:
          labels:
            app: web
        spec:
          containers:
          - image: 245684979/java-demo
            name: java
    

    构建yaml

    [root@k8s-master ~]# kubectl apply -f web.yaml
    deployment.apps/web created
    [root@k8s-master ~]# kubectl get pod
    NAME                        READY   STATUS    RESTARTS   AGE
    java-demo-b57dd87fb-5rlsl   1/1     Running   1          23h
    java-demo-b57dd87fb-cp2tq   1/1     Running   1          23h
    java-demo-b57dd87fb-shr4k   1/1     Running   1          23h
    web-5ccd9ffd6-694m2         1/1     Running   0          51s
    web-5ccd9ffd6-llq9z         1/1     Running   0          51s
    web-5ccd9ffd6-tlh9q         1/1     Running   0          51s
    

    4.2 发布

    通过service暴露端口

    [root@k8s-master ~]# kubectl expose deployment web --port=80 --target-port=8080 --type=NodePort 
    service/web exposed
    
    #如果要生成yaml文件后面添加 --dry-run=client -o yaml >web_service.yaml
    

    查看service

    [root@k8s-master ~]# kubectl get svc
    NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
    java-demo    NodePort    10.10.17.207   <none>        80:32433/TCP   24h
    kubernetes   ClusterIP   10.10.0.1      <none>        443/TCP        4d17h
    web          NodePort    10.10.9.46     <none>        80:32683/TCP   2m36s
    

    进行访问

    image

    数据库的配置已经打包到镜像中了,所以之前的数据也存在

    5. 升级与回滚

    5.1 升级

    升级为nginx镜像

    #做测试修改为nginx的pod
    [root@k8s-master ~]# kubectl set image deployment web java=nginx
    deployment.apps/web image updated
    
    #默认为滚动更新,启动一台新pod,删除一台旧pod,直到全部替换更新
    

    进行访问会发现无法访问

    image

    需要修改service的端口为nginx的80

     [root@k8s-master ~]# kubectl edit service web
     ...
        targetPort: 80
    

    再次访问已经为nginx的首页了

    image

    查看升级状态

    [root@k8s-master ~]# kubectl rollout status deployment web 
    deployment "web" successfully rolled out
    

    5.2 回滚

    查看历史版本记录

    [root@k8s-master ~]# kubectl rollout history deployment web 
    deployment.apps/web 
    REVISION  CHANGE-CAUSE
    1         <none>
    2         <none>
    

    回滚到上一版本

    [root@k8s-master ~]# kubectl rollout undo deployment web 
    deployment.apps/web rolled back
    

    会发现访问网页提示无法访问了,说明回到了未修改端口的上一版本


    image
    #修改端口为8080
    [root@k8s-master ~]# kubectl edit service web
    ...
        targetPort: 8080
    
    image

    回滚到指定版本的参数

    kubectl rollout undo deployment web --to-revision=2
    

    6. 弹性伸缩 scale

    扩容和缩容一样的操作,只需要修改副本数

    #将web扩容为5个副本,会在之前的3个之上再添加2个pod
    [root@k8s-master ~]# kubectl scale deployment web --replicas=5
    deployment.apps/web scaled
    [root@k8s-master ~]# kubectl get pod
    NAME                        READY   STATUS              RESTARTS   AGE
    java-demo-b57dd87fb-5rlsl   1/1     Running             1          27h
    java-demo-b57dd87fb-cp2tq   1/1     Running             1          26h
    java-demo-b57dd87fb-shr4k   1/1     Running             1          27h
    web-64c686b49d-28zbv        0/1     ContainerCreating   0          3s
    web-64c686b49d-cb65c        0/1     ContainerCreating   0          3s
    web-64c686b49d-479qh        1/1     Running             0          7m11s
    web-64c686b49d-s95bb        1/1     Running             0          4m52s
    web-64c686b49d-vbbnx        1/1     Running             0          6m49s
    
    #缩容为3个副本
    kubectl scale deployment web --replicas=3
    
    #也可以直接去修改副本数
    kubectl edit deployment web
    

    k8s的扩容只是一个维度,需要建立在集群的每个节点资源之上。根据业务的量去扩容缩容。

    在业务高峰或者低峰的时候,可以手动的调整Pod数量来提供资源的利用率,也可以使用HPA这种资源对象,可以做到自动伸缩。

    五、 Service对象

    Pod的生命是有限的,死亡过后不会复活了。RCDeployment可以用来动态的创建和销毁Pod。尽管每个Pod都有自己的IP地址,但是如果Pod重新启动了的话那么它的IP很有可能也就变化了。这就会带来一个问题:比如我们有一些后端的Pod的集合为集群中的其他前端的Pod集合提供API服务,如果我们在前端的Pod中把所有的这些后端的Pod的地址都写死了,然后去某种方式去访问其中一个Pod的服务,这样看上去是可以正常工作的,但是如果这个Pod挂掉了,然后重新启动起来了,IP地址非常有可能就变了,这个时候前端就极大可能访问不到后端的服务了。

    遇到这样的问题该怎么解决呢?:question:

    • 比如我们在部署一个WEB服务的时候,前端一般部署一个Nginx作为服务的入口,然后Nginx后面肯定就是挂载的其他后端的各种服务,以前我们可能是去手动更改Nginx配置中的资源池upstream选项,来动态改变提供服务的数量

    • 如果要解决上面遇到的问题,可以通过服务发现的工具解决掉。当Pod被销毁或者新建过后,我们可以把这个Pod的地址注册到这个服务发现中心去就可以。但是这样的话我们的前端的Pod结合就不能直接去连接后台的Pod集合了,所以还应该连接到一个能够做服务发现的中间件上面。

    • Kubernetes集群就为我们提供了这样的一个对象 - ServiceService是一种抽象的对象,它定义了一组Pod的逻辑集合和一个用于访问它们的策略,这个概念和微服务非常类似。一个Serivce下面包含的Pod集合一般是由Label Selector(标签)来决定的。

    • 上面举的例子,假如我们后端运行了3个副本,这些副本都是可以替代的,因为前端并不关心它们使用的是哪一个后端服务。尽管由于各种原因后端的Pod集合会发送变化,但是前端的Pod却不需要知道这些变化,也不需要自己用一个列表来记录这些后端的服务,Service的这种抽象对象就可以帮我们达到这种解耦的目的。

    1. Kubernetes的三种IP

    • Node IP:Node节点的IP地址
    • Pod IP: Pod的IP地址
    • Cluster IP: ServiceIP地址

    :one:首先,Node IPKubernetes集群中节点的物理网卡doIP地址(一般为内网),所有属于这个网络的服务器之间都可以直接通信,所以Kubernetes集群外要想访问Kubernetes集群内部的某个节点或者服务,肯定得通过Node IP进行通信(这个时候一般是通过外网IP了)

    :two:然后Pod IP是每个PodIP地址,它是Docker Engine根据docker0网桥的IP地址段进行分配的。

    :three:最后Cluster IP是一个虚拟的IP,仅仅作用于Kubernetes Service这个对象,由Kubernetes自己来进行管理和分配地址,当然我们也无法ping这个地址,他没有一个真正的实体对象来响应,他只能结合Service Port来组成一个可以通信的服务。

    2. Service存在的意义

    • 防止Pod失联(服务发现)
    • 定义一组Pod的访问策略(负载均衡),service默认使用iptables来实现负载均衡。

    3. Pod与Service的关系

    • 通过Label Selector(标签)相关联
    • 通过Service实现Pod的四层负载均衡 传输层tcp,udp)
    #查看之前创建的java-demo的yaml文件
    [root@k8s-master ~]# cat deploy.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: java-demo
      name: java-demo
    spec:
      replicas: 3
      selector:     #定义了标签为java-demo
        matchLabels:
          app: java-demo
      template:
        metadata:
          labels:
            app: java-demo
        spec:
          containers:
          - image: 245684979/java-demo
            name: java-demo
    

    通过的使用kubectl apply -f deploy.yaml就可以创建一个名为java-demoService对象,具有标签app=java-demoPod上,这个Service会被系统分配一个Cluster IP,该Service还会持续的监听selector下面的Pod,会把这些Pod信息更新到一个名为java-demoendpoints对象上去,这个对象就类似于我们上面说的Pod集合。

    [root@k8s-master ~]# kubectl get endpoints
    NAME         ENDPOINTS                                                  AGE
    java-demo    10.244.58.211:8080,10.244.85.210:8080,10.244.85.211:8080   28h
    kubernetes   192.168.0.10:6443                                          4d22h
    web          10.244.58.221:8080,10.244.85.228:8080,10.244.85.232:8080   4h23m
    

    4. kube-proxy与Service的关系

    负责为 Service 提供 cluster 内部的服务发现和负载均衡

    Kubernetes中默认是使用的iptables这种模式来代理

    kube-proxy会监视Kubernetes master对 Service 对象和 Endpoints 对象的添加和移除。

    对每个 Service,它会添加上 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求。


    image

    5. Service类型

    在定义Service的时候可以指定一个自己需要的类型的Service,如果不指定的话默认是ClusterIP类型。

    可以使用的四种服务类型

    • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的服务类型。
    • NodePort:通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 ,可以从集群的外部访问一个 NodePort 服务。
    • LoadBalancer:使用公有云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。
    • ExternalName:不常用, 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。 对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。
      image

    6. 创建ClusterIP类型的Service

    之前已经创建了NodePort类型的service

    再创建一个新的service类型svc2.yaml文件来测试ClusterIP

    # --port:集群内部service之间访问端口
    # --target-port:pod内应用程序访问端口
    # --type=NodePort:生成集群外部访问端口
    
    kubectl expose deployment java-demo --port=80 --target-port=8080 --type=ClusterIP --dry-run -o yaml >svc2.yaml
    
    #删除之前的,构建新创建的
    [root@k8s-master ~]# kubectl delete -f svc.yaml
    [root@k8s-master ~]# kubectl apply -f svc2.yaml
    
    #查看svc
    [root@k8s-master ~]# kubectl get svc
    NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
    java-demo    ClusterIP   10.10.154.28   <none>        80/TCP         2m
    kubernetes   ClusterIP   10.10.0.1      <none>        443/TCP        5d
    web          NodePort    10.10.9.46     <none>        80:32683/TCP   6h36m
    
    #可以直接访问集群内部IP了
    curl 10.10.154.28
    ....
                  whatToType: "这里有很多美女,挑一个回家吧!",
                  typeSpeed: 300,
                  lifeLike: true,
                  breakLines :true
                }, function() {
                      console.log('This is tomcat callback function!');
                });
             </script>
    </body>
    </html>
    

    7. ipvs负载均衡替代iptables

    service多了以后 iptables表会影响性能

    支持多种调度算法

    生产中使用ipvs来做service的负载均衡转发

    六、 ingress 实现集群外部的服务发现

    Kubernetes 集群中的应用如何暴露给外部的用户使用呢?:question:

    • 使用 NodePortLoadBlancer 类型的Service可以实现把应用暴露给外部用户使用,除此之外,Kubernetes 还为我们提供了一个非常重要的资源对象可以用来暴露服务给外部用户,那就是ingress
    • 对于小规模的应用我们使用 NodePort 或许能够满足我们的需求,但是当你的应用越来越多的时候,你就会发现对于NodePort的管理就非常麻烦了,这个时候使用ingress 就非常方便了,可以避免管理大量的 Port。
    • Ingress为解决NodePort的痛点而生。

    1. 简介

    vivo 公司 Kubernetes 集群 Ingress 网关实践
    推荐阅读学习ingress的文章

    Ingress其实就是从 kuberenets 集群外部访问集群的一个入口,将外部的请求转发到集群内不同的 Service 上,其实就相当于 nginx、haproxy 等负载均衡代理服务器,会想到直接使用 nginx 就实现了,但是只使用 nginx 这种方式有很大缺陷,每次有新服务加入的时候怎么改 Nginx 配置?不可能去手动更改或者滚动更新前端的 Nginx 的Pod 。

    如果再加上一个服务发现的工具的话其实就可以了,Ingress 实际上就是这样实现的,只是服务发现的功能自己实现了,不需要使用第三方的服务了,然后再加上一个域名规则定义,路由信息的刷新需要一个靠 Ingress controller 来提供。

    Ingress controller 可以理解为一个监听器,通过不断地与 kube-apiserver 打交道,实时的感知后端 service、pod 的变化,当得到这些变化信息后,Ingress controller 再结合 Ingress 的配置,更新反向代理负载均衡器,达到服务发现的作用。

    现在可以供大家使用的 Ingress controller 有很多,比如 traefiknginx-controllerKubernetes Ingress Controller for KongHAProxy Ingress controller,当然你也可以自己实现一个 Ingress Controller,现在普遍用得较多的是 traefik 和 nginx-controller,traefik 的性能较 nginx-controller 差,但是配置使用要简单许多。

    2. 各种 Ingress 横向对比

    image

    2. Pod与Ingress的关系

    • 通过Service关联Pod
    • 基于域名访问
    • 通过Ingress Controller实现Pod的负载均衡
      • 支持TCP/UDP 4层和HTTP 7层

    3. Ingress Nginx的工作原理分析

    参考博客链接

    Nginx-ingressKubernetes生态中的重要成员,主要负责向外暴露服务,同时提供负载均衡等附加功能;

    nginx-ingress已经能够完成 7/4 层的代理功能;4层代理基于 ConfigMap

    1. Nginx 的 7 层反向代理模式

    image

    Nginx 对后端运行的服务(Service1、Service2)提供反向代理,在配置文件中配置了域名与后端服务 Endpoints集合的对应关系。客户端通过使用 DNS 服务或者直接配置本地的 hosts 文件,将域名都映射到 Nginx 代理服务器。当客户端访问 service1.com 时,浏览器会把包含域名的请求发送给 nginx 服务器,nginx 服务器根据传来的域名,选择对应的 Service,这里就是选择 Service 1 后端服务,然后根据一定的负载均衡策略,选择 Service1 中的某个容器接收来自客户端的请求并作出响应。过程很简单,nginx 在整个过程中仿佛是一台根据域名进行请求转发的“路由器”,这也就是7层代理的整体工作流程。

    对于 Nginx 反向代理做了什么,上面说的内容已经大概了解了。在 k8s 中,后端服务的变化是十分频繁的,单纯依靠人工来更新nginx 的配置文件几乎不可能,nginx-ingress 由此应运而生。Nginx-ingress 通过监视 k8s 的资源状态变化实现对 nginx 配置文件的自动更新

    2. nginx-ingress 工作流程分析

    image

    nginx-ingress 模块在运行时主要包括三个主体:NginxController、Store、SyncQueue。其中,Store 主要负责从 kubernetes APIServer 收集运行时信息,感知各类资源(如 ingress、service等)的变化,并及时将更新事件消息(event)写入一个环形管道;SyncQueue 协程定期扫描 syncQueue 队列,发现有任务就执行更新操作,即借助 Store 完成最新运行数据的拉取,然后根据一定的规则产生新的 nginx 配置,(有些更新必须 reload,就本地写入新配置,执行 reload),然后执行动态更新操作,即构造 POST 数据,向本地 Nginx Lua 服务模块发送 post 请求,实现配置更新;NginxController 作为中间的联系者,监听 updateChannel,一旦收到配置更新事件,就向同步队列 syncQueue 里写入一个更新请求。

    当添加一个web服务 wordpress 后,在 nginx 配置中会添加一个 server 条目,但该条目中没有具体指出后端的容器地址,而是指向了一个叫 http://upstream_balancer 的地址,这个 balancer 其实是由 Lua 动态提供路由的。既然没有实际的容器后端在配置文件中进行配置,自然地,服务中容器数量的增减变化也就不必修改 nginx 配置文件了,这就是免 reload 的关键!简单推测,Lua 模块所做的就是维持一个服务到容器的映射关系,动态地提供负载均衡路由。

    4. 部署ingress-nginx Controller

    https://github.com/kubernetes/ingress-nginx/

    下载官方yaml文件

    wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/cloud/deploy.yaml
    
    #这一步为可选项:修改为 DaemonSet 控制器,特性是在每个node节点运行一个同样的Pod
    #默认为 Deployment
    apiVersion: apps/v1
    kind: DaemonSet
    
    #修改镜像地址为国内(阿里云仅支持到0.32版)
    [root@k8s-master ingress-nginx]# vim deploy.yaml
    ...
        spec:
          dnsPolicy: ClusterFirst
          containers:
            - name: controller
              image: registry.aliyuncs.com/google_containers/nginx-ingress-controller:0.32.0
              imagePullPolicy: IfNotPresent
    

    构建ingress nginx

    kubectl apply -f deploy.yaml
    
    [root@k8s-master ingress-nginx]# kubectl get pod -n ingress-nginx  
    NAME                                        READY   STATUS      RESTARTS   AGE
    ingress-nginx-admission-create-wjnhs        0/1     Completed   0          88s
    ingress-nginx-admission-patch-rtg6c         0/1     Completed   0          88s
    ingress-nginx-controller-574f54bc47-vp2fs   1/1     Running     0          99s
    

    查看ingress的pod和版本

    [root@k8s-master ingress-nginx]# kubectl get pods -n ingress-nginx 
    NAME                                        READY   STATUS      RESTARTS   AGE
    ingress-nginx-admission-create-dqg8l        0/1     Completed   0          6m58s
    ingress-nginx-admission-patch-tj2js         0/1     Completed   0          6m58s
    ingress-nginx-controller-574f54bc47-qzjmv   1/1     Running     0          7m8s
    
    [root@k8s-master ingress-nginx]# kubectl exec -it -n ingress-nginx ingress-nginx-controller-574f54bc47-qzjmv -- /nginx-ingress-controller --version
    -------------------------------------------------------------------------------
    NGINX Ingress controller
      Release:       0.32.0
      Build:         git-446845114
      Repository:    https://github.com/kubernetes/ingress-nginx
      nginx version: nginx/1.17.10
    
    -------------------------------------------------------------------------------
    

    5. 创建ingress规则

    [root@k8s-master ingress-nginx]# cat ingress.yaml
    apiVersion: extensions/v1beta1  
    kind: Ingress
    metadata:
      name: web  
    spec:
      rules:
      - host: blog.girl.com 
        http:
          paths:
          - backend:  
              serviceName: web  
              servicePort: 80
    
    #查看当前service,这里使用web的的80端口
    [root@k8s-master ingress-nginx]# kubectl get svc
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    java-demo    NodePort    10.10.206.186   <none>        80:31985/TCP   23h
    kubernetes   ClusterIP   10.10.0.1       <none>        443/TCP        5d23h
    web          NodePort    10.10.9.46      <none>        80:32683/TCP   30h
    
    #构建ingress
    [root@k8s-master ingress-nginx]# kubectl apply -f ingress.yaml 
    ingress.extensions/web created
    [root@k8s-master ingress-nginx]# kubectl get ingress
    NAME   CLASS    HOSTS           ADDRESS   PORTS   AGE
    web    <none>   blog.girl.com             80      11s
    

    在本地配置hosts解析

    image

    在本地进行ping是否畅通

    image

    浏览器使用域名访问

    image

    如果想不使用端口访问需要在web的pod中添加hostPort端口,因为现在是NodePort端口

    6. 示例Nginx服务负载均衡测试

    #创建nginx的pod
    [root@k8s-master pod]# cat nginx.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: nginx
      name: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
            
    [root@k8s-master pod]# kubectl apply -f nginx.yaml
    [root@k8s-master pod]# kubectl get pod 
    NAME                        READY   STATUS    RESTARTS   AGE
    nginx-f89759699-5bn67       1/1     Running   0          8m
    nginx-f89759699-h9jqt       1/1     Running   0          7m
    nginx-f89759699-m2kgt       1/1     Running   0          7m
    
    #创建service
    [root@k8s-master service]# cat svc_nginx.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: nginx
      name: nginx
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: nginx
      type: NodePort
    
    [root@k8s-master pod]# kubectl apply -f svc_nginx.yaml 
    
    #创建ingress
    [root@k8s-master ingress-nginx]# cat ingress_nginx.yaml 
    apiVersion: extensions/v1beta1  
    kind: Ingress
    metadata:
      name: nginx
    spec:
      rules:
      - host: www.nginx.com 
        http:
          paths:
          - backend:  
              serviceName: nginx
              servicePort: 80
    
    [root@k8s-master pod]# kubectl apply -f ingress_nginx.yaml 
    
    [root@k8s-master ingress-nginx]# kubectl get svc,ingress
    NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/nginx        NodePort    10.10.121.138   <none>        80:32645/TCP   8m
    
    NAME                       CLASS    HOSTS           ADDRESS   PORTS   AGE
    ingress.extensions/nginx   <none>   www.nginx.com             80       3m
    
    #修改Pod中的三台容器的首页index.html文件
    [root@k8s-master ingress-nginx]# kubectl exec -it nginx-f89759699-5bn67 bash
    root@nginx-f89759699-5bn67:/# echo nginx-f89759699-5bn67  >/usr/share/nginx/html/index.html
    
    [root@k8s-master ingress-nginx]# kubectl exec -it nginx-f89759699-h9jqt /bin/bash
    root@nginx-f89759699-h9jqt:/# echo nginx-f89759699-h9jqt >/usr/share/nginx/html/index.htm
    
    [root@k8s-master ingress-nginx]# kubectl exec -it nginx-f89759699-m2kgt /bin/bash
    root@nginx-f89759699-m2kgt:/# echo nginx-f89759699-m2kgt >/usr/share/nginx/html/index.html
    

    添加本地hosts解析

    image

    浏览器访问并刷新页面查看负载均衡的效果

    image image
    image

    七、Helm包管理工具

    官网: https://helm.sh/

    1. Helm作用与概念

    Helm是个啥?

    Helm就相当于kubernetes环境下的yum包管理工具。包管理器类似于我们在 Ubuntu 中使用的apt、Centos中使用的yum 或者Python中的 pip 一样,能快速查找、下载和安装软件包。Helm 由客户端组件 helm 和服务端组件 Tiller 组成, 能够将一组K8S资源打包统一管理, 是查找、共享和使用为Kubernetes构建的软件的最佳方式。

    Helm的用途

    做为 Kubernetes 的一个包管理工具,Helm具有如下功能:

    • 创建新的 chart
    • chart 打包成 tgz 格式
    • 上传 chart 到 chart 仓库或从仓库中下载 chart
    • Kubernetes集群中安装或卸载 chart
    • 管理用Helm安装的 chart 的发布周期

    Helm相关组件及概念

    Helm 包含两个组件,分别是 helm 客户端 和 Tiller 服务器:

    • helm 是一个命令行工具,用于本地开发及管理chart,chart仓库管理等
    • Tiller 是 Helm 的服务端。在V3版本被弃用。Tiller 负责接收 Helm 的请求,与 k8s 的 apiserver 交互,根据chart 来生成一个 release 并管理 release
    • chart Helm的打包格式叫做chart,所谓chart就是一系列 yaml 文件, 它描述了一组相关的 k8s 集群资源
    • release 使用 helm install 命令在 Kubernetes 集群中部署的 Chart 称为 Release
    • Repoistory Helm chart 的仓库,Helm 客户端通过 HTTP 协议来访问存储库中 chart 的索引文件和压缩包

    2. Helm的v3和v2版本变化

    Helm3是CLI工具的最新主要版本。Helm 3基于Helm 2的成功,不断满足不断发展的生态系统的需求。Helm 3的内部实现已从Helm 2发生了很大变化。

    https://github.com/helm/helm/releases/tag/

    • 架构上的改变
    • 最明显的变化删除了 Tiller
    • Helm直接通过kubeconfig连接apiserver
    • release名称可以在不同命名空间重用
    • chart支持放到doceker镜像仓库

    3. Helm安装

    1. 下载Helm包

    https://get.helm.sh/helm-v3.2.4-linux-amd64.tar.gz

    [root@k8s-master tools]# wget https://get.helm.sh/helm-v3.2.4-linux-amd64.tar.gz
    [root@k8s-master tools]# tar xf helm-v3.2.4-linux-amd64.tar.gz
    [root@k8s-master tools]# ls linux-amd64/
    helm  LICENSE  README.md
    [root@k8s-master tools]# mv linux-amd64/helm /usr/bin/
    

    2. 配置Helm国内镜像源

    阿里云的源已经不更新了,这里使用微软的国内源 http://mirror.azure.cn/kubernetes/charts

    [root@k8s-master ~]# helm repo add stable http://mirror.azure.cn/kubernetes/charts
    "stable" has been added to your repositories
    
    [root@k8s-master ~]# helm repo list
    NAME    URL                                     
    stable  http://mirror.azure.cn/kubernetes/charts
    

    3. 设置 Helm 命令自动补齐

    source <(helm completion bash)
    

    4. Helm的测试使用

    1. 搜索一个weave的包

    weave是k8s的一个ui界面

    [root@k8s-master ~]# helm search repo weave
    NAME                CHART VERSION   APP VERSION DESCRIPTION                                       
    stable/weave-cloud  0.3.7           1.4.0       Weave Cloud is a add-on to Kubernetes which pro...
    stable/weave-scope  1.1.10          1.12.0      A Helm chart for the Weave Scope cluster visual...
    

    2. 下载包

    [root@k8s-master ~]# helm install ui stable/weave-scope 
    NAME: ui
    LAST DEPLOYED: Mon Jul 27 10:48:59 2020
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    NOTES:
    You should now be able to access the Scope frontend in your web browser, by
    using kubectl port-forward:
    
    kubectl -n default port-forward $(kubectl -n default get endpoints \
    ui-weave-scope -o jsonpath='{.subsets[0].addresses[0].targetRef.name}') 8080:4040
    
    then browsing to http://localhost:8080/.
    For more details on using Weave Scope, see the Weave Scope documentation:
    
    https://www.weave.works/docs/scope/latest/introducing/
    

    3. 查看安装好的release、Pod、Service

    [root@k8s-master ~]# helm list 
    NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART               APP VERSION
    ui      default     1           2020-07-27 10:48:59.644952211 +0800 CST deployed    weave-scope-1.1.10  1.12.0     
    
    [root@k8s-master ~]# kubectl get pod
    NAME                                            READY   STATUS    RESTARTS   AGE
    weave-scope-agent-ui-khzbl                      1/1     Running   0          4m25s
    weave-scope-agent-ui-x9kgm                      1/1     Running   0          4m25s
    weave-scope-cluster-agent-ui-7498b8d4f4-w7x94   1/1     Running   0          4m25s
    weave-scope-frontend-ui-649c7dcd5d-rl2m4        1/1     Running   0          4m25s
    
    [root@k8s-master ~]# kubectl get svc
    NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    ui-weave-scope   ClusterIP   10.10.97.176    <none>        80/TCP         6m12s
    

    4. 将service修改为NodePort暴露给外部

    #将ClusterIP修改为NodePort
    [root@k8s-master ~]# kubectl edit service ui-weave-scope
    ...
      sessionAffinity: None
      type: NodePort
      
    [root@k8s-master ~]# kubectl get svc
    NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    ui-weave-scope   NodePort    10.10.97.176    <none>        80:32328/TCP   14m
    

    5. 访问

    http://192.168.0.10:32328


    image

    可以直接登录控制台


    image

    5. Helm的模板创建

    1. 手动创建一个 Chart

    其中最核心的是 templates 这个文件夹,里面其实就是 K8s 资源描述yaml文件的模版。模版里面的内容可以通过 values.yaml 里面的内容去渲染,同时也可以在使用 helm install --set key=value xxx 部署的时候去覆盖 values.yaml 里面的默认值。

    [root@k8s-master helm]# helm create mychart
    Creating mychart
    [root@k8s-master helm]# tree mychart/
    mychart/
    ├── charts
    ├── Chart.yaml
    ├── templatesll
    │   ├── deployment.yaml
    │   ├── _helpers.tpl
    │   ├── hpa.yaml
    │   ├── ingress.yaml
    │   ├── NOTES.txt
    │   ├── serviceaccount.yaml
    │   ├── service.yaml
    │   └── tests
    │       └── test-connection.yaml
    └── values.yaml
    
    3 directories, 10 files
    #先将默认生成的文件删除掉
    [root@k8s-master helm]# cd mychart/templates/
    [root@k8s-master templates]# rm -rf *
    

    2. 将之前创建的nginx的yaml文件复制进来

    cp /root/service/svc_nginx.yaml /root/deployment/nginx.yaml ./
    mv nginx.yaml deployment.yaml
    [root@k8s-master templates]# ls
    deployment.yaml  svc_nginx.yaml
    

    3. 进行安装nginx模板

    如果有之前创建相同名字的资源,需要删除掉,否则会报错

    [root@k8s-master ~]# helm install nginx helm/mychart/
    NAME: nginx
    LAST DEPLOYED: Mon Jul 27 14:06:43 2020
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    
    [root@k8s-master ~]# kubectl get pod
    NAME                                            READY   STATUS    RESTARTS   AGE
    nginx-f89759699-f2gg5                           1/1     Running   0          45s
    nginx-f89759699-fqrpx                           1/1     Running   0          45s
    nginx-f89759699-kmrlg                           1/1     Running   0          45s
    
    [root@k8s-master ~]# kubectl get svc
    NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    ...
    nginx            NodePort    10.10.182.160   <none>        80:32580/TCP   9s
    ui-weave-scope   NodePort    10.10.97.176    <none>        80:32328/TCP   3h17m
    

    4. 查看已经创建的模板

    [root@k8s-master ~]# helm list
    NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART               APP VERSION
    nginx   default     1           2020-07-27 14:06:43.23384726 +0800 CST  deployed    mychart-0.1.0       1.16.0     
    ui      default     1           2020-07-27 10:48:59.644952211 +0800 CST deployed    weave-scope-1.1.10  1.12.0 
    

    5. helm模板的升级

    #如果yaml文件中有修改,修改后需要执行upgrade
    
    [root@k8s-master ~]# helm upgrade nginx helm/mychart/
    Release "nginx" has been upgraded. Happy Helming!
    NAME: nginx
    LAST DEPLOYED: Mon Jul 27 14:14:42 2020
    NAMESPACE: default
    STATUS: deployed
    REVISION: 2
    TEST SUITE: None
    

    6. Helm Chart开发与模板使用

    一套yaml文件部署多个应用时,yaml文件需要修改的位置

    • 资源名称
    • 镜像
    • 标签
    • 副本数
    • 端口

    1. 动态的渲染模板

    [root@k8s-master mychart]# pwd
    /root/helm/mychart
    
    #删除默认内容,添加下面的基础信息用来测试
    [root@k8s-master mychart]# cat values.yaml 
    replicas: 1
    
    image: 245684979/java-demo
    tag: latest
    
    label: java-demo
    
    port: 8080
    

    2. 修改nginx模板的yaml文件

    [root@k8s-master mychart]# cat templates/deployment.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: {{ .Release.Name }}-dp  #-dp 标识符
    spec:
      replicas: {{ .Values.replicas }}
      selector:
        matchLabels:
          app: {{ .Values.label }}
      template:
        metadata:
          labels:
            app: {{ .Values.label }}
        spec:
          containers:
          - image: {{ .Values.image }}:{{ .Values.tag }}
            name: nginx
    
    ###
    [root@k8s-master ~]# cat helm/mychart/templates/svc_nginx.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: {{ .Release.Name }}-svc  #标识符
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: {{ .Values.port }}
      selector:
        app: {{ .Values.label }}
      type: NodePort
    

    3. 将渲染变量模板应用到yaml中

    输出一下变量渲染生效后的输出结果

    # --dry-run: 不执行查看渲染结果,如果不加此参数则会创建
    
    [root@k8s-master ~]# helm install --dry-run nginx helm/mychart/
    NAME: nginx
    LAST DEPLOYED: Mon Jul 27 14:52:55 2020
    NAMESPACE: default
    STATUS: pending-install
    REVISION: 1
    TEST SUITE: None
    HOOKS:
    MANIFEST:
    ---
    # Source: mychart/templates/svc_nginx.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-svc
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: java-demo
      type: NodePort
    ---
    # Source: mychart/templates/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-dp
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: java-demo
      template:
        metadata:
          labels:
            app: java-demo
        spec:
          containers:
          - image: 245684979/java-demo:latest
            name: nginx
    

    执行此模板

    [root@k8s-master ~]# helm install java-demo helm/mychart/
    NAME: java-demo
    LAST DEPLOYED: Mon Jul 27 14:56:53 2020
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    

    查看生成的pod和service

    [root@k8s-master ~]# kubectl get pod
    NAME                                            READY   STATUS    RESTARTS   AGE
    ...
    java-demo-dp-859745b69c-2r78f                   1/1     Running   0          101s
    
    [root@k8s-master ~]# kubectl get svc
    NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    java-demo-svc    NodePort    10.10.217.33    <none>        80:31618/TCP   2m3s
    ...
    

    也可以尝试访问一下是否成功

    http://192.168.0.10:31618


    image

    4. 更新chart包

    [root@k8s-master ~]# helm upgrade java-demo --set replicas=3 helm/mychart/
    Release "java-demo" has been upgraded. Happy Helming!
    NAME: java-demo
    LAST DEPLOYED: Mon Jul 27 15:08:34 2020
    NAMESPACE: default
    STATUS: deployed
    REVISION: 2
    TEST SUITE: None
    
    [root@k8s-master ~]# kubectl get pod
    NAME                                            READY   STATUS    RESTARTS   AGE
    java-demo-dp-859745b69c-2r78f                   1/1     Running   0          12m
    java-demo-dp-859745b69c-gzx8k                   1/1     Running   0          46s
    java-demo-dp-859745b69c-zxvwl                   1/1     Running   0          46s
    

    5. 回滚chart包

    #列出模板的历史版本信息
    [root@k8s-master ~]# helm history java-demo 
    REVISION    UPDATED                     STATUS      CHART           APP VERSION DESCRIPTION     
    1           Mon Jul 27 14:56:53 2020    superseded  mychart-0.1.0   1.16.0      Install complete
    2           Mon Jul 27 15:08:34 2020    deployed    mychart-0.1.0   1.16.0      Upgrade complete
    
    #回滚到 1 版本,1版本为创第一次创建,副本数为1;创建完成后可以检查一下
    [root@k8s-master ~]# helm rollback java-demo 1
    Rollback was a success! Happy Helming!
    
    #由三副本变为1副本了
    [root@k8s-master ~]# kubectl get pod
    NAME                                            READY   STATUS    RESTARTS   AGE
    java-demo-dp-859745b69c-2r78f                   1/1     Running   0          17m
    

    7. Chart 的UI管理界面 monocular

    可以在里面添加 chart 的仓库,能够查看到当前集群中已经运行的 Chart,同时还能够直接在页面上就部署一个 chart 至 kuberntes 集群,就好像一个 kubernetes 的 appstore 一样。不支持覆盖 chart 中指定一个的默认参数,唯一可选择的就是部署的 namespace。

    安装方法比较简单 可访问官方查看:https://github.com/helm/monocular

    8. Helm命令总结

    #搜索可用于安装的Chart
    helm search mysql
    
    #安装一个Chart
    helm install stable/mysql
    
    #列出k8s中已经部署的Chart
    helm list --all
    
    #helm的仓库更新
    helm repo update
    
    #查看镜像源
    helm repo list
    
    #添加镜像源
    helm repo add stable <url>
    
    #删除镜像源
    helm repo remove <url>
    
    #创建Chart包管理模板,会产生一个Chart所需的目录结构
    helm create mychart
    
    #升级chart包
    helm upgrade --set xxx java-demo
    
    #查看历史版本
    helm history java-demo
    
    #回滚chart包版本
    helm rollback java-demo 1
    
    #删除release
    helm delete nginx
    
    #打包Chart
    helm package helm/mychart/
    Successfully packaged chart and saved it to: /root/mychart-0.1.0.tgz
    

    八、弹性伸缩(扩容/缩容)

    1. Node扩容/缩容

    从Kubernetes集群中删除节点的方法:https://blog.csdn.net/erhaiou2008/article/details/104986006/

    1、Cluster AutoScaler

    扩容: Cluster AutoScaler 定期检测是否有充足的资源来调度新创建的 Pod,当资源不足时会调用 Cloud Provider 创建新的 Node。

    图片来自网络 image

    缩容: Cluster AutoScaler 也会定期监测 Node 的资源使用情况,当一个 Node 长时间资源利用率都很低时(低于 50%)自动将其所在虚拟机从云服务商中删除。此时,原来的 Pod 会自动调度到其他 Node 上面。

    图片来自网络 image

    支持的云提供商:

    2. Pod自动扩容/缩容(HPA)

    Horizontal Pod Autoscaler(HPA,Pod水平自动伸缩),根据资源利用率或者自定义指标自动调整replication controller, deployment 或 replica set,实现部署的自动扩展和缩减,让部署的规模接近于实际服务的负载。HPA不适于无法缩放的对象,例如DaemonSet。

    1、HPA基本原理

    Kubernetes 中的 Metrics Server 持续采集所有 Pod 副本的指标数据。HPA 控制器通过 Metrics Server 的 API(Heapster 的 API 或聚合 API)获取这些数据,基于用户定义的扩缩容规则进行计算,得到目标 Pod 副本数量。当目标 Pod 副本数量与当前副本数量不同时,HPA 控制器就向 Pod 的副本控制器(Deployment、RC 或 ReplicaSet)发起 scale 操作,调整 Pod 的副本数量,完成扩缩容操作。如图所示。

    在弹性伸缩中,冷却周期是不能逃避的一个话题, 由于评估的度量标准是动态特性,副本的数量可能会不断波动。有时被称为颠簸, 所以在每次做出扩容缩容后,冷却时间是多少。

    在 HPA 中,默认的扩容冷却周期是 3 分钟,缩容冷却周期是 5 分钟。

    可以通过调整kube-controller-manager组件启动参数设置冷却时间:

    • --horizontal-pod-autoscaler-downscale-delay :扩容冷却
    • --horizontal-pod-autoscaler-upscale-delay :缩容冷却

    2、HPA的演进历程

    目前 HPA 已经支持了 autoscaling/v1autoscaling/v2beta1autoscaling/v2beta2 三个大版本 。

    目前大多数人比较熟悉是autoscaling/v1,这个版本只支持CPU一个指标的弹性伸缩。

    而autoscaling/v2beta1增加了支持自定义指标,autoscaling/v2beta2又额外增加了外部指标支持。

    而产生这些变化不得不提的是Kubernetes社区对监控与监控指标的认识与转变。从早期Heapster到Metrics Server再到将指标边界进行划分,一直在丰富监控生态。

    3. 基于CPU指标进行缩放

    1、 Kubernetes API Aggregation

    在 Kubernetes 1.7 版本引入了聚合层,允许第三方应用程序通过将自己注册到kube-apiserver上,仍然通过 API Server 的 HTTP URL 对新的 API 进行访问和操作。为了实现这个机制,Kubernetes 在 kube-apiserver 服务中引入了一个 API 聚合层(API Aggregation Layer),用于将扩展 API 的访问请求转发到用户服务的功能。

    图片来自网络


    image

    当你访问 apis/metrics.k8s.io/v1beta1 的时候,实际上访问到的是一个叫作 kube-aggregator 的代理。而 kube-apiserver,正是这个代理的一个后端;而 Metrics Server,则是另一个后端 。通过这种方式,我们就可以很方便地扩展 Kubernetes 的 API 了。

    因是使用kubeadm部署的,默认已开启。如果使用二进制方式部署的话,需要在kube-APIServer中添加启动参数,增加以下配置:

    # vim /opt/kubernetes/cfg/kube-apiserver.conf
    ...
    --requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
    --proxy-client-cert-file=/opt/kubernetes/ssl/server.pem \
    --proxy-client-key-file=/opt/kubernetes/ssl/server-key.pem \
    --requestheader-allowed-names=kubernetes \
    --requestheader-extra-headers-prefix=X-Remote-Extra- \
    --requestheader-group-headers=X-Remote-Group \
    --requestheader-username-headers=X-Remote-User \
    --enable-aggregator-routing=true \
    ...
    

    设置完成重启 kube-apiserver 服务,就启用 API 聚合功能了。


    2. autoscaling/v1(CPU指标测试)

    autoscaling/v1版本只能支持CPU一个指标。

    先部署一个应用pod

    [root@k8s-master autoscaling]# cat deployment_web.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: web
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx-php
      template:
        metadata:
          labels:
            app: nginx-php
        spec:
          containers:
          - image: 245684979/nginx-php
            name: java
            resources: 
               requests:
                 memory: "300Mi"
                 cpu: "250m"
    
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      name: web
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: nginx-php
    
    
    [root@k8s-master autoscaling]# kubectl get pod
    NAME                                            READY   STATUS    RESTARTS   AGE
    web-5bf5bb785f-tnjzn                            1/1     Running   0          46s
    
    #ClusterIP为10.244.58.206 接 -o wide参数查看
    

    创建HPA策略组

    [root@k8s-master autoscaling]# cat autoscaling_v1.yaml 
    apiVersion: autoscaling/v1
    kind: HorizontalPodAutoscaler
    metadata:
      name: web
    spec:
      maxReplicas: 5
      minReplicas: 1
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: web
      targetCPUUtilizationPercentage: 60
    
    #- scaleTargetRef:表示当前要伸缩对象是谁
    #- targetCPUUtilizationPercentage:当整体的资源利用率超过60%的时候,会进行扩容
    
    [root@k8s-master autoscaling]# kubectl get hpa
    NAME   REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
    web    Deployment/web   0%/60%    1         1         1          1m
    

    进行压测

    yum install httpd-tools
    ab -n 100000 -c 100  http://10.244.58.206/status.php
    

    检查扩容状态

    [root@k8s-master ~]# kubectl get hpa
    NAME   REFERENCE        TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
    web    Deployment/web   537%/60%   1         5         4          3m42s
    
    [root@k8s-master ~]# kubectl top pods
    NAME                                            CPU(cores)   MEMORY(bytes)           
    web-5bf5bb785f-tnjzn                            1343m        25Mi 
    
    [root@k8s-master ~]# kubectl get pods
    NAME                                    READY   STATUS              RESTARTS   AGE
    web-5bf5bb785f-7l5tl                    0/1     ContainerCreating   0          41s
    web-5bf5bb785f-7n886                    1/1     Running             0          56s
    web-5bf5bb785f-pzgzs                    1/1     Running             0          56s
    web-5bf5bb785f-qm8wb                    0/1     ContainerCreating   0          56s
    web-5bf5bb785f-tnjzn                    1/1     Running             0          6m13s
    

    关闭压测,过5分钟检查缩容状态

    [root@k8s-master ~]# kubectl get pod
    NAME                                     READY   STATUS    RESTARTS   AGE
    web-5bf5bb785f-tnjzn                     1/1     Running   0          13m
    

    工作流程:
    hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor)


    3. autoscaling/v2beta2(多指标)

    为满足更多的需求, HPA 还有 autoscaling/v2beta1autoscaling/v2beta2两个版本。

    这两个版本的区别是 autoscaling/v1beta1支持了 Resource Metrics(CPU)和 Custom Metrics(应用程序指标),而在 autoscaling/v2beta2的版本中额外增加了 External Metrics (外部指标)的支持。

    #生成yaml
    kubectl get hpa.v2beta2.autoscaling -o yaml > hpa-v2.yaml
    

    v2与上面v1版本效果一样,只不过这里格式有所变化。

    v2还支持其他另种类型的度量指标:Pods和Object。

    metrics中的type字段有四种类型的值:Object、Pods、Resource、External。

    • Resource:指的是当前伸缩对象下的pod的cpu和memory指标,只支持Utilization(利用率)和AverageValue(平均值)类型的目标值。
    • Object:指的是指定k8s内部对象的指标,数据需要第三方adapter提供,只支持Value和AverageValue类型的目标值。
    • Pods:指的是伸缩对象Pods的指标,数据需要第三方的adapter提供,只允许AverageValue类型的目标值。
    • External:指的是k8s外部的指标,数据同样需要第三方的adapter提供,只支持Value和AverageValue类型的目标值。
    #测试的yaml文件
    [root@k8s-master autoscaling]# cat hpa-v2.yaml 
    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    metadata:
      name: web
      namespace: default
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: web
      minReplicas: 1
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 50
      - type: Pods
        pods:
          metric:
            name: packets-per-second
          target:
            type: AverageValue
            averageValue: 1k
      - type: Object
        object:
          metric:
            name: requests-per-second
          describedObject:
            apiVersion: networking.k8s.io/v1beta1
            kind: Ingress
            name: main-route
          target:
            type: Value
            value: 10k
    

    工作流程:
    hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods

    4. 基于Prometheus自定义指标弹性伸缩

    参考博客
    https://blog.51cto.com/12480612/2457624

    资源指标只包含CPU、内存,一般来说也够了。但如果想根据自定义指标:如请求qps/5xx错误数来实现HPA,就需要使用自定义指标了,目前比较成熟的实现是 Prometheus Custom Metrics。自定义指标由Prometheus来提供,再利用k8s-prometheus-adpater聚合到apiserver,实现和核心指标(metric-server)同样的效果。

    1. 准备一个nfs环境

    提前部署好nfs-client,否则prometheus无法启动
    为防止Pod漂移到其他节点无法访问,所以需要创建一个nfs共享目录来进行挂载

    #准备一台nfs服务器或者用master节点作为nfs服务器测试即可
    #在服务端安装nfs软件:
    yum install -y nfs-utils rpcbind
    #启动rpcbind和nfs服务
    systemctl restart rpcbind nfs
    systemctl enable rpcbind nfs
    #nfs配置文件/etc/exports
    echo '/ifs/kubernetes   *(rw,no_root_squash' >>/etc/exports
    #创建nfs共享目录
    mkdir -p /ifs/kubernetes
    #平滑重启nfs
    systemctl reload nfs
    #检查可以挂载的目录
    [root@k8s-master ~]# showmount -e 
    Export list for k8s-master:
    /ifs/kubernetes *
    #在所有k8s节点安装nfs客户端
    yum install  nfs-utils -y
    

    nfs-client文件包下载链接:提取码: rr89

    [root@k8s-master ~]# unzip nfs-client.zip
    [root@k8s-master ~]# cd nfs-client/
    [root@k8s-master nfs-client]# ll
    total 12
    -rw-r--r-- 1 root root  225 Nov 30  2019 class.yaml
    -rw-r--r-- 1 root root  994 Nov 30  2019 deployment.yaml
    -rw-r--r-- 1 root root 1526 Nov 30  2019 rbac.yaml
    

    修改deployment.yaml文件

    [root@k8s-master nfs-client]# cat deployment.yaml
    ...
                  value: 192.168.0.10 #nfs服务器地址
                - name: NFS_PATH
                  value: /ifs/kubernetes    #nfs共享目录
          volumes:
            - name: nfs-client-root
              nfs:
                server: 192.168.0.10    #nfs服务器地址
                path: /ifs/kubernetes   #nfs共享目录
    

    构建nfs-client

    [root@k8s-master nfs-client]# kubectl apply -f .
    [root@k8s-master nfs-client]# kubectl get pod
    NAME                                            READY   STATUS    RESTARTS   AGE
    nfs-client-provisioner-f7886779f-cwqkr          1/1     Running   0          26s
    
    # kubectl get pv
    # kubectl get sc
    

    查看nfs共享目录下成功了

    [root@k8s-master nfs-client]# ls /ifs/kubernetes/
    kube-system-grafana-data-grafana-0-pvc-469e13d0-8429-4766-b23a-af9baf3eb80c
    kube-system-prometheus-data-prometheus-0-pvc-074bfaaf-4ceb-42d9-b940-d2f4905bc69b
    

    2. 部署Prometheus

    Prometheus文件包下载链接: 提取码: 3buh

    [root@k8s-master ~]# unzip  prometheus.zip
    [root@k8s-master ~]# cd prometheus/
    [root@k8s-master prometheus]# ll
    total 68
    -rw-r--r-- 1 root root 5124 Nov 24  2019 prometheus-configmap.yaml
    -rw-r--r-- 1 root root 1080 Nov 23  2019 prometheus-rbac.yaml
    -rw-r--r-- 1 root root 4884 Nov 24  2019 prometheus-rules.yaml
    -rw-r--r-- 1 root root  392 Nov 23  2019 prometheus-service.yaml
    -rw-r--r-- 1 root root 3257 Jul 30 14:28 prometheus-statefulset.yaml
    
    #当前只需要用到prometheus的yaml文件
    kubectl apply -f prometheus-rbac.yaml 
    kubectl apply -f prometheus-configmap.yaml 
    kubectl apply -f prometheus-rules.yaml 
    kubectl apply -f prometheus-service.yaml 
    kubectl apply -f prometheus-statefulset.yaml
    
    #查看Pod和svc资源并进行访问
    [root@k8s-master ~]# kubectl get pod,svc -n kube-system 
    NAME                                           READY   STATUS    RESTARTS   AGE
    ...
    pod/prometheus-0                               2/2     Running   0          10m
    
    NAME                              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                       AGE
    service/prometheus                NodePort    10.10.82.85     <none>        9090:30090/TCP                10m
    

    访问Prometheus UI:http://NdeIP:30090

    3. 基于prometheus采集QPS速率指标测试

    • 应用程序要暴露/metrics监控指标并且是prometheus数据格式
    • prometheus采集入库
    • 针对要监控的数据添加adapter规则(promSQL)
    • adapter注册Api server
    • 编写HPA规则(对应的指标名称)

    部署一个应用

    [root@k8s-master hpa]# cat metrics-app.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: metrics-app
      name: metrics-app
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: metrics-app
      template:
        metadata:
          labels:
            app: metrics-app
          annotations:
            prometheus.io/scrape: "true"    #表明可以采集Pod
            prometheus.io/port: "80"    #采集Pod允许访问的端口
            prometheus.io/path: "/metrics"  #采集Pod要连接的url地址
        spec:
          containers:
          - image: 245684979/metrics-app
            name: metrics-app
            ports:
            - name: web
              containerPort: 80
            resources:
              requests:
                cpu: 200m
                memory: 256Mi
            readinessProbe:
              httpGet:
                path: /
                port: 80
              initialDelaySeconds: 3
              periodSeconds: 5
            livenessProbe:
              httpGet:
                path: /
                port: 80
              initialDelaySeconds: 3
              periodSeconds: 5
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: metrics-app
      labels:
        app: metrics-app
    spec:
      ports:
      - name: web
        port: 80
        targetPort: 80
      selector:
        app: metrics-app
    
    [root@k8s-master hpa]# kubectl apply -f metrics-app.yaml
    

    该metrics-app暴露了一个Prometheus指标接口,可以通过访问service看到:

    [root@k8s-master hpa]# kubectl get pod,svc
    NAME                                                READY   STATUS    RESTARTS   AGE
    pod/metrics-app-b4d7dd845-5h5r9                     1/1     Running   0          2m49s
    pod/metrics-app-b4d7dd845-dgmlc                     1/1     Running   0          2m49s
    pod/metrics-app-b4d7dd845-vmdf5                     1/1     Running   0          2m49
    
    NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/metrics-app      ClusterIP   10.10.81.19     <none>        80/TCP         2m49s
    
    [root@k8s-master hpa]# curl 10.10.81.19
    Hello! My name is metrics-app-b4d7dd845-dgmlc. The last 10 seconds, the average QPS has been 0.5. Total requests served: 44
    
    [root@k8s-master hpa]# curl 10.10.81.19/metrics
    # HELP http_requests_total The amount of requests in total
    # TYPE http_requests_total counter
    http_requests_total 210 #当前Pod累计的请求值
    # HELP http_requests_per_second The amount of requests per second the latest ten seconds
    # TYPE http_requests_per_second gauge
    http_requests_per_second 0.5    #10s之内有0.5个http请求
    

    在prometheus的界面上可以请求到数据

    创建HPA策略

    [root@k8s-master hpa]# vim app-hpa-v2.yaml
    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    metadata:
      name: metrics-app-hpa 
      namespace: default
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: metrics-app
      minReplicas: 1
      maxReplicas: 10
      metrics:
      - type: Pods
        pods:
          metric:
            name: http_requests_per_second
          target:
            type: AverageValue
            averageValue: 800m   # 800m 即0.8个/秒
    
    
    [root@k8s-master hpa]# kubectl apply -f app-hpa-v2.yaml
    [root@k8s-master hpa]# kubectl get hpa
    NAME              REFERENCE                TARGETS          MINPODS   MAXPODS   REPLICAS   AGE
    metrics-app-hpa   Deployment/metrics-app   <unknown>/800m   1         10        3          15m
    

    这里使用Prometheus提供的指标测试来测试自定义指标(QPS)的自动缩放。
    获取不到值:<unknown>

    但是 prometheus采集到的metrics并不能直接给k8s用,因为两者数据格式不兼容,还需要另外一个组件(k8s-prometheus-adpater),将prometheus的metrics 数据格式转换成k8s API接口能识别的格式,转换以后,因为是自定义API,所以还需要用Kubernetes aggregator在主APIServer中注册,以便直接通过/apis/来访问。

    4. 部署 Custom Metrics Adapter

    https://github.com/DirectXMan12/k8s-prometheus-adapter
    该 PrometheusAdapter 有一个稳定的Helm Charts,可以直接使用helm的包。

    准备好helm的环境:
    上文已经安装好helm包管理工具了

    [root@k8s-master ~]# helm repo list
    NAME    URL                                     
    stable  http://mirror.azure.cn/kubernetes/charts
    [root@k8s-master ~]# helm list 
    

    部署prometheus-adapter
    指定prometheus地址:

    helm install prometheus-adapter stable/prometheus-adapter --namespace kube-system --set prometheus.url=http://prometheus.kube-system,prometheus.port=9090
    
    [root@k8s-master ~]# helm list -n kube-system
    NAME                NAMESPACE   REVISION    UPDATED                                 STATUS      CHART                       APP VERSION
    prometheus-adapter  kube-system 1           2020-07-30 18:04:42.895949887 +0800 CST deployed    prometheus-adapter-2.5.0    v0.7.0
    
    [root@k8s-master ~]# kubectl get pods -n kube-system
    NAME                                       READY   STATUS    RESTARTS   AGE
    prometheus-adapter-56c85455f8-rrmxc        0/1     Running   0          40s
    

    保证适配器注册到APIServer:

    [root@k8s-master ~]# kubectl get apiservices |grep custom 
    v1beta1.custom.metrics.k8s.io          kube-system/prometheus-adapter   True        86s
    
    #输出监控指标
    kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"
    

    5. 配置适配器收集特定的指标

    当创建好HPA还没结束,因为适配器还不知道你要什么指标(http_requests_per_second),HPA也就获取不到Pod提供指标。
    ConfigMap在default名称空间中编辑prometheus-adapter ,并在该rules: 部分的顶部添加一个新的seriesQuery

    kubectl edit cm prometheus-adapter -n kube-system
    ...
        rules:
        - seriesQuery: 'http_requests_total{kubernetes_namespace!="",kubernetes_pod_name!=""}'
          resources:
            overrides:
              kubernetes_namespace: {resource: "namespace"}
              kubernetes_pod_name: {resource: "pod"}
          name:
            matches: "^(.*)_total"
            as: "${1}_per_second"
          metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'
    ...
    

    该规则将http_requests在2分钟的间隔内收集该服务的所有Pod的平均速率。

    需要重建prometheus-adapter的Pod才能获取到监控指标

    kubectl delete pod -n kube-system prometheus-adapter-56c85455f8-zth2c
    
    [root@k8s-master hpa]# kubectl get hpa
    NAME             REFERENCE               TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
    metrics-app-hpa  Deployment/metrics-app  416m/800m   1         10        2          34m
    

    测试一下 API:

    kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/http_requests_per_second"
    

    进行压力测试

    ab -n 100000 -c 100  http://10.10.81.19/metrics
    

    查看HPA状态:

    [root@k8s-master ~]# kubectl get hpa
    NAME            REFERENCE              TARGETS       MINPODS  MAXPODS  REPLICAS   AGE
    metrics-app-hpa Deployment/metrics-app 254176m/800m  1        10       4          6m29s
    
    [root@k8s-master ~]# kubectl describe hpa metrics-app-hpa
      Normal  SuccessfulRescale  53s   horizontal-pod-autoscaler  New size: 4; reason: pods metric http_requests_per_second above target
      Normal  SuccessfulRescale  37s   horizontal-pod-autoscaler  New size: 8; reason: pods metric http_requests_per_second above target
      Normal  SuccessfulRescale  22s   horizontal-pod-autoscaler  New size: 10; reason: pods metric http_requests_per_second above target
      
    [root@k8s-master ~]# kubectl get pod
    NAME                                     READY   STATUS              RESTARTS   AGE
    metrics-app-b4d7dd845-2mr5c              0/1     ContainerCreating   0          50s
    metrics-app-b4d7dd845-bndtx              0/1     Running             0          50s
    metrics-app-b4d7dd845-dgmlc              1/1     Running             2          16h
    metrics-app-b4d7dd845-dlbjn              1/1     Running             0          80s
    metrics-app-b4d7dd845-fvmlp              0/1     Running             0          65s
    metrics-app-b4d7dd845-ldqwg              1/1     Running             0          65s
    metrics-app-b4d7dd845-npkzg              1/1     Running             0          65s
    metrics-app-b4d7dd845-vmdf5              1/1     Running             1          16h
    metrics-app-b4d7dd845-zpvdr              1/1     Running             0          80s
    metrics-app-b4d7dd845-zx66k              1/1     Running             0          65s
    

    6. 总结

    图片来自网络
    1. 通过/metrics收集每个Pod的http_request_total指标;
    2. prometheus将收集到的信息汇总;
    3. APIServer定时从Prometheus查询,获取request_per_second的数据;
    4. HPA定期向APIServer查询以判断是否符合配置的autoscaler规则;
    5. 如果符合autoscaler规则,则修改Deployment的ReplicaSet副本数量进行伸缩。
    6. 监控的是所有Pod的平均值,是一个deployment中部署的。
    7. 暴露的/metrics接口需要开发在代码框架中提前定义好用prometheus采集相关的Url接口。也有一些应用默认自带prometheus的监控接口。可以去查找prometheus针对于应用程序暴露指标的客户端。

    相关文章

      网友评论

        本文标题:③k8s部署应用的流程与管理

        本文链接:https://www.haomeiwen.com/subject/bqdslktx.html