10. K8S 升级回滚和日志收集

1. k8s pod版本更新流程及命令行实现升级与回滚

1.1 代码的几种发布方式

1.1.1 蓝绿发布

  1. 项目逻辑上分为AB组,在项目系统时,首先把A组从负载均衡中摘除,进行新版本的部署。B组仍然继续提供服务。

img

  1. 当A组升级完毕,负载均衡重新接入A组,再把B组从负载列表中摘除,进行新版本的部署。A组重新提供服务。

    img

  2. 最后,B组也升级完成,负载均衡重新接入B组,此时,AB组版本都已经升级完成,并且都对外提供服务。

特点:

  • 如果出问题,影响范围较大;
  • 发布策略简单;
  • 用户无感知,平滑过渡;
  • 升级/回滚速度快。

缺点:

  • 需要准备正常业务使用资源的两倍以上服务器,防止升级期间单组无法承载业务突发;
  • 短时间内浪费一定资源成本;
  • 基础设施无改动,增大升级稳定性。

1.1.2 滚动发布

滚动发布是指每次只升级一个或多个服务,升级完成后加入生产环境,不断执行这个过程,直到集群中的全部旧版本升级新版本。

img

  • 红色:正在更新的实例
  • 蓝色:更新完成并加入集群的实例
  • 绿色:正在运行的实例

特点:

  • 用户无感知,平滑过渡;
  • 节约资源。

缺点:

  • 部署时间慢,取决于每阶段更新时间;
  • 发布策略较复杂;
  • 无法确定OK的环境,不易回滚。

部署过程:

  • 先升级1个副本,主要做部署验证;
  • 每次升级副本,自动从LB上摘掉,升级成功后自动加入集群;
  • 事先需要有自动更新策略,分为若干次,每次数量/百分比可配置;
  • 回滚是发布的逆过程,先从LB摘掉新版本,再升级老版本,这个过程一般时间比较长;
  • 自动化要求高。

1.1.3 金丝雀/灰度发布

灰度发布只升级部分服务,即让一部分用户继续用老版本,一部分用户开始用新版本,如果用户对新版本没什么意见,那么逐步扩大范围,把所有用户都迁移到新版本上面来。

img

特点:

  • 保证整体系统稳定性,在初始灰度的时候就可以发现、调整问题,影响范围可控;
  • 新功能逐步评估性能,稳定性和健康状况,如果出问题影响范围很小,相对用户体验也少;
  • 用户无感知,平滑过渡。

缺点:

  • 自动化要求高

部署过程:

  • 从LB摘掉灰度服务器,升级成功后再加入LB;
  • 少量用户流量到新版本;
  • 如果灰度服务器测试成功,升级剩余服务器。

1.2 虚拟机环境下的版本升级实践流程

image-20211026144902746

Scripts:https://codeup.aliyun.com/614c9d1b3a631c643ae62857/Scripts.git

1.3 k8环境下的版本升级

image-20211025144226174

1.3.1 滚动更新和回滚

https://kubernetes.io/zh/docs/tutorials/kubernetes-basics/update/update-intro/

用户希望应用程序始终可用,而开发人员则需要每天多次部署它们的新版本。在 Kubernetes 中,这些是通过滚动更新(Rolling Updates)完成的。 滚动更新 允许通过使用新的实例逐步更新 Pod 实例,零停机进行 Deployment 更新。新的 Pod 将在具有可用资源的节点上进行调度。

Oct-25-2021 14-51-10

在指定的deployment中通过kubectl set image来指定新版本的镜像tag,来实现更新代码的目的。

