使用日志服務(wù)收集Spark作業(yè)日志
在ACK集群中運(yùn)行Spark作業(yè)時會生成大量的日志分散在不同的Pods中,導(dǎo)致日志管理變得困難。您可以通過日志服務(wù)(SLS)提供的一站式的日志采集、加工、查詢與分析、可視化和告警等能力,實(shí)現(xiàn)對Spark日志的高效管理。本文將介紹如何使用日志服務(wù)(SLS)對運(yùn)行在ACK集群中的Spark作業(yè)日志進(jìn)行管理。
前提條件
已部署ack-spark-operator組件,請參見部署ack-spark-operator組件。
已經(jīng)創(chuàng)建日志服務(wù)(SLS) Project,請參見管理Project。
已安裝Logtail組件,請參見安裝Logtail組件(阿里云Kubernetes集群)。
流程概述
本文將引導(dǎo)您完成如下步驟,幫助您了解如何配置SLS以管理Spark作業(yè)產(chǎn)生的系統(tǒng)日志和業(yè)務(wù)日志。
構(gòu)建Spark容器鏡像:構(gòu)建包含了log4j JSON template layout依賴的Spark容器鏡像,并推送到您的鏡像倉庫中。
配置Log4j2日志:創(chuàng)建一個ConfigMap資源,用于配置Log4j2日志,設(shè)定日志級別為INFO,并將日志打印格式設(shè)定為JSONL格式。
創(chuàng)建Logtail配置:創(chuàng)建一個AliyunConfig資源,日志服務(wù)將相應(yīng)地在指定的日志庫中創(chuàng)建Logtail采集配置,對通過Spark operator提交的Spark作業(yè)日志進(jìn)行收集。
提交示例Spark作業(yè):創(chuàng)建并運(yùn)行示例Spark作業(yè),查看pod日志輸出是否為JSONL格式,并對部分字段含義進(jìn)行說明。
查詢和分析Spark日志:登錄SLS控制臺,查詢和分析指定時間段內(nèi)的Spark作業(yè)日志。
(可選)環(huán)境清理:在完成測試后,清理無需使用的Spark作業(yè)和資源,避免產(chǎn)生額外的費(fèi)用。
步驟一:構(gòu)建Spark容器鏡像
創(chuàng)建如下Dockerfile(本示例使用Spark 3.5.3版本),并將所需的依賴項(xiàng)添加到Spark的類路徑中。構(gòu)建完成后,將該鏡像推送到您的鏡像倉庫。為了方便日志的收集和解析,我們將采用JSONL格式輸出日志。
ARG SPARK_IMAGE=<SPARK_IMAGE> # 需要將<SPARK_IMAGE>替換成您自己的Spark基礎(chǔ)鏡像。
FROM ${SPARK_IMAGE}
# Add dependency for log4j-layout-template-json
ADD --chown=spark:spark --chmod=644 https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-layout-template-json/2.24.1/log4j-layout-template-json-2.24.1.jar ${SPARK_HOME}/jars
步驟二:配置Log4j2日志
使用如下內(nèi)容創(chuàng)建一個名為spark-log-conf.yaml
的文件,并將日志級別設(shè)定為INFO,同時配置日志打印格式為JSONL格式,日志模板采用Elastic Common Schema(ECS),一種標(biāo)準(zhǔn)化的日志格式。有關(guān)更多配置請參見采集Log4j日志。
apiVersion: v1
kind: ConfigMap
metadata:
name: spark-log-conf
namespace: default
data:
log4j2.properties: |
# Set everything to be logged to the console and file
rootLogger.level = info
rootLogger.appenderRefs = console, file
rootLogger.appenderRef.console.ref = STDOUT
rootLogger.appenderRef.file.ref = FileAppender
appender.console.name = STDOUT
appender.console.type = Console
appender.console.layout.type = JsonTemplateLayout
appender.console.layout.eventTemplateUri = classpath:EcsLayout.json
appender.file.name = FileAppender
appender.file.type = File
appender.file.fileName = /opt/spark/logs/spark.log
appender.file.layout.type = JsonTemplateLayout
appender.file.layout.eventTemplateUri = classpath:EcsLayout.json
執(zhí)行如下命令創(chuàng)建ConfigMap資源。
kubectl apply -f spark-log-conf.yaml
預(yù)期輸出:
configmap/spark-log-conf created
步驟三:創(chuàng)建Logtail配置
使用如下內(nèi)容創(chuàng)建一個名為aliyun-log-config.yaml
的AliyunLogConfig清單文件,并在其中替換<SLS_PROJECT>
為您的SLS Project的名稱,<SLS_LOGSTORE>
為您的SLS Logstore名稱。有關(guān)更多配置選項(xiàng)請參見使用AliyunLogConfig管理采集配置。
apiVersion: log.alibabacloud.com/v1alpha1
kind: AliyunLogConfig
metadata:
name: spark
namespace: default
spec:
# (可選)目標(biāo)project名稱(默認(rèn)為 k8s-log-<Your_Cluster_ID>)
project: <SLS_PROJECT>
# Logstore 名稱。如果您所指定的Logstore不存在,日志服務(wù)會自動創(chuàng)建。
logstore: <SLS_LOGSTORE>
# iLogtail采集配置。
logtailConfig:
# 采集配置名稱。
configName: spark
# 數(shù)據(jù)源類型,file表示文本日志
inputType: file
# 日志輸入的相關(guān)配置。
inputDetail:
# 日志文件所在目錄。
logPath: /opt/spark/logs
# 日志文件名稱,支持通配符。
filePattern: '*.log'
# 日志文件編碼。
fileEncoding: utf8
# 日志類型。
logType: json_log
localStorage: true
key:
- content
logBeginRegex: .*
logTimezone: ''
discardNonUtf8: false
discardUnmatch: true
preserve: true
preserveDepth: 0
regex: (.*)
outputType: LogService
topicFormat: none
adjustTimezone: false
enableRawLog: false
# 采集容器中的文本日志。
dockerFile: true
# 高級配置。
advanced:
# 容器元信息預(yù)覽。
collect_containers_flag: true
# Kubernetes采集配置。
k8s:
# 按照標(biāo)簽過濾Pod。
IncludeK8sLabel:
sparkoperator.k8s.io/launched-by-spark-operator: "true"
# 按照容器名稱過濾容器。
K8sContainerRegex: "^spark-kubernetes-(driver|executor)$"
# 額外的日志標(biāo)簽配置。
ExternalK8sLabelTag:
spark-app-name: spark-app-name
spark-version: spark-version
spark-role: spark-role
spark-app-selector: spark-app-selector
sparkoperator.k8s.io/submission-id: sparkoperator.k8s.io/submission-id
# 日志處理插件。
plugin:
processors:
# 日志分隔。
- type: processor_split_log_string
detail:
SplitKey: content
SplitSep: ''
# 字段JSON解析。
- type: processor_json
detail:
ExpandArray: false
ExpandConnector: ''
ExpandDepth: 0
IgnoreFirstConnector: false
SourceKey: content
KeepSource: false
KeepSourceIfParseError: true
NoKeyError: false
UseSourceKeyAsPrefix: false
# 日志時間戳提取。
- type: processor_strptime
detail:
SourceKey: '@timestamp'
Format: '%Y-%m-%dT%H:%M:%S.%fZ'
KeepSource: false
AdjustUTCOffset: true
UTCOffset: 0
AlarmIfFail: false
執(zhí)行如下命令創(chuàng)建Logtail配置。
kubectl apply -f aliyun-log-config.yaml
您可以按照以下步驟查看新建的日志庫和Logtail配置。
登錄日志服務(wù)控制臺。
在Project列表區(qū)域,單擊目標(biāo)Project。
在 頁簽中,單擊目標(biāo)日志庫前面的>,依次選擇 。
單擊目標(biāo)Logtail采集配置,查看Logtail采集配置詳情。
步驟四:提交示例Spark作業(yè)
使用以下內(nèi)容創(chuàng)建一個名為spark-pi.yaml
的SparkApplication清單文件。
apiVersion: sparkoperator.k8s.io/v1beta2
kind: SparkApplication
metadata:
name: spark-pi
namespace: default
spec:
type: Scala
mode: cluster
image: <SPARK_IMAGE>
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: local:///opt/spark/examples/jars/spark-examples_2.12-3.5.3.jar
arguments:
- "5000"
sparkVersion: 3.5.3
sparkConfigMap: spark-log-conf
driver:
cores: 1
memory: 512m
serviceAccount: spark-operator-spark
executor:
instances: 1
cores: 1
memory: 4g
執(zhí)行如下命令提交作業(yè)。
kubectl apply -f spark-pi.yaml
等待作業(yè)執(zhí)行結(jié)束后,查看Driver Pod日志的最后10行。
kubectl logs --tail=10 spark-pi-driver
預(yù)期輸出:
{"@timestamp":"2024-11-20T11:45:48.487Z","ecs.version":"1.2.0","log.level":"WARN","message":"Kubernetes client has been closed.","process.thread.name":"-937428334-pool-19-thread-1","log.logger":"org.apache.spark.scheduler.cluster.k8s.ExecutorPodsWatchSnapshotSource"}
{"@timestamp":"2024-11-20T11:45:48.585Z","ecs.version":"1.2.0","log.level":"INFO","message":"MapOutputTrackerMasterEndpoint stopped!","process.thread.name":"dispatcher-event-loop-7","log.logger":"org.apache.spark.MapOutputTrackerMasterEndpoint"}
{"@timestamp":"2024-11-20T11:45:48.592Z","ecs.version":"1.2.0","log.level":"INFO","message":"MemoryStore cleared","process.thread.name":"main","log.logger":"org.apache.spark.storage.memory.MemoryStore"}
{"@timestamp":"2024-11-20T11:45:48.592Z","ecs.version":"1.2.0","log.level":"INFO","message":"BlockManager stopped","process.thread.name":"main","log.logger":"org.apache.spark.storage.BlockManager"}
{"@timestamp":"2024-11-20T11:45:48.596Z","ecs.version":"1.2.0","log.level":"INFO","message":"BlockManagerMaster stopped","process.thread.name":"main","log.logger":"org.apache.spark.storage.BlockManagerMaster"}
{"@timestamp":"2024-11-20T11:45:48.598Z","ecs.version":"1.2.0","log.level":"INFO","message":"OutputCommitCoordinator stopped!","process.thread.name":"dispatcher-event-loop-1","log.logger":"org.apache.spark.scheduler.OutputCommitCoordinator$OutputCommitCoordinatorEndpoint"}
{"@timestamp":"2024-11-20T11:45:48.602Z","ecs.version":"1.2.0","log.level":"INFO","message":"Successfully stopped SparkContext","process.thread.name":"main","log.logger":"org.apache.spark.SparkContext"}
{"@timestamp":"2024-11-20T11:45:48.604Z","ecs.version":"1.2.0","log.level":"INFO","message":"Shutdown hook called","process.thread.name":"shutdown-hook-0","log.logger":"org.apache.spark.util.ShutdownHookManager"}
{"@timestamp":"2024-11-20T11:45:48.604Z","ecs.version":"1.2.0","log.level":"INFO","message":"Deleting directory /var/data/spark-f783cf2e-44db-452c-83c9-738f9c894ef9/spark-2caa5814-bd32-431c-a9f9-a32208b34fbb","process.thread.name":"shutdown-hook-0","log.logger":"org.apache.spark.util.ShutdownHookManager"}
{"@timestamp":"2024-11-20T11:45:48.606Z","ecs.version":"1.2.0","log.level":"INFO","message":"Deleting directory /tmp/spark-dacdfd95-f166-4b23-9312-af9052730417","process.thread.name":"shutdown-hook-0","log.logger":"org.apache.spark.util.ShutdownHookManager"}
輸出日志已按JSONL格式打印,各字段含義如下:
@timestamp
:日志記錄產(chǎn)生時間。ecs.version
:Elastic Common Schema (ECS) 版本號(ECS為標(biāo)準(zhǔn)化日志格式)。log.level
:日志級別。message
:日志消息。process.thread.name
:產(chǎn)生該日志的線程名稱。log.logger
:記錄該日志的logger名稱。
步驟五:查詢和分析Spark日志
您可以通過查詢和分析日志,指定作業(yè)執(zhí)行的時間范圍,以確認(rèn)日志是否已成功收集。
(可選)步驟六:環(huán)境清理
如果您已體驗(yàn)完本教程,相關(guān)資源如不再需要,可以通過執(zhí)行以下命令進(jìn)行刪除。
執(zhí)行如下命令刪除Spark作業(yè)。
kubectl delete -f spark-pi.yaml
執(zhí)行如下命令刪除Logtail配置。
kubectl delete -f aliyun-log-config.yaml
執(zhí)行如下命令刪除Log4j2日志配置。
kubectl delete -f spark-log-conf.yaml