亚马逊AWS官方博客

在 EKS 中使用 Fluent Bit 收集应用日志并保存到 S3 中的方案

概述

AWS容器服务团队在2020年10月发布了Fluent Bit supports Amazon S3 as a destination to route container logs 功能,集成在 fluent/fluent-bit:1.6.0和amazon/aws-for-fluent-bit:2.8.0 镜像中。EKS用户可以通过Fluent Bit将应用日志保存在 Amazon S3 中, S3 是面向互联网的存储服务,您可以使用 Amazon S3 随时在 Web 上的任何位置保存和取回任何数量的数据。您可以使用简单而直观的 Web 界面 AWS 管理控制台来完成这些任务。

存放在Amazon S3中的数据,可以采用Amazon Athena进行查询。Amazon Athena 是一种交互式查询服务,让您能够轻松使用标准 SQL 分析 Amazon S3 中的数据。Athena 没有服务器,因此您无需管理任何基础设施,且只需为您查询时扫描的数据量付费。

Fluent Bit 介绍

Fluent Bit是一种快速和轻量的日志处理器,支持Linux,OSX,Windows和BSD操作系统。Amazon S3插件支持收集日志保存到Amazon S3中,日志上传时,支持multipart upload API或PutObject API。Multipart upload 允许将一个对象进行分段上传,好处是提高网络的吞吐量和快速从网络中断中恢复。

 

在 EKS 中 Fluent Bit 的配置

整个测试环境部署在AWS BJS Region,预先配置了VPC,EKS Cluster,EKS Nodegroup和VPC Endpoint-S3 Gateway,其中EKS Cluster的名称是eks-bjs,EKS Nodegroup 放在 private subnet 中,采用 EC2 instance 的模式。架构示意图如下:

FluentBit做为DaemonSet的方式部署在EKS Node上,具体操作步骤中需要使用awscli,eksctl和kubectl 软件,安装说明见:https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html#eksctl-prereqs

具体操作步骤如下:

1.创建S3 bucket,比如fluent-bit-s3-test。在实际操作中,需将 fluent-bit-s3-test 替换为自有的 bucketName。

2.创建 iamserviceaccount

3.创建测试用的 testapp

4.创建 fluent bit config

5.创建 fluent bit daemonset

6.查看 fluent bit 日志,查看在s3中保存的日志

7.使用 Athena 查询日志

 

1.创建S3 bucket

可采用下面AWS Cli命令进行创建S3 bucket

aws s3 mb s3://fluent-bit-s3-test --region cn-north-1

 

2.创建iamserviceaccount

FluentBit在将日志上传到S3时,需要S3的 PutObject 权限。

需要执行下面指令,创建 iamserviceaccount,进行授权。

cat <<EOF > s3-putobject-iam-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws-cn:s3:::fluent-bit-s3-test/*"
        }
     ]
}
EOF
 
aws iam create-policy --policy-name S3PutObjectPolicy --policy-document file://./s3-putobject-iam-policy.json --region cn-north-1
 
POLICY_NAME=$(aws iam list-policies --query 'Policies[?PolicyName==` S3PutObjectPolicy`].Arn' --output text --region cn-north-1)
 
eksctl utils associate-iam-oidc-provider --cluster=eks-bjs --approve --region cn-north-1
 
eksctl create iamserviceaccount \
       --cluster=eks-bjs \
       --region cn-north-1 \
       --namespace=default \
       --name=s3-putobject \
       --attach-policy-arn=${POLICY_NAME} \
       --override-existing-serviceaccounts \
       --approve

 

3.创建测试用的testapp

在测试 testapp 中,运行一个简单shell脚本,生成日志文件,并将日志文件保存在宿主机的/data/logs目录,每个pod生成的日志文件名为 test-<POD_NAME>.log

测试 testapp 的 yml 文件如下:

cat <<'EOF' > testapp.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
  labels:
    app: test
spec:
  selector:
    matchLabels:
      app: test
  replicas: 4
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - name: createlog
        image: busybox
        imagePullPolicy: Always
        command: [ "sh", "-c"]
        args:
        - i=0;
          while true; 
            do
              echo "[`date +%Y/%m/%d-%H:%M:%S`]"+$i+$HOSTNAME >> /data/logs/test-$HOSTNAME.log;
              let i=i+1; 
              sleep 2;
            done
        volumeMounts:
        - name: logs
          mountPath: /data/logs
      volumes:
      - name: logs
        hostPath:
          path: /data/logs
EOF

 

 

安装testapp的命令如下:

kubectl apply -f testapp.yml

 

其中createlog容器的输出日志格式如下:

[2020/11/12-02:58:37]+103+test-deployment-6db76c8fff-j6hhs

 

4.创建fluent bit config

fluent bit config的示例如下:

其中[INPUT] Path /data/logs/test*.log对应测试testapp的日志保存地址,fluent bit将该目录中test*.log文件中的日志内容保存到S3中。

[OUTPUT]中的total_file_size参数是设定S3日志文件的最大尺寸,upload_timeout 参数是设定每次上传日志文件的最大间隔时间。详细参数说明见:https://docs.fluentbit.io/manual/pipeline/outputs/s3

cat <<EOF > fluentbit-config-s3.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentbit-config
  labels:
    k8s-app: fluentbit
data:
# Configuration files: server, input, filters and output
# ======================================================
  fluentbit.conf: |
    [SERVICE]
        Flush         1
        Log_Level     info
        Daemon        off

    [INPUT]
        Name              tail
        Tag               test-log
        Path              /data/logs/test*.log
        DB                /var/log/testlog.db
        Mem_Buf_Limit     5MB
        Skip_Long_Lines   On
        Refresh_Interval  10 

    [OUTPUT]
        Name                          s3
        Match                         test-log
        bucket                        fluent-bit-s3-test
        region                        cn-north-1
        store_dir                     /home
        total_file_size               10M
        upload_timeout                1m
        s3_key_format                 /fluentbit-logs/test-log/year=%Y/month=%m/day=%d/%H-%M-%S
EOF

 

安装 fluent bit config 的命令如下:

kubectl apply -f fluentbit-config-s3.yml

 

5. 创建fluent bit daemonset

fluent bit daemonset的示例如下:

其中需要配置serviceAccountName: s3-putobject

cat <<EOF > fluentbit-daemonset.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
    name: fluentbit
    labels:
        k8s-app: fluentbit
        version: v8
        kubernetes.io/cluster-service: "true"
spec:
    selector:
        matchLabels:
          k8s-app: fluentbit
          version: v1
    updateStrategy:
        type: RollingUpdate
    template:
        metadata:
            labels:
                k8s-app: fluentbit
                version: v1
                kubernetes.io/cluster-service: "true"
        spec:
            containers:
              - name: fluentbit
                image: fluent/fluent-bit:1.6.0
                imagePullPolicy: Always
                command: ["/fluent-bit/bin/fluent-bit","-c", "/fluent-bit/etc/fluentbit.conf"]
                env:
                - name: NODE_NAME
                  valueFrom:
                    fieldRef:
                        fieldPath: spec.nodeName
                - name: MY_POD_NAME
                  valueFrom:
                    fieldRef:
                        fieldPath: metadata.name
                - name: MY_POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                        fieldPath: metadata.namespace
                - name: MY_POD_IP
                  valueFrom:
                    fieldRef:
                        fieldPath: status.podIP
                resources:
                    requests:
                        cpu: 5m
                        memory: 20Mi
                    limits:
                        cpu: 60m
                        memory: 60Mi
                volumeMounts:
                - name: varlog
                  mountPath: /var/log
                - name: logs
                  mountPath: /data/logs
                  readOnly: true
                - name: fluentbit-config
                  mountPath: /fluent-bit/etc/
            serviceAccountName: s3-putobject
            terminationGracePeriodSeconds: 10
            volumes:
                - name: varlog
                  hostPath:
                    path: /var/log
                - name: logs
                  hostPath:
                    path: /data/logs
                - name: fluentbit-config
                  configMap:
                    name: fluentbit-config
EOF

 

 

安装fluent bit daemonset的命令如下:

kubectl apply -f fluentbit-daemonset.yml

 

6.查看fluent bit日志,查看在s3中保存的日志

查看fluent bit pod是否运行正常,命令如下:

kubectl get pod

下面是命令的返回结果,可以看到fluentbit-*是Running状态。

查看fluent bit pod的日志,命令如下:

kubectl logs -l k8s-app=fluentbit

下面是命令的返回结果,无错误输出。

查看S3 Bucket(fluent-bit-s3-test)是否有fluent bit上传的日志文件,命令如下:

aws s3 ls s3://fluent-bit-s3-test/fluentbit-logs/test-log/ --recursive --region cn-north-1

返回结果如下,已经存在日志文件。

下载日志文件,得到的日志内容如下:

7.使用Athena查询日志

登陆AWS Console,进入Athena服务,链接为https://console.amazonaws.cn/athena/home?region=cn-north-1#query

在右上角Settings中,设置Query result location。

在左上角Query editor中,在New query 1中,执行下面的语句创建test_logs表:

CREATE EXTERNAL TABLE `default`.`test_logs`(
   `date` string, 
   `timestamp` string, 
   `no` string, 
   `pod_name` string)
   PARTITIONED BY (year int,month int,day int)
   ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' 
   WITH SERDEPROPERTIES ( 
     'input.regex'='\\{\"date\":\"([^ ]*)\",\"log\":\"([^ ]*)\\+([0-9]*)\\+([^ ]*)\"\\}') 
   STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' 
   OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
   LOCATION 's3://fluent-bit-s3-test/fluentbit-logs/test-log/'
   TBLPROPERTIES ('has_encrypted_data'='false')

 

 

然后在New query 2中,执行下面语句,更新table的partition信息

MSCK REPAIR TABLE default.test_logs;

 

在New query 3中,执行下面语句,查询日志

select * from default.test_logs limit 10;

下面是执行结果

结论

在这篇文章中,介绍了如何通过Fluent Bit收集EKS中的应用日志并保存在S3中和通过Athena查询日志数据。Amazon S3是无服务器架构的存储服务,存储文件的性价比高,同时S3有99.999999999%的数据持久性,Amazon Athena也是无服务器架构的查询服务,是基于扫描数据量来收费,支持标准SQL查询。总体方案具有高性价比,高数据持久性,维护容易等特点。

 

参考资料

本篇作者

薛召兵

AWS解决方案架构师,负责帮助客户进行上云架构的设计和咨询。同时致力于AWS容器服务、媒体服务和机器学习服务在国内和全球商业客户的应用和推广,推进企业服务迁移上云进程。有10年以上的软件开发、售前技术支持、系统架构设计等经验。