Pekerjaan Spark yang berjalan di kluster Container Service for Kubernetes (ACK) menghasilkan log yang tersebar di banyak Pod, sehingga menyulitkan manajemen log terpusat. Dengan mengintegrasikan Simple Log Service (SLS), Anda dapat:
Mengumpulkan log terstruktur dari semua Pod driver dan executor Spark secara otomatis.
Menjalankan kueri dan menganalisis log pekerjaan Spark dalam rentang waktu tertentu.
Menyaring log berdasarkan nama aplikasi, versi, role, dan submission ID.
Topik ini menjelaskan cara mengonfigurasi seluruh pipeline pengumpulan log: membangun gambar kontainer Spark dengan dukungan pencatatan terstruktur, men-deploy konfigurasi Logtail untuk mengumpulkan log Pod, serta menjalankan kueri terhadap hasilnya di Simple Log Service.
Prasyarat
Sebelum memulai, pastikan Anda telah:
Menginstal komponen ack-spark-operator. Untuk informasi lebih lanjut, lihat Langkah 1: Instal komponen ack-spark-operator.
Membuat proyek Simple Log Service. Untuk informasi lebih lanjut, lihat Manage a project.
Menginstal komponen Logtail di kluster ACK Anda. Untuk informasi lebih lanjut, lihat Install Logtail components in an ACK cluster.
Memiliki registri gambar kontainer untuk mendorong gambar Spark kustom Anda.
Cara kerja
Pipeline ini bekerja sebagai berikut:
Gambar kontainer Spark kustom menambahkan pustaka tata letak templat JSON Log4j2, sehingga mengaktifkan output JSONL terstruktur.
ConfigMap mengonfigurasi Log4j2 untuk menulis log dalam format JSONL menggunakan templat Elastic Common Schema (ECS), baik ke stdout maupun ke file di
/opt/spark/logs/spark.log.Konfigurasi Logtail (AliyunLogConfig) memberi tahu Simple Log Service untuk mengumpulkan log dari kontainer yang sesuai dengan label Pod Spark Operator dan pola nama kontainer, lalu mengurai bidang JSONL serta mengekstraksi timestamp.
Setelah pekerjaan Spark berjalan, log-nya tersedia di penyimpanan log (Logstore) yang ditentukan untuk kueri dan analisis.
Langkah 1: Bangun gambar kontainer Spark
Buat Dockerfile berikut. Contoh ini menggunakan Spark 3.5.3 dan menambahkan dependensi log4j-layout-template-json ke classpath Spark, yang memungkinkan output JSONL melalui appender JsonTemplateLayout.
ARG SPARK_IMAGE=<SPARK_IMAGE> # Ganti <SPARK_IMAGE> dengan gambar dasar Spark Anda.
FROM ${SPARK_IMAGE}
# Tambahkan dependensi untuk 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}/jarsBangun dan dorong gambar ke registri Anda:
docker build -t <your-registry>/<your-image-name>:<tag> .
docker push <your-registry>/<your-image-name>:<tag>Ganti placeholder dengan detail registri dan gambar aktual Anda.
Langkah 2: Konfigurasi log Log4j2
Buat file bernama spark-log-conf.yaml dengan konten berikut. ConfigMap ini mengatur tingkat log ke INFO dan mengonfigurasi appender konsol serta file agar menghasilkan log dalam format JSONL menggunakan templat ECS. Untuk informasi lebih lanjut, lihat Collect Log4j logs.
apiVersion: v1
kind: ConfigMap
metadata:
name: spark-log-conf
namespace: default
data:
log4j2.properties: |
# Atur semua hal untuk dicatat ke konsol dan 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.jsonTerapkan ConfigMap:
kubectl apply -f spark-log-conf.yamlOutput yang diharapkan:
configmap/spark-log-conf createdLangkah 3: Buat konfigurasi Logtail
Buat file bernama aliyun-log-config.yaml dengan konten berikut. Ganti <SLS_PROJECT> dengan nama proyek Simple Log Service Anda dan <SLS_LOGSTORE> dengan nama Logstore Anda. Jika Logstore belum ada, Simple Log Service akan membuatnya secara otomatis.
Konfigurasi ini menyaring Pod yang diluncurkan oleh Spark Operator menggunakan label sparkoperator.k8s.io/launched-by-spark-operator: "true", yang secara otomatis ditetapkan oleh Spark Operator pada semua Pod driver dan executor. Log dikumpulkan dari /opt/spark/logs, diurai sebagai JSON, dan bidang @timestamp diekstraksi sebagai waktu log. Untuk informasi lebih lanjut tentang bidang AliyunLogConfig, lihat Use AliyunLogConfig to manage a Logtail configuration.
apiVersion: log.alibabacloud.com/v1alpha1
kind: AliyunLogConfig
metadata:
name: spark
namespace: default
spec:
# (Opsional) Nama proyek. Nilai default: k8s-log-<Your_Cluster_ID>.
project: <SLS_PROJECT>
# Nama Logstore. Jika Logstore yang Anda tentukan belum ada, Simple Log Service akan membuat Logstore secara otomatis.
logstore: <SLS_LOGSTORE>
# Konfigurasi Logtail.
logtailConfig:
# Nama konfigurasi Logtail.
configName: spark
# Jenis sumber data. Nilai file menentukan log teks.
inputType: file
# Konfigurasi input log.
inputDetail:
# Direktori tempat file log berada.
logPath: /opt/spark/logs
# Nama file log. Karakter wildcard didukung.
filePattern: '*.log'
# Pengkodean file log.
fileEncoding: utf8
# Tipe log.
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
# Kumpulkan log teks dari kontainer.
dockerFile: true
# Konfigurasi lanjutan.
advanced:
# Pratinjau metadata kontainer.
collect_containers_flag: true
# Konfigurasi Logtail di Kubernetes.
k8s:
# Saring Pod berdasarkan label.
IncludeK8sLabel:
sparkoperator.k8s.io/launched-by-spark-operator: "true"
# Saring kontainer berdasarkan nama kontainer.
K8sContainerRegex: "^spark-kubernetes-(driver|executor)$"
# Konfigurasi tag log tambahan.
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 pemrosesan log.
plugin:
processors:
# Isolasi log.
- type: processor_split_log_string
detail:
SplitKey: content
SplitSep: ''
# Urai bidang JSON.
- type: processor_json
detail:
ExpandArray: false
ExpandConnector: ''
ExpandDepth: 0
IgnoreFirstConnector: false
SourceKey: content
KeepSource: false
KeepSourceIfParseError: true
NoKeyError: false
UseSourceKeyAsPrefix: false
# Ekstraksi timestamp log.
- type: processor_strptime
detail:
SourceKey: '@timestamp'
Format: '%Y-%m-%dT%H:%M:%S.%fZ'
KeepSource: false
AdjustUTCOffset: true
UTCOffset: 0
AlarmIfFail: falseTerapkan konfigurasi:
kubectl apply -f aliyun-log-config.yamlUntuk memverifikasi bahwa Logstore dan konfigurasi Logtail telah dibuat:
Login ke Simple Log Service console.
Pada bagian Projects, klik proyek Anda.

