日志采集操作示例
在 Kubernetes 环境中让 Java 应用的日志落地到指定目录,同时保证被 Fluent Bit 采集,需要从应用配置和运维部署两个层面配合实现。
下面是几种主流方案的完整示例。
# 方案一:Java 应用直接输出到文件(Sidecar 采集模式)【推荐】
这是最符合 Kubernetes 设计理念的方案:Java 应用将日志写入容器的指定目录,同 Pod 内的 Sidecar 容器负责将日志内容输出到 stdout,再让 Fluent Bit 自动采集。
# 1. Java 应用配置(Logback 示例)
在 src/main/resources/logback.xml 中配置日志输出到文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 定义日志文件路径 -->
<property name="LOG_PATH" value="/app/logs" />
<property name="LOG_FILE" value="${LOG_PATH}/app" />
<!-- 控制台输出(保留用于其他用途) -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 文件输出(滚动策略) -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天滚动,自动压缩 -->
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 可选的 JSON 格式输出(便于结构化查询) -->
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/app-json.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/app-json.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Maven 依赖(JSON 格式需要):
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
1
2
3
4
5
2
3
4
5
# 2. Kubernetes Deployment 配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
spec:
containers:
# 主容器:Java 应用
- name: java-app
image: your-java-app:latest
volumeMounts:
- name: app-logs # 挂载共享卷
mountPath: /app/logs # 日志写入目录(与 logback.xml 中 LOG_PATH 一致)
env:
- name: JAVA_OPTS
value: "-Xms256m -Xmx512m"
# 通过环境变量动态指定日志路径(可选)
- name: LOG_PATH
value: "/app/logs"
resources:
limits:
memory: "1Gi"
cpu: "500m"
# Sidecar 容器:将文件日志输出到 stdout
- name: log-sidecar
image: busybox:latest
command:
- /bin/sh
- -c
- |
# 等待日志文件出现
echo "[$(date)] Waiting for log file..."
while [ ! -f /logs/app.log ]; do
sleep 2
done
echo "[$(date)] Starting to tail app.log..."
tail -n+1 -f /logs/app.log
volumeMounts:
- name: app-logs
mountPath: /logs # 挂载同一个共享卷
resources:
requests:
memory: "32Mi"
cpu: "10m"
limits:
memory: "64Mi"
cpu: "20m"
volumes:
- name: app-logs
emptyDir: {} # 临时存储,Pod 生命周期内有效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 3. 工作原理
- Java 应用将日志写入
/app/logs/app.log(容器内) - Sidecar 容器通过
tail -f读取同一个文件,输出到 stdout - Fluent Bit DaemonSet 读取
/var/log/containers/*.log(即 Sidecar 的 stdout),自动采集并发送到 VictoriaLogs
优点:无需修改 Fluent Bit 配置,完全复用现有日志采集体系。
# 方案二:日志文件挂载到宿主机(hostPath)
如果需要日志文件长期保留在节点上,或者需要与节点上的其他工具集成,可以使用 hostPath 直接挂载到宿主机目录。
# 1. Java 应用配置(同上,Logback 配置写入指定路径)
# 2. Deployment 使用 hostPath 挂载
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app-hostpath
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
spec:
# 重要:需要指定节点选择器,确保 Pod 总是调度到同一节点
nodeSelector:
kubernetes.io/hostname: k8s-node01
containers:
- name: java-app
image: your-java-app:latest
volumeMounts:
- name: app-logs-host
mountPath: /app/logs
env:
- name: LOG_PATH
value: "/app/logs"
volumes:
- name: app-logs-host
hostPath:
path: /data/java-logs/default/java-app # 宿主机路径
type: DirectoryOrCreate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 3. 修改 Fluent Bit 采集 hostPath 目录
由于需要让 Fluent Bit 也能读取宿主机上的这个目录,需要修改 Fluent Bit DaemonSet,挂载同样的宿主机路径。
在 Fluent Bit DaemonSet 中添加 volume 和 volumeMount:
# fluent-bit-daemonset.yaml 的修改部分
spec:
template:
spec:
containers:
- name: fluent-bit
volumeMounts:
# ... 原有挂载 ...
- name: java-app-logs # 新增
mountPath: /data/java-logs # Fluent Bit 容器内的挂载点
readOnly: true
volumes:
# ... 原有 volumes ...
- name: java-app-logs # 新增
hostPath:
path: /data/java-logs
type: DirectoryOrCreate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
然后修改 ConfigMap,添加新的 Input 来采集这个目录下的日志:
data:
fluent-bit.conf: |
# ... 原有配置 ...
# 新增:采集 Java 应用的日志文件
[INPUT]
Name tail
Tag java-app
Path /data/java-logs/*/*.log # 匹配所有子目录下的日志
DB /var/log/flb_java.db
Mem_Buf_Limit 5MB
Skip_Long_Lines On
Path_Key log_file_path # 记录文件路径用于区分 Pod
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
缺点:
- Pod 需要固定节点(nodeSelector)
- Pod 重建后,新 Pod 需要调度到同一节点才能读取历史日志
- 节点故障时日志会丢失
- 需要手动管理宿主机目录的权限和清理
# 方案三:log4j2 配置示例
如果使用 Log4j2,配置文件 log4j2.xml 示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="LOG_PATH">/app/logs</Property>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<!-- 控制台输出 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
<!-- 文件输出(按大小和时间滚动) -->
<RollingFile name="RollingFile"
fileName="${LOG_PATH}/app.log"
filePattern="${LOG_PATH}/app-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="50MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
<!-- 异步日志(提升性能) -->
<Async name="AsyncFile">
<AppenderRef ref="RollingFile"/>
</Async>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="AsyncFile"/>
</Root>
</Loggers>
</Configuration>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 方案对比与建议
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Sidecar + emptyDir | 通用场景,日志只需采集到 VictoriaLogs | ✅ 无需修改 Fluent Bit ✅ Pod 可在任意节点调度 ✅ 完全复用现有架构 | Sidecar 占用少量资源 |
| hostPath 直接挂载 | 日志需要保留在节点供其他工具使用 | ✅ 日志持久化在节点 ✅ 节点上可直接查看 | ❌ Pod 需固定节点 ❌ 节点故障日志丢失 ❌ 需手动管理清理 |
| 直接采集应用 stdout | 最简单的场景 | ✅ 零配置 | ❌ 无法控制日志格式 ❌ 不支持日志滚动 |
综合考虑你的环境,强烈推荐方案一(Sidecar 模式),因为它:
- 不需要修改你已经部署好的 Fluent Bit DaemonSet
- Pod 可以在任意节点调度,灵活性高
- 日志通过 Sidecar 输出到 stdout,自动被 Fluent Bit 采集
- 资源消耗极小(busybox sidecar 只用约 2-5MB 内存)
上次更新: 2026/05/25, 09:30:42
|