Deployment 控制器支持两种更新策略:默认为滚动更新

  1. 滚动更新(rolling update)
  • 滚动更新是默认的资源更新策略,滚动更新是基于新版本镜像创建新版本的pod,然后删除一部分旧版本pod,然后在创建新版本pod,再删除一部分旧版本pod,直到新版本pod删除完成,滚动更新优势是在升级过程中不会导致服务不可用,缺点是升级过程中会导致两个版本在短时间内并存。
  • 具体升级过程是在执行更新操作后k8s会在创建一个新版本的ReplicaSet控制器,在删除旧版本的ReplicaSet控制器下的pod。同时会在新版本ReplicaSet控制器下创建新的pod,直到旧版本的pod全部被删除完后再把旧版本的ReplicaSet控制器回收。
  • 在执行滚动更新的同时,为保证服务的可用性,当前控制器内不可用的pod(pod需要拉取镜像还行创建和执行探针探测期间是不可用的),不能超出一定范围,因为需要至少保留一定数量的pod以保证服务可以被正常访问。可以通过指定参数实现:kubectl explain deployment.spec.strategy
    • deployment.spec.strategy.rollingUpdate.maxSurge: 指定在升级期间pod总数可以超出定义好的期望pod数的个数或者百分比,默认为25%,如果设置为10%,假设当前是100个pod,那么升级时最多将创建110pod,即额外有10%的pod临时会超出当前的副本数限制。
    • deployment.spec.strategy.rollingUpdate.maxUnavailable:指定在升级期间最大的不可用pod数,可以是整数或者当前pod的百分比,默认是25%,假设当前100个pod,那么在升级时最多可以有25个pod不可用,即还有75个pod是可用的。
    • 注意:以上两个值不能同时为0,如果maxUnavailable最大不可用pod为0,maxSurge超出数也为0,那么将会导致pod无法进行滚动更新。
  1. 重建更新(recreate)
  • 先删除现有pod,然后基于新版本的镜像重建,优势是同时只有一个版本在线,不会产生多版本在线的问题,缺点是pod删除后到pod重建中间会导致服务无法访问。

image-20211026105035106

1.3.1.1 升级镜像到指定版本
镜像更新格式:
kubectl set image deployment/deployment-name container-name=image -n namespace

# kubectl set image deployment test-tomcat-app1-deployment test-tomcat-app1-container=tomcat:8.5.56 -n test --record   #--record 记录更新信息
1.3.1.2 查看历史版本-可以用于后期的回滚
# kubectl rollout history deployment/test-tomcat-app1-deployment -n test
1.3.1.3 撤销-在最近的两个版本之间切换
# kubectl rollout undo deployment test-tomcat-app1-deployment -n test
1.3.1.4 回滚到指定版本
# kubectl rollout undo deployment test-tomcat-app1-deployment  -n test --to-revision=3

1.3.2 金丝雀/灰度发布

https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/#canary-deployment

K8S上两种实现方式

1.3.2.1 在升级的过程中暂停一下
# 连续快速执行# kubectl set image deployment test-tomcat-app1-deployment test-tomcat-app1-container=harbor.k8s.local/k8s/tomcat-app1:v2 -n test --record# kubectl rollout pause deployment test-tomcat-app1-deployment -n test  #暂停升级# kubectl rollout resume deployment test-tomcat-app1-deployment -n test  #新版本测试后,继续升级其它pod# kubectl rollout undo deployment test-tomcat-app1-deployment -n test  #新版本有问题,回滚
1.3.2.2 基于yaml文件进行
  1. 服务的原始版本deployment
# cat tomcat-app1.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: test-tomcat-app1-deployment-label
  name: test-tomcat-app1-deployment
  namespace: test
spec:
  replicas: 6
  selector:
    matchLabels:
      app: test-tomcat-app1-selector
  template:
    metadata:
      labels:
        app: test-tomcat-app1-selector
    spec:
      containers:
      - name: test-tomcat-app1-container
        image: harbor.k8s.local/k8s/tomcat:8.5.59 
        #command: ["/apps/tomcat/bin/run_tomcat.sh"]
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
        volumeMounts:
        - name: test-images
          mountPath: /usr/local/nginx/html/webapp/images
          readOnly: false
        - name: test-static
          mountPath: /usr/local/nginx/html/webapp/static
          readOnly: false
      volumes:
      - name: test-images
        nfs:
          server: 172.16.244.141
          path: /data/k8sdata/images
      - name: test-static
        nfs:
          server: 172.16.244.141
          path: /data/k8sdata/static
#      nodeSelector:
#        project: test
#        app: tomcat

  1. 服务原始版本的service
