热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

efk使用心得之自动化工具编写

efk入门篇(四

 先回顾下上一篇 最佳实践,简要的介绍了下如何用最佳的实践来收集日志,但我们可以发现,如果没有一个工具来辅助的话,要实施起来会比较依赖于”人工智能“,而一个强有力的工具辅助我们的日志运维是很有必要的,而也这是本篇要着重介绍的。


前言


笔者在实践中,也是深深的感受到了不统一或是不规范带来的一系列苦恼。而在之前几篇文章中,我们为统一和规范做了很多探索,而要实现这一步骤的前提是必须要有一个工具来辅助。那这个工具需要为我们做些什么呢?大体上需要如下这么几个东西:

  1. 通过一个指令初始化通用模板,角色账号与一些通用的ingest pipeline

  2. 通过一个指令快速的创建一个索引,需要包含索引生命周期策略,并自动把生命周期策略应用到索引上,同时还需要自动创建出kibana上与该索引关联的index-pattern,同时还需要自动创建出filebeat用于收集该索引日志的yml文件

  3. 通过一个指令将filebeat的yml文件推送到指定服务器


01

初始化操作


通过执行这个指令,可以创建出系统层面比较通用的一些设置。比如全局模板,用户角色,ingest pipeline,甚至是其他将会应用到的一些设置。这个没什么好说的。为此我们需要一个es shell 脚本:

    #!/bin/bash
    URL=$1
    USERNAME=$2
    PASSWORD=$3
    VARI_ABLE=$4
    FLAG=$5
    CURL_LOG='tempfile'
    API_NAME=''
    JSON_FILENAME="${VARI_ABLE}"


    function pipeline(){
    API_NAME="_ingest/pipeline/${VARI_ABLE}"
    _execute
    }


    function template(){
    API_NAME="_template/${VARI_ABLE}"
        _execute
    }


    function policy(){
    API_NAME="_ilm/policy/${VARI_ABLE}"
    JSON_FILENAME='policy'
       _execute
    }


    function _execute(){
    httpcode=$(curl -k --cacert cert/elastic-ca.pem -H'Content-Type: application/json' -H'WWW-Authenticate:Basic realm=security charset=UTF-8' -s -u ${USERNAME}:${PASSWORD} -XPUT ${URL}/${API_NAME} -d "@template/${JSON_FILENAME}.json" -w %{http_code} -o "$CURL_LOG")
    #echo "$httpcode"
    if [ "$httpcode" = "200" ]; then
    rm "$CURL_LOG"
    exit 1
    else
    cat "$CURL_LOG" > dev/stderr
    rm "$CURL_LOG"
    fi
    }


    if [ "$FLAG" = "pipeline" ]; then
    pipeline
    elif [ "$FLAG" = "template" ]; then
    template
    elif [ "$FLAG" = "policy" ]; then
    policy
    else
    echo "invalid parameter"
    fi

    只需要准备好对应的json文件便可以执行对应的策略

    还需要一个kibana shell 脚本:

      #!/bin/bash


      URL=$1
      USERNAME=$2
      PASSWORD=$3
      INDEXPATTERN=$4
      FLAG=$5


      function create(){
      curl -k --cacert cert/elastic-ca.pem -H'Content-Type: application/json' -H'kbn-xsrf: true' -s -u ${USERNAME}:${PASSWORD} -XPOST ${URL}/api/saved_objects/index-pattern/${INDEXPATTERN}?overwrite=true -d'
      {
      "attributes":
      {
      "title": "'"$INDEXPATTERN"'",
      "timeFieldName": "@timestamp"
      }
      }
      '
      }


      function delete(){
      curl -k --cacert cert/elastic-ca.pem -H'Content-Type: application/json' -H'kbn-xsrf: true' -s -u ${USERNAME}:${PASSWORD} -XDELETE ${URL}/api/saved_objects/index-pattern/${INDEXPATTERN}
      }


      if [ "$FLAG" = "create" ]; then
      create
      elif [ "$FLAG" = "delete" ]; then
      delete
      else
      echo "invalid parameter"
      fi

      02


      创建索引


      这个指令是核心。试想在完全依赖”人工智能“的场景下,运维上到服务器后,手动增加一个文件目录监听后,做个重启,再接着去创建kibana index-pattern,如果不运用索引生命周期管理,可能就此结束了。那有人会疑问了,索引怎么删除的呢?依赖一个定时器,定时对超过一定时间范围的索引做删除!这是一个真实的故事。当然了,这样做有一定的可行性,但并不推荐。因而创建索引的指令,必须把依赖”人工智能“的这个过程自动化掉。在结合索引生命周期管理,把整个流程需要的设置项都设置出来,这样就很完美了。下面是创建索引关键代码:

        public static async Task CreateIndexAsync(IndexDto dto)
        {
        var stuffix = dto.Environment + "-" + dto.IndexName;
        //别名
        var aliasName = stuffix + "-alias";
        //策略
        var policyId = stuffix + "-policy";
        //模板
        var templateName = stuffix + "-template";
        //索引名
        var indexName = dto.RollUpType == 0 ? "<" + stuffix + "-{now/d}-1>" : stuffix + "-000001";
        // kibana index-pattern
        var kibanaIndexPattern = stuffix + "-*";


        //1.先创建策略
        var getlifecycleRequest = new GetLifecycleRequest(policyId);
        var lifeCycleGetRespOnse= await EsClient.Client.IndexLifecycleManagement.GetLifecycleAsync(getlifecycleRequest);
        if (lifeCycleGetResponse.ApiCall.HttpStatusCode == 404)
          {
        var result = await EsScriptClient.ExecutePolicyAsync(new PolicyDto(policyId));
        if (!result.Item1)
        {
        LogCenterManager.Log(LogLevel.Error, $"索引生命周期策略 { policyId} 创建失败,返回响应值:{result.Item2}", nameof(CreateIndexAsync));
        return;
              }
              LogCenterManager.Log(LogLevel.Info, $"索引生命周期策略 {policyId} 创建成功"nameof(CreateIndexAsync));     
          }
        //2.先创建模板,优先级为1,高于通用模板
        var indexExistsTemplateRequest = new IndexTemplateExistsRequest(templateName);
        if (!(await EsClient.Client.Indices.TemplateExistsAsync(indexExistsTemplateRequest)).Exists)
        {
        var putIndexTemplateRequest = new PutIndexTemplateRequest(templateName)
        {
                  Order = 1,
        IndexPatterns = new[] { $"{stuffix}-*" },
        Settings = new IndexSettings(new Dictionary<string, object>
        {
        {"lifecycle.name", policyId},
        {"lifecycle.rollover_alias", aliasName}
        })
        };
        var putTemplateRespOnse= await EsClient.Client.Indices.PutTemplateAsync(putIndexTemplateRequest);
        if (!putTemplateResponse.IsValid)
        {
        LogCenterManager.Log(LogLevel.Error, $"索引模板 {templateName} 创建失败", nameof(CreateIndexAsync), putTemplateResponse.OriginalException);
        return;
                }
        LogCenterManager.Log(LogLevel.Info, $"索引模板 {templateName} 创建成功,应用 lifecycle.name:{policyId},lifecycle.rollover_alias:{aliasName}", nameof(CreateIndexAsync));
            }
        //3.创建初始写索引
        if (!(await EsClient.Client.Indices.ExistsAsync(indexName)).Exists)
        {
             var createIndexResponse = await EsClient.Client.Indices.CreateAsync(indexName, request =>
        {
        return request.Aliases(aliases => aliases.Alias(aliasName, alias => alias.IsWriteIndex()));
        });
        if (!createIndexResponse.IsValid)
        {
        LogCenterManager.Log(LogLevel.Error, $"索引 {indexName} 创建失败", nameof(CreateIndexAsync), createIndexResponse.OriginalException);
        return;
        }
            }
        //4.创建kibana index-pattern
        var createKibanaIndexPatternRespOnse= await KibanaClient.CreateIndexPatternAsync(new IndexPatternDto(kibanaIndexPattern, dto.Flag));
        if (!createKibanaIndexPatternResponse.Item1)
        {
        LogCenterManager.Log(LogLevel.Error, $"kibana index-pattern {kibanaIndexPattern} 失败,返回响应值:{createKibanaIndexPatternResponse.Item2}", nameof(CreateIndexAsync));
        return;
          }
        //5.生成 filebeat 配置文件
        var filebeatInputFile = Path.Combine(Consts.FilebeatOutputFilePath, dto.IndexName + ".yml");
        var cOntents= await File.ReadAllTextAsync(Consts.FilebeatFilePath, Encoding.UTF8);
        cOntents= contents
        .Replace("${current_path}", filebeatInputFile)
        .Replace("${create_time}", DateTime.Now.ToString("yyyy-MM-dd"))
        .Replace("${log_type}", dto.IndexName)
        .Replace("${logName}", dto.IndexName.Replace("-", "."))
        .Replace("${source}", dto.IndexName.Split('-')[0]);


        await File.WriteAllTextAsync(filebeatInputFile, contents);


        LogCenterManager.Log(LogLevel.Info, Environment.NewLine + contents + Environment.NewLine + Environment.NewLine + $"索引 {dto.IndexName} 创建成功,{dto.IndexName}.yml 文件可以试着手动进行二次确认,内容如上,没问题的话,可执行 -push 命令往服务器推送", nameof(CreateIndexAsync));
        }

        创建索引会用上面的shell脚本


        03


        文件推送


        为什么这里会需要这样一个指令呢?这个指令主要是用来自动将编辑好的yml文件自动上传到filebeat监听的目录中,是一种简单便捷指令,当然不提供也是没有问题的,只是运维要清楚该如何放置文件即可。而这个文件内容如下:

          # 自动生成
          # ${current_path} ${create_time}
          - type: log
          enabled: true
          paths:
              - /var/logs/${logName}/*.log
          fields_under_root: true
          fields:
          log_type: ${log_type}
               source${source}
          json.keys_under_root: true
          json.overwrite_keys: true
          json.add_error_key: false
            json.message_key: 'message'
          multiline.pattern: '^\{"date":"\d{4}-\d{1,2}-\d{1,2}'
          multiline.negate: true
            multiline.match: after

          通过”创建索引“将上述变量进行逐一替换,一个用于filebeat监听的yml文件就已经准备好了,只需要对这个文件进行一些微调,即可使用。比如我们的应用都是部署在linux上,那我们可以用如下脚本来实现简单的文件推送需求:

            #!/bin/bash
            USERNAME=$1
            SOURCENAME=$2
            TARGETNAME=$3
            TARGETFILE="/usr/local/filebeat/input.d"
            ssh ${USERNAME} "mkdir ${TARGETFILE}"
            scp template/output/${SOURCENAME}.yml ${USERNAME}:${TARGETFILE}/${TARGETNAME}.yml
            r=$?
            if [ "$r" = 0 ]; then
            echo "success"
            else
            echo "error:$r"
            fi


            写在最后


            本文主要详细介绍了下制作自动化工具的几个核心步骤,文中也贴出了主要关键代码,通过分析来看,其实就是将我们日常中需要手动完成的步骤通过工具来做而已,并没有用到特别高深隐晦的技术。不过还是那句话,看懂和动手真的是两码事,聪明如你,动起手来吧!下一篇将会介绍下filebeat中的设置项。


            如有收获,点个在看,诚挚感





            推荐阅读
            • Python操作MySQL(pymysql模块)详解及示例代码
              本文介绍了使用Python操作MySQL数据库的方法,详细讲解了pymysql模块的安装和连接MySQL数据库的步骤,并提供了示例代码。内容涵盖了创建表、插入数据、查询数据等操作,帮助读者快速掌握Python操作MySQL的技巧。 ... [详细]
            • 从Oracle安全移植到国产达梦数据库的DBA实践与攻略
              随着我国对信息安全和自主可控技术的重视,国产数据库在党政机关、军队和大型央企等行业中得到了快速应用。本文介绍了如何降低从Oracle到国产达梦数据库的技术门槛,保障用户现有业务系统投资。具体包括分析待移植系统、确定移植对象、数据迁移、PL/SQL移植、校验移植结果以及应用系统的测试和优化等步骤。同时提供了移植攻略,包括待移植系统分析和准备移植环境的方法。通过本文的实践与攻略,DBA可以更好地完成Oracle安全移植到国产达梦数据库的工作。 ... [详细]
            • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
            • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
              本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
            • Centos7.6安装Gitlab教程及注意事项
              本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
            • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
            • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
              本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
            • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
            • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
            • web.py开发web 第八章 Formalchemy 服务端验证方法
              本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
            • 31.项目部署
              目录1一些概念1.1项目部署1.2WSGI1.3uWSGI1.4Nginx2安装环境与迁移项目2.1项目内容2.2项目配置2.2.1DEBUG2.2.2STAT ... [详细]
            • PDO MySQL
              PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
            • 移动端常用单位——rem的使用方法和注意事项
              本文介绍了移动端常用的单位rem的使用方法和注意事项,包括px、%、em、vw、vh等其他常用单位的比较。同时还介绍了如何通过JS获取视口宽度并动态调整rem的值,以适应不同设备的屏幕大小。此外,还提到了rem目前在移动端的主流地位。 ... [详细]
            • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
            • 本文讨论了在使用PHP cURL发送POST请求时,请求体在node.js中没有定义的问题。作者尝试了多种解决方案,但仍然无法解决该问题。同时提供了当前PHP代码示例。 ... [详细]
            author-avatar
            手机用户2602897765
            这个家伙很懒,什么也没留下!
            PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
            Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有