如何通过Fluentd将EKS Pod内多路径日志发送至CloudWatch?
下面提供两种可行方案,根据你的场景选择:
方案一:通过主机路径挂载,用节点级Fluentd采集
这种方式让工作节点能访问Pod内的日志目录,再通过集群里的Fluentd DaemonSet(通常是AWS官方的CloudWatch日志采集DaemonSet)进行采集推送。
修改Pod部署配置,挂载日志目录到工作节点
编辑你的Deployment/StatefulSet,为每个需要采集的日志路径添加hostPath类型的卷挂载。示例配置片段:spec: containers: - name: your-app-container image: your-app-image volumeMounts: - name: tomcat-logs mountPath: /opt/tomcat/logs - name: app-logs mountPath: /var/log volumes: - name: tomcat-logs hostPath: path: /var/log/your-app/tomcat type: DirectoryOrCreate # 如果路径不存在自动创建 - name: app-logs hostPath: path: /var/log/your-app/main type: DirectoryOrCreate注意:要确保工作节点上的路径权限允许Pod容器读写,必要时可以设置
securityContext调整容器用户权限。配置节点上的Fluentd采集规则
如果用的是AWS官方的Fluentd DaemonSet(aws-for-fluent-bit或amazon-cloudwatch-logs-for-fluentd),修改其配置文件,添加新的日志采集源:# 采集Tomcat日志 <source> @type tail path /var/log/your-app/tomcat/*.logs pos_file /var/log/fluentd/tomcat-logs.pos tag tomcat.app.logs <parse> @type multiline format_firstline /^\d{4}-\d{2}-\d{2}/ # 根据你的日志格式调整匹配规则 format1 /^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+(?<level>\w+)\s+(?<message>.*)$/ </parse> </source> # 采集应用/var/log下的日志 <source> @type tail path /var/log/your-app/main/*.logs pos_file /var/log/fluentd/app-logs.pos tag app.system.logs <parse> @type regexp format /^(?<time>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z)\s+(?<component>\w+)\s+(?<message>.*)$/ </parse> </source> # 将日志输出到CloudWatch <match tomcat.app.logs app.system.logs> @type cloudwatch_logs log_group_name /aws/eks/your-cluster/app-logs log_stream_name {tag}-{hostname} auto_create_stream true region us-east-1 # 替换为你的集群区域 </match>重启Fluentd DaemonSet让配置生效。
方案二:使用Fluentd Sidecar容器直接推送
这种方式无需依赖节点级采集,直接在Pod内部署Fluentd Sidecar,共享主容器的日志目录后直接推送到CloudWatch。
添加Sidecar容器到Pod配置
编辑Deployment/StatefulSet,添加Fluentd Sidecar,并用emptyDir或直接挂载主容器的日志目录(确保Sidecar能访问到)。示例配置片段:spec: serviceAccountName: fluentd-cloudwatch-sa # 绑定了CloudWatch权限的SA containers: - name: your-app-container image: your-app-image volumeMounts: - name: app-logs mountPath: /opt/tomcat/logs - name: system-logs mountPath: /var/log - name: fluentd-sidecar image: amazon/aws-for-fluent-bit:latest # 用AWS优化的镜像更省心 volumeMounts: - name: app-logs mountPath: /opt/tomcat/logs - name: system-logs mountPath: /var/log - name: fluentd-config mountPath: /fluent-bit/etc/ volumes: - name: app-logs emptyDir: {} # 共享存储,主容器写入的日志Sidecar可读取 - name: system-logs emptyDir: {} - name: fluentd-config configMap: name: fluentd-sidecar-config配置Sidecar的Fluentd规则
创建ConfigMap存储Fluentd配置:apiVersion: v1 kind: ConfigMap metadata: name: fluentd-sidecar-config data: fluent-bit.conf: | [SERVICE] Flush 1 Log_Level info [INPUT] Name tail Path /opt/tomcat/logs/*.logs Tag tomcat.sidecar.logs Parser tomcat-log Refresh_Interval 5 [INPUT] Name tail Path /var/log/*.logs Tag app.sidecar.logs Parser app-log Refresh_Interval 5 [PARSER] Name tomcat-log Format regex Regex /^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+(?<level>\w+)\s+(?<message>.*)$/ Time_Key time Time_Format %Y-%m-%d %H:%M:%S [PARSER] Name app-log Format regex Regex /^(?<time>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z)\s+(?<component>\w+)\s+(?<message>.*)$/ Time_Key time Time_Format %Y-%m-%dT%H:%M:%SZ [OUTPUT] Name cloudwatch Match * region us-east-1 log_group_name /aws/eks/your-cluster/sidecar-app-logs log_stream_name {tag}-{pod_name} auto_create_group true配置IAM权限(IRSA)
创建一个IAM角色,授予logs:CreateLogGroup、logs:CreateLogStream、logs:PutLogEvents权限,然后通过IRSA绑定到Pod使用的ServiceAccount(fluentd-cloudwatch-sa),避免使用节点IAM角色的宽权限。
注意事项
- 方案一需要确保主机路径不会被多个Pod冲突覆盖,建议在hostPath路径中加入Pod名称或命名空间变量(比如
/var/log/your-app/{{.Release.Namespace}}/{{.Pod.Name}},如果用Helm部署)。 - 方案二要注意Sidecar的资源占用,合理设置
resources.requests和resources.limits,避免影响主容器运行。 - 两种方案都要考虑日志轮转,确保Fluentd能正确读取轮转后的日志文件(Fluentd的tail插件默认支持追踪inode变化)。
内容的提问来源于stack exchange,提问作者Anvesh Muppeda