Pilih Log Storage \> Logstores. Klik ikon \> di sebelah Logstore target. Pilih Data Import \> Logtail Configurations.

Klik konfigurasi Logtail untuk melihat detailnya.
Langkah 4: Kirim pekerjaan Spark contoh
Buat file bernama spark-pi.yaml dengan konten berikut. Bidang sparkConfigMap mereferensikan ConfigMap yang dibuat pada Langkah 2, yang menyuntikkan konfigurasi Log4j2 ke dalam Pod Spark.
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: 4gKirim pekerjaan:
kubectl apply -f spark-pi.yamlSetelah pekerjaan selesai, periksa 10 baris terakhir log Pod driver untuk memastikan output JSONL:
kubectl logs --tail=10 spark-pi-driverOutput yang diharapkan:
{"@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"}Setiap entri log JSONL berisi bidang-bidang berikut:
| Field | Description |
|---|---|
@timestamp | Waktu saat log dihasilkan |
ecs.version | Versi ECS (Elastic Common Schema) |
log.level | Tingkat log, seperti INFO atau WARN |
message | Pesan log |
process.thread.name | Nama thread yang menghasilkan log |
log.logger | Nama logger yang mencatat log |
Langkah 5: Verifikasi pengumpulan log
Setelah pekerjaan Spark selesai, pastikan log telah sampai ke Logstore Anda sebelum menggunakannya untuk analisis.
Login ke Simple Log Service console dan buka proyek Anda. Di Logstore, atur rentang waktu yang mencakup jendela eksekusi pekerjaan dan jalankan kueri. Anda seharusnya melihat entri dalam format JSONL dengan bidang ECS seperti yang dijelaskan di atas.

Jika tidak ada log yang muncul, periksa:
Konfigurasi Logtail aktif dan nama Logstore sesuai dengan
<SLS_LOGSTORE>dalam AliyunLogConfig Anda.Pod Spark memiliki label
sparkoperator.k8s.io/launched-by-spark-operator: "true"(ditetapkan secara otomatis oleh Spark Operator).File log ada di
/opt/spark/logs/spark.logdi dalam Pod driver atau executor.
Langkah 6: Jalankan kueri dan analisis log Spark
Dengan log yang mengalir ke Simple Log Service, gunakan fitur query and analysis untuk menyaring dan mengagregasi log pekerjaan Spark berdasarkan rentang waktu, tingkat log, nama aplikasi, atau role Spark (driver vs. executor).
(Opsional) Langkah 7: Bersihkan
Setelah pengujian, hapus sumber daya untuk menghindari biaya yang tidak perlu.
Hapus pekerjaan Spark:
kubectl delete -f spark-pi.yamlHapus konfigurasi Logtail:
kubectl delete -f aliyun-log-config.yamlHapus ConfigMap Log4j2:
kubectl delete -f spark-log-conf.yaml