# cat tomcat-service.yaml
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: test-tomcat-app1-service-label
  name: test-tomcat-app1-service
  namespace: test
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
    #nodePort: 40003
  selector:
    app: test-tomcat-app1-selector
    #version: v2
  1. 服务的新版本deployment
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: test-tomcat-app1-deployment-label-v2
    version: v2
  name: test-tomcat-app1-deployment-v2
  namespace: test
spec:
  replicas: 1    #调节副本数,确定新旧版本副本比例
  selector:
    matchLabels:
      app: test-tomcat-app1-selector
      version: v2
  template:
    metadata:
      labels:
        app: test-tomcat-app1-selector
        version: v2    ##添加v2的标志字段
    spec:
      containers:
      - name: test-tomcat-app1-container
        image: harbor.k8s.local/k8s/tomcat-app1:v2 #使用新的镜像
        #command: ["/apps/tomcat/bin/run_tomcat.sh"]
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
        volumeMounts:
        - name: test-images
          mountPath: /usr/local/nginx/html/webapp/images
          readOnly: false
        - name: test-static
          mountPath: /usr/local/nginx/html/webapp/static
          readOnly: false
      volumes:
      - name: test-images
        nfs:
          server: 172.16.244.141
          path: /data/k8sdata/images
      - name: magedu-static
        nfs:
          server: 172.16.244.141
          path: /data/k8sdata/static
#      nodeSelector:
#        project: test
#        app: tomcat
  1. 在原始的service条件下,selector只匹配app=test-tomcat-app1-selector,所以service的endpoint是包含了两个版本的pod。

  2. 测试新版没有问题后,则可更新service,在selector中添加version字段,匹配sersion=v2,则service的endpoint就只包含新版本,实现全部升级。

    # cat tomcat-service.yaml
    ---
    kind: Service
    apiVersion: v1
    metadata:
      labels:
        app: test-tomcat-app1-service-label
      name: test-tomcat-app1-service
      namespace: test
    spec:
      type: NodePort
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 8080
        #nodePort: 40003
      selector:
        app: test-tomcat-app1-selector
        version: v2  #添加version字段进行匹配
    
  3. 如果新版本测试有问题,则可直接删除新版本的deployment。

2. k8s结合Jenkins与gitlab实现代码升级与回滚

image-20211027223212621

2.1 部署Jenkins

https://www.jenkins.io/

2.1.1 部署java环境

~# apt install openjdk-11-jdk

2.1.2 部署Jenkins

~# apt install -y daemon
~# dpkg -i  jenkins_2.303.2_all.deb 

2.1.3 修改配置文件

~# systemctl stop jenins
~# dpkg -c jenkins_2.303.2_all.deb 
~# vim /etc/default/jenkins
NAME=jenkins
JAVA_ARGS="-Djava.awt.headless=true -Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true" 
#新版本下开起钩子JAVA_ARGS="-Dhudson.security.csrf.GlobalCrumbIssuerConfiguration.DISABLE_CSRF_PROTECTION=true"
PIDFILE=/var/run/$NAME/$NAME.pid
JENKINS_USER=root      #启动使用的用户,测试就用root了
JENKINS_GROUP=root     #启动使用的用户,测试就用root了
JENKINS_WAR=/usr/share/$NAME/$NAME.war
JENKINS_HOME=/var/lib/$NAME
RUN_STANDALONE=true
JENKINS_LOG=/var/log/$NAME/$NAME.log
JENKINS_ENABLE_ACCESS_LOG="no"
MAXOPENFILES=8192
HTTP_PORT=8080
PREFIX=/$NAME
JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT"

2.1.4 启动jenkins,安装插件

~# systemctl restart jenkins.service
# 默认推荐插件安装后,在安装gitlab相关插件,如果插件安装完后,页面显示仍有英文,可以在重启一次服务
image-20211026191250297

2.2 部署gitlab

2.2.1 安装包

~# dpkg -i gitlab-ce_14.2.5-ce.0_amd64.deb 

2.2.2 修改配置

~# vim /etc/gitlab/gitlab.rb
...
external_url 'http://172.16.244.152'
...

2.2.3 重新加载配置

sudo gitlab-ctl reconfigure

2.2.4 登陆测试

#初始密码:cat /etc/gitlab/initial_root_password 

2.3 实现代码部署与回滚

2.3.1 配置测试项目

image-20211027105712280

2.3.2 jenkins与gitlab的非交互clone配置

  1. jenkins 服务器上生成密钥对

    root@jenkins:~# ssh-keygen 
    root@jenkins:~# cat /root/.ssh/id_rsa.pub 
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCiVIWzsDpSOYidr0O1lRZkK1qKaqrukazZIXqKI5UT2qgP1O3SfJAl6unPMi1AKK3y1T9Dd7tPG3i49/kCoGC0rdG0uXV+CkPR1iu4tglv5cbLfHuDCR+KRZtBG5+6h7RS8PnjHXSA5hqDSvVaHEqBySjb8Wlhggb3pMb0gMZ7QznapK7BVR42vjqDTekm6XjFUJ8w6VnSe6I5Jdu3UKZ25H17D6tgC4Mn1XSWLODr61evdl7JNeUBudEKCvDMeChKKOVJ6XOS/2E6x01PUprU0LYIzwzV98+iHcssYuQwk+zlvcFy1ed6JKjkQRg+zijjRvhvGpAe7ScNvI7I2VD7MjST8l0U4GltoEH4F3ZV8hZRH03gXT8wsRAoaAgrTAYnAHNmzKCZ2LjiyDYW8K1GVAeuKRulBdN8FXwVq+YXpgSyAznMIl4JBMqRhJylNKgxIhhsyALj4wohpYV7t8cz7HtDs94lFuBZw80r/jKpvW/xO+q6XakXi+XCsmXRchk= root@jenkins.k8s.local
    
  2. 将jenkin服务器的公钥放在gitlab

    image-20211027125745636
    root@jenkins:~# git clone git@172.16.244.152:test/app1.git
    

2.3.3 Jenkins 创建任务

2.3.3.1 创建Jenkins任务,以脚本的形式进行构建
image-20211027134106660
root@jenkins:/data/scripts# cat test-job1.sh
#!/bin/bash

#记录脚本开始执行时间
starttime=`date +'%Y-%m-%d %H:%M:%S'`

#变量
SHELL_DIR="/data/scripts"
SHELL_NAME="$0"
K8S_CONTROLLER1="172.16.244.100"
K8S_CONTROLLER2="172.16.244.102"
K8S_CONTROLLER3="172.16.244.103"
DATE=`date +%Y-%m-%d_%H_%M_%S`
METHOD=$1
Branch=$2


if test -z $Branch;then
  Branch=develop
fi


function Code_Clone(){
  Git_URL="git@172.16.244.152:test/app1.git"
  DIR_NAME=`echo ${Git_URL} |awk -F "/" '{print $2}' | awk -F "." '{print $1}'`
  DATA_DIR="/data/gitdata/test"
  Git_Dir="${DATA_DIR}/${DIR_NAME}"
  cd ${DATA_DIR} &&  echo "即将清空上一版本代码并获取当前分支最新代码" && sleep 1 && rm -rf ${DIR_NAME}
  echo "即将开始从分支${Branch} 获取代码" && sleep 1
  git clone -b ${Branch} ${Git_URL} 
  echo "分支${Branch} 克隆完成,即将进行代码编译!" && sleep 1
  #cd ${Git_Dir} && mvn clean package
  #echo "代码编译完成,即将开始将IP地址等信息替换为测试环境"
  #####################################################
  sleep 1
  cd ${Git_Dir}
  tar czf ${DIR_NAME}.tar.gz  ./*
}

#将打包好的压缩文件拷贝到k8s 控制端服务器
function Copy_File(){
  echo "压缩文件打包完成,即将拷贝到k8s 控制端服务器${K8S_CONTROLLER1}" && sleep 1
  scp ${Git_Dir}/${DIR_NAME}.tar.gz root@${K8S_CONTROLLER1}:/root/k8s-data/dockerfile/web/test/tomcat-app1/
  echo "压缩文件拷贝完成,服务器${K8S_CONTROLLER1}即将开始制作Docker 镜像!" && sleep 1
}

#到控制端执行脚本制作并上传镜像
function Make_Image(){
  echo "开始制作Docker镜像并上传到Harbor服务器" && sleep 1
  ssh root@${K8S_CONTROLLER1} "cd /root/k8s-data/dockerfile/web/test/tomcat-app1/ && bash build-command.sh ${DATE}"
  echo "Docker镜像制作完成并已经上传到harbor服务器" && sleep 1
}

#到控制端更新k8s yaml文件中的镜像版本号,从而保持yaml文件中的镜像版本号和k8s中版本号一致
function Update_k8s_yaml(){
  echo "即将更新k8s yaml文件中镜像版本" && sleep 1
  ssh root@${K8S_CONTROLLER1} "cd /root/k8s-data/yaml/test/tomcat-app1 && sed -i 's/image: harbor.test.*/image: harbor.k8s.local\/k8s\/tomcat-app1:${DATE}/g' tomcat-app1.yaml"
  echo "k8s yaml文件镜像版本更新完成,即将开始更新容器中镜像版本" && sleep 1
}

#到控制端更新k8s中容器的版本号,有两种更新办法,一是指定镜像版本更新,二是apply执行修改过的yaml文件
function Update_k8s_container(){
  #第一种方法
  ssh root@${K8S_CONTROLLER1} "kubectl set image deployment/test-tomcat-app1-deployment  test-tomcat-app1-container=harbor.k8s.local/k8s/tomcat-app1:${DATE} -n test" 
  #第二种方法,推荐使用第一种
  #ssh root@${K8S_CONTROLLER1} "cd  /root/k8s-data/yaml/test/tomcat-app1 && kubectl  apply -f tomcat-app1.yaml --record" 
  echo "k8s 镜像更新完成" && sleep 1
  echo "当前业务镜像版本: harbor.k8s/local/tomcat-app1:${DATE}"
  #计算脚本累计执行时间,如果不需要的话可以去掉下面四行
  endtime=`date +'%Y-%m-%d %H:%M:%S'`
  start_seconds=$(date --date="$starttime" +%s);
  end_seconds=$(date --date="$endtime" +%s);
  echo "本次业务镜像更新总计耗时:"$((end_seconds-start_seconds))"s"
}

#基于k8s 内置版本管理回滚到上一个版本
function rollback_last_version(){
  echo "即将回滚之上一个版本"
  ssh root@${K8S_CONTROLLER1}  "kubectl rollout undo deployment/test-tomcat-app1-deployment  -n test"
  sleep 1
  echo "已执行回滚至上一个版本"
}

#使用帮助
usage(){
  echo "部署使用方法为 ${SHELL_DIR}/${SHELL_NAME} deploy "
  echo "回滚到上一版本使用方法为 ${SHELL_DIR}/${SHELL_NAME} rollback_last_version"
}

#主函数
main(){
  case ${METHOD}  in
  deploy)
    Code_Clone;
    Copy_File;
    Make_Image; 
    Update_k8s_yaml;
    Update_k8s_container;
  ;;
  rollback_last_version)
    rollback_last_version;
  ;;
  *)
    usage;
  esac;
}

main $1 $2
2.3.3.2 jenkins 的变量传递
image-20211027134640978 image-20211027164749179 image-20211027164812867 image-20211027164851316

3. k8s结合ELK实现日志收集

image-20211027222923741

https://kubernetes.io/zh/docs/concepts/cluster-administration/logging/

日志:

  • 系统日志 /var/log/syslog
  • 应用日志
    • 系统错误日志 error.log
    • 访问日志 access.log

实现方式:

  1. 在k8s运行daemonSet,收集每个node节点日志,缺点是很难分类;优点是配置简单,后期维护简单。
  2. 在每个pod中启动日志收集客户端(filebeat),收集当前pod中的日志。两个实现方式:1.在pod的同一个容器中,先启动filebeat进程,然后在启动服务(实现相对简单)。2.在一个pod中启动两个容器,一个是容器是服务,另一个是filebeat。采用hostpath或emptydir做数据共享缓存,实现filebeat容器能够读取服务容器的日志。

image-20211027231643818

3.1 部署zookeeper集群

http://zookeeper.apache.org/doc/r3.5.9/zookeeperStarted.html#sc_Prerequisites

~# apt install -y openjdk-8-jdk
~# mkdir /apps
~# mkdir -p /data/zookeeper
~# mv apache-zookeeper-3.5.9-bin.tar.gz  /apps/
~# cd /apps/
:/apps# tar xvf apache-zookeeper-3.5.9-bin.tar.gz 
:/apps# cd apache-zookeeper-3.5.9-bin/conf
:/apps/apache-zookeeper-3.5.9-bin/conf#cp zoo_sample.cfg zoo.cfg
:/apps/apache-zookeeper-3.5.9-bin/conf# vim zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper
clientPort=2181
maxClientCnxns=60    #单个客户端的最大连接数(该注释不能在配置文件中体现,要不启不来)
autopurge.snapRetainCount=3
autopurge.purgeInterval=1
server.1=172.16.244.165:2888:3888
server.2=172.16.244.166:2888:3888
server.3=172.16.244.167:2888:3888

# scp zoo.cfg root@172.16.244.166:/apps/apache-zookeeper-3.5.9-bin/conf
# scp zoo.cfg root@172.16.244.167:/apps/apache-zookeeper-3.5.9-bin/conf
root@mq1:~# echo 1 > /data/zookeeper/myid
root@mq2:~# echo 2 > /data/zookeeper/myid
root@mq3:~# echo 3 > /data/zookeeper/myid
root@mq1:/apps/apache-zookeeper-3.5.9-bin# ./bin/zkServer.sh start
root@mq2:/apps/apache-zookeeper-3.5.9-bin# ./bin/zkServer.sh start
root@mq3:/apps/apache-zookeeper-3.5.9-bin# ./bin/zkServer.sh start

root@mq1:/apps/apache-zookeeper-3.5.9-bin# ./bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/apache-zookeeper-3.5.9-bin/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower

root@mq2:/apps/apache-zookeeper-3.5.9-bin# ./bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/apache-zookeeper-3.5.9-bin/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: leader

root@mq3:/apps/apache-zookeeper-3.5.9-bin# ./bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /apps/apache-zookeeper-3.5.9-bin/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower

3.2 部署kafka

https://kafka.apache.org/downloads

~# mv kafka_2.13-2.4.1.tgz /apps
~# mkdir -p /data/kafka-logs
:/apps# tar xvf kafka_2.13-2.4.1.tgz 
:/apps# cd kafka_2.13-2.4.1/
:/apps/kafka_2.13-2.4.1# vim config/server.properties
broker.id=1            #各节点不同的整数,可以是节点IP的最后一位
listeners=PLAINTEXT://172.16.244.165:9092    #节点本身的IP
num.network.threads=3        #数据大的时候可以多开点
num.io.threads=8             #数据大的时候可以多开点
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/data/kafka-logs    #自定义数据存储目录,写的是logs,但并不全是log
num.partitions=1
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.retention.hours=168
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
zookeeper.connect=172.16.244.165:2181,172.16.244.166:2181,172.16.244.167:2181   #写上所有zookeeper节点的IP和端口
zookeeper.connection.timeout.ms=6000
group.initial.rebalance.delay.ms=0


~# /apps/kafka_2.13-2.4.1/bin/kafka-server-start.sh -daemon /apps/kafka_2.13-2.4.1/config/server.properties  # 启动kafka

root@mq1:~# ss -anlptu | grep 9092
tcp   LISTEN 0       50       [::ffff:172.16.244.165]:9092               *:*     users:(("java",pid=570417,fd=133))  

3.3 部署ES集群及浏览器安装elasticsearch head插件

https://www.elastic.co/cn/downloads/

~# dpkg -i elasticsearch-7.6.2-amd64.deb 
~ # grep -Ev "^#|^$" /etc/elasticsearch/elasticsearch.yml
cluster.name: my-es-1                #设置集群名称
node.name: node1                     #节点名称
path.data: /var/lib/elasticsearch    #数据路径,生产环境单独放在一个盘上
path.logs: /var/log/elasticsearch    #日志路径
network.host: 172.16.244.161         #监听地址
http.port: 9200                      #监听端口
discovery.seed_hosts: ["172.16.244.161", "172.16.244.162","172.16.244.163"]  #节点地址
cluster.initial_master_nodes: ["172.16.244.161", "172.16.244.162","172.16.244.163"]    #master节点地址,如果不想被选举为master的节点,可以不写
gateway.recover_after_nodes: 2        #集群数据同步启动的在线节点数,小于这个值,集群不进行数据同步,一般是总节点数的一半
action.destructive_requires_name: true #在删除索引的时候是否允许进行模糊匹配,一般生产上是不允许,该选项要打开
~# systemctl restart elasticsearch.service 
image-20211028133807007 image-20211028134241538 image-20211028134420494

3.4 pod中启动filebeat实现日志收集并输出到kafka

一般是将filebeat安装到系统的基础镜像中,在最后的app镜像中,将其加载配置后启动即可。

3.4.1 filebeat 配置文件

https://www.elastic.co/guide/en/beats/filebeat/7.6/kafka-output.html

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /apps/tomcat/logs/catalina.out
  fields:
    type: tomcat-catalina    #收集tomcat的系统日志
- type: log   
  enabled: true
  paths:
    - /apps/tomcat/logs/localhost_access_log.*.txt 
  fields:
    type: tomcat-accesslog    #收集tomcat的访问日志
filebeat.config.modules:
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false
setup.template.settings:
  index.number_of_shards: 1
setup.kibana:

output.kafka:
  hosts: ["172.16.244.165:9092","172.16.244.166:9092","172.16.244.167:9092"]
  required_acks: 1
  topic: "test-tomcat-app1"    #topic 要写,否则容器中的filebeat进程可能启不来
  compression: gzip
  max_message_bytes: 1000000
#output.redis:
#  hosts: ["172.31.2.105:6379"]
#  key: "k8s-test-app1"
#  db: 1
#  timeout: 5
#  password: "123456"

3.4.2 制作镜像

# cat Dockerfile
#tomcat web1
FROM harbor.k8s.local/k8s/tomcat-base:v8.5.43

ADD catalina.sh /apps/tomcat/bin/catalina.sh
ADD server.xml /apps/tomcat/conf/server.xml
#ADD myapp/* /data/tomcat/webapps/myapp/
ADD app1.tar.gz /data/tomcat/webapps/myapp/
ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh
ADD filebeat.yml /etc/filebeat/filebeat.yml 
RUN chown  -R nginx.nginx /data/ /apps/
#ADD filebeat-7.5.1-x86_64.rpm /tmp/
#RUN cd /tmp && yum localinstall -y filebeat-7.5.1-amd64.deb

EXPOSE 8080 8443

CMD ["/apps/tomcat/bin/run_tomcat.sh"]

# cat run_tomcat.sh
#!/bin/bash
#echo "nameserver 223.6.6.6" > /etc/resolv.conf
#echo "192.168.7.248 k8s-vip.example.com" >> /etc/hosts

/usr/share/filebeat/bin/filebeat -e -c /etc/filebeat/filebeat.yml -path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/filebeat -path.logs /var/log/filebeat &
su - nginx -c "/apps/tomcat/bin/catalina.sh start"
tail -f /etc/hosts

3.4.3 部署新镜像的应用

kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
  labels:
    app: test-tomcat-app1-deployment-label
  name: test-tomcat-app1-deployment
  namespace: test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test-tomcat-app1-selector
  template:
    metadata:
      labels:
        app: test-tomcat-app1-selector
    spec:
      containers:
      - name: test-tomcat-app1-container
        image: harbor.k8s.local/k8s/tomcat-app1:20211030    #更新为新的镜像
        #command: ["/apps/tomcat/bin/run_tomcat.sh"]
        #imagePullPolicy: IfNotPresent
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
          name: http
        env:
        - name: "password"
          value: "123456"
        - name: "age"
          value: "18"
        resources:
          limits:
            cpu: 1
            memory: "512Mi"
          requests:
            cpu: 500m
            memory: "512Mi"
     #   volumeMounts:
     #   - name: test-images
     #     mountPath: /usr/local/nginx/html/webapp/images
     #     readOnly: false
     #   - name: test-static
     #     mountPath: /usr/local/nginx/html/webapp/static
     #     readOnly: false
     # volumes:
     # - name: test-images
     #   nfs:
     #     server: 172.16.244.141
     #     path: /data/k8sdata/images
     # - name: test-static
     #   nfs:
     #     server: 172.16.244.141
     #     path: /data/k8sdata/static
#      nodeSelector:
#        project: test
#        app: tomcat
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: test-tomcat-app1-service-label
  name: test-tomcat-app1-service
  namespace: test
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
    nodePort: 40003
  selector:
    app: test-tomcat-app1-selector
# 进入容器,查看filebeat进程是否起来了
[root@test-tomcat-app1-deployment-8f9fb7686-qdzfb /]# ps -ef | grep filebeat
root           6       1  0 00:24 ?        00:00:00 /usr/share/filebeat/bin/filebeat -e -c /etc/filebeat/filebeat.yml -path.home /usr/share/filebeat -path.config /etc/filebeat -path.data /var/lib/filebeat -path.logs /var/log/filebeat

3.4.4 登陆kafka客户端查看是否有数据上报

https://kafkatool.com/

image-20211030004253174 image-20211030004546325

image-20211030004631274

image-20211030004937121

3.5 部署logstash将kafka数据输出至elasticsearch集群

~# apt install -y openjdk-11-jdk
~# dpkg -i logstash-7.6.2.deb
  • 配置官网文档:

https://www.elastic.co/guide/en/logstash/7.6/index.html

  • 从kafka取数据:

https://www.elastic.co/guide/en/logstash/7.6/plugins-inputs-kafka.html

  • 输出到es:

https://www.elastic.co/guide/en/logstash/7.6/plugins-outputs-elasticsearch.html

~# cd  /etc/logstash/conf.d
~# vim kafka-to-es.conf
input {
  kafka {
    bootstrap_servers => "172.16.244.165:9092,172.16.244.166:9092,172.16.244.167:9092"
    topics => ["test-tomcat-app1","test-tomcat-app2"]
    codec => "json"
  }
}

output {
  if [fields][type] == "tomcat-accesslog" {
    elasticsearch {
      hosts => ["172.16.244.161:9200","172.16.244.162:9200","172.16.244.163:9200"]
      index => "test-tomcat-app1-accesslog-%{+YYYY.MM.dd}"  #让es按天生成索引,后期按天删除清日志,实际配置文件改注释要删除。
    }
  }

  if [fields][type] == "tomcat-catalina" {
    elasticsearch {
      hosts => ["172.16.244.161:9200","172.16.244.162:9200","172.16.244.163:9200"]
      index => "test-tomcat-app1-catalinalog-%{+YYYY.MM.dd}"
    }
  }
#测试时用的,直接输出到标准输出
#  stdout { 
#    codec => rubydebug
#  }
}

# 先测试配置文件语法# /usr/share/logstash/bin/logstash -f kafka-to-es.conf  -t

# 直接启动# /usr/share/logstash/bin/logstash -f kafka-to-es.conf  #二进制启动,占用终端

#systemd启动方式
~# systemctl start logstash.service
  • elasticsearch head 确认是否有输入

image-20211030013333559

image-20211030013510385

3.6 部署kibana并验证数据

要求kibana与es的版本要完全一致

root@logstash1:~# dpkg -i kibana-7.6.2-amd64.deb
root@logstash1:~# vim /etc/kibana/kibana.yml
server.port: 5601
server.host: "172.16.244.164"
elasticsearch.hosts: ["http://172.16.244.161:9200","http://172.16.244.162:9200","http://172.16.244.163:9200"]
i18n.locale: "zh-CN"

root@logstash1:~# systemctl restart kibana.service
image-20211030014716444 image-20211030014743321

image-20211030014804550

image-20211030014832278

image-20211030014852492

image-20211030014944079

image-20211030015351533

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值