- 云原生
- 容器运行时
【免费下载链接】kata-containers
Kata Containers is an open source project and community working to build a standard implementation of lightweight Virtual Machines (VMs) that feel and perform like containers, but provide the workload isolation and security advantages of VMs. https://katacontainers.io/
kata-log-parser(即kata-ctl log-parser子命令)是 Kata Containers 用于排查运行时问题的日志分析工具:它把 agent、shim、hypervisor 等各组件散落在 journald 中的日志合并为单一日志流,按时间戳排序后统一重放,并支持对每条记录做结构校验、按需丢弃或报错,最后以 JSON、CSV、TOML、YAML、XML、RON、TEXT 七种格式之一输出。读完本文,你将掌握从开启 containerd debug、采集 runtime-rs 日志,到用kata-ctl log-parser完成校验、排序与格式转换的完整排障流程,并理解其底层解析管线与错误处理语义。
工具概览:定位与演进
kata-log-parser是 Kata Containers 控制工具kata-ctl(位于 src/tools/kata-ctl)内置的一个子命令,其核心功能是:
- 合并:将各系统组件(shim、agent、hypervisor 等)产生的日志文件合并到一起;
- 排序:按时间戳(
ts字段)对所有日志条目重新排序,还原真实事件顺序; - 校验:检查每条日志记录是否符合预期的 JSON 结构;
- 重放与转码:重新格式化日志,并以不同输出格式呈现。
注意:这是对基于 Go 的旧版
kata-log-parser(参见仓库中的 src/tools/log-parser)的一次 Rust 重写,未来将取代旧工具。当前实现位于 src/tools/kata-ctl/src/log_parser,完整文档见 log_parser/README.md。
在 kata-ctl 的 README 中,log-parser被归为"帮助分析 kata runtime 日志"的附属工具;kata-ctl本身是kata-runtime工具程序的 Rust 重写,面向高级功能使用与问题定位、调试场景。
查看工具最新、最权威的选项清单,直接运行:
$ kata-ctl log-parser --help日志格式:runtime-rs 的结构化 JSON
Kata 的runtime-rs日志是以下格式的 JSON 对象:
{"msg":"message","level":"INFO","ts":"1970-01-01T00:00:00.000000000Z","name":"kata-runtime","version":"0.1.0","pid":"0","source":"source","subsystem":"subsystem"}字段语义如下:
| 字段 | 含义 |
|---|---|
msg | 日志正文消息 |
level | 日志级别,取值见下文"级别解析" |
ts | RFC 3339 格式时间戳(UTC) |
name | 产生日志的组件名,如kata-runtime |
version | 组件版本 |
pid | 进程 ID(注意在 JSON 中以字符串形式携带) |
source | 日志来源 |
subsystem | 子系统,如hypervisor、virt-container |
严格模式与宽松模式
解析器内部存在两种数据结构(详见 log_message.rs):
StrictLogMessage:要求level、msg、name、pid、source、subsystem、ts全部字段必填且类型正确;LogMessage:除msg和ts外其余字段均为Option,允许缺失。
在 log_parser.rs 中可以看到二者的选择逻辑:
pub fn log_parser(args: LogParser) -> anyhow::Result<()> { if args.ignore_missing_fields { handle_logs::<LogMessage>(args) } else { handle_logs::<StrictLogMessage>(args) } .context("Could not parse logs") }即:默认采用严格模式(所有字段必须齐全);一旦设置--ignore-missing-fields,则切换到宽松模式,缺失level、name、version、pid、source、subsystem中一个或多个字段的日志仍可被接受(缺失字段在输出中按skip_serializing_none规则省略)。msg与ts是两种模式下都强制要求的。
一行一条记录
一条日志条目必须独占一行,且一行只能包含一条日志条目。解析器在 parse_file.rs 中按行切分输入,逐行调用serde_json::from_str解析,任何一行解析失败都会产生一个ParsingError。测试用例parse_mixed直接演示了这一点:混入Random Kernel Message这类非 Kata 日志行时,该行会被标记为解析错误。
日志级别的解析
LogLevel是对slog::Level的封装,解析时同时接受短写与长写(见 log_message.rs):
| 长写 | 短写 | slog 级别 |
|---|---|---|
critical | crit | Critical |
error | erro | Error |
warning | warn | Warning |
info | — | Info |
debug | debg | Debug |
trace | trce | Trace |
级别解析不区分大小写(内部先to_lowercase())。实际日志中出现的DEBG(如测试样例)即被归一化为DEBUG输出。
命令行选项
README 列出并可在源码 args.rs 中确认的全部选项如下:
| 选项 | 说明 |
|---|---|
<INPUT_FILE>... | 位置参数,可传入一个或多个日志文件,全部文件会被合并处理 |
-o, --output-file <OUTPUT_FILE> | 输出到指定文件;不设置时输出到 stdout |
--output-format <OUTPUT_FORMAT> | 输出格式,默认为json,可选csv、json、ron、text、toml、xml、yaml |
-q, --quiet | 不把无效日志条目的错误打印到 stderr(静默丢弃) |
-s, --strict | 遇到任何无效日志条目即终止程序并报错 |
-c, --check-only | 只检查日志文件,仅在出错时显示输出;成功时不输出内容 |
--error-if-file-empty | 任一输入文件为空则报错 |
--error-if-no-records | 所有日志文件均为空(无任何记录)则报错 |
--ignore-missing-fields | 不因缺少pid、source、name、level等字段的行而报错(即宽松模式) |
-h, --help | 显示全部 CLI 选项 |
错误处理三态(见 process_logs.rs)是理解该工具行为的关键:
- 默认:无效条目被过滤掉,同时把错误信息打印到 stderr;
--quiet:无效条目被静默过滤,不打印任何错误;--strict:遇到第一个无效条目即返回该错误、中止处理(实现上利用Result的collect()语义,将Vec<Result<T, E>>收集为Result<Vec<T>, E>,见find_errors)。
排序在所有过滤之后进行(log_parser.rs),按每条日志的时间戳升序排列(sort_logs中sort_by_key(|l| l.get_timestamp()))。
端到端使用流程
以下是 README 给出的完整五步排障流程,含注释与扩展说明:
1. 开启 containerd debug
保证 containerd(以及 shimv2)输出足够详细的日志。编辑 containerd 配置文件(通常为/etc/containerd/config.toml),加入顶层 debug 配置(详见 docs/Developer-Guide.md#enabling-full-containerd-debug):
[debug] level = "debug"如果只想开启 shim 自身调试,可在plugins.linux段设置:
[plugins.linux] shim_debug = true2. 确认正在使用 runtime-rs
本文介绍的日志格式针对runtime-rs(Rust 运行时)。用以下命令确认当前 shim 是 Rust 还是 Go 实现:
$ containerd-shim-kata-v2 --version | grep -qi rust && echo rust || echo golang输出rust才符合本工具预期;输出golang说明系统仍在使用旧 Go 运行时。
3. 采集日志
从 journald 中提取以kata标识写入的日志,并用grep "^{"过滤出 JSON 对象行(即剔除非结构化文本):
$ sudo journalctl -q -o cat -a -t kata | grep "^{" > ./kata.log提示:除清空 journal 外,也可用
--since=<容器创建时间>限定采集窗口,避免日志文件过大。
4. 确保日志文件可读
journalctl 以 root 权限运行,生成的文件属主为 root,需改为当前用户:
$ sudo chown $USER *.log这一步对应解析器读取阶段的权限语义:当文件不存在时返回InputFileNotFound,无权限时返回InputFilePermissionError(见 log_parser_error.rs)。
5. 处理日志
$ kata-ctl log-parser kata.log -o out.log将合并、校验、排序后的结果写入out.log(默认 JSON 格式)。也可以同时传入多个文件合并分析:
$ kata-ctl log-parser kata.log agent.log -o merged.log --output-format yaml构建与安装 kata-ctl
kata-ctl采用 Makefile 驱动(见 src/tools/kata-ctl/README.md):
$ make # 编译 $ make install # 安装到默认路径 $ make install INSTALL_PATH=/path/to/custom/dir # 安装到自定义目录log-parser作为kata-ctl的子命令(命令分发见 main.rs 的Commands::LogParser(args) => log_parser(args)),随kata-ctl一起构建与安装。
源码级原理:解析管线与输出引擎
处理管线
主流程handle_logs(log_parser.rs)清晰呈现了五段式管线:
读取文件 → 逐行解析 → 过滤错误 → 空文件检查 → 时间戳排序 → 格式输出- 读取:
open_file_into_memory将整个输入文件一次性读入内存字符串(parse_file.rs)。源码注释特别提醒:内存占用可能异常偏高,因为整个文件都会驻留内存——采集日志时尽量控制文件规模。 - 解析:
parse_log按行serde_json::from_str,逐条产生Result<O, LogParserError>。 - 过滤:
filter_errors依据strict/quiet标志选择丢弃、静默或输出到 stderr 的错误策略(process_logs.rs)。 - 检查:
--error-if-file-empty触发FileEmpty、--error-if-no-records触发NoRecordsError。 - 排序与输出:
sort_logs按时间戳升序排序;若设置--check-only则到此为止直接返回成功(不输出任何内容),否则进入输出阶段。
错误类型体系
LogParserError(log_parser_error.rs)覆盖了输入输出全链路的失败情形:
| 错误变体 | 触发场景 |
|---|---|
InputFileNotFound | 输入文件不存在 |
FileEmpty | 输入文件不包含任何有效日志 |
InputFilePermissionError | 无权限打开输入文件 |
OutputFilePermissionError | 无权限写入输出文件 |
ParsingError | 某行 JSON 解析失败(附带原始行文本) |
SerializationError | 输出序列化失败 |
NoRecordsError | 所有文件均无记录 |
Unknown | 其他未知 I/O 错误 |
输出格式引擎
输出阶段由output_file分发(output_file.rs):根据--output-format选择对应的序列化函数——csv使用csvcrate、json用serde_json、ron用ron、toml用toml、xml用quick_xml、yaml用serde_yaml、text则输出 Rust 的Debug表示。选好格式后,若指定了-o则File::create写入文件(权限不足映射为OutputFilePermissionError),否则print!到 stdout。
同一份日志在不同格式下的输出形态,可直接从 log_message.rs 的序列化测试中看到,例如:
- CSV(首行为表头):
level,msg,pid,subsystem,ts,数据行DEBUG,vmm-master thread is uninitialized or has exited.,3327263,hypervisor,2023-03-15 14:17:02.526992506 UTC; - TOML:
level = "DEBUG"/msg = "..."/pid = "3327263"等键值对; - YAML:
pid: '3327263'(字符串被加引号); - XML:
<LogMessage><level>DEBUG</level><msg>...</msg>...</LogMessage>; - RON:
(level:Some("DEBUG"),msg:"...",pid:Some("3327263"),...)。
值得注意的是,宽松模式(LogMessage)下缺失的字段(如name、source)在 CSV/XML 等格式中也会相应从表头/标签中省略,而严格模式(StrictLogMessage)输出则总是包含全部七个字段,如 CSV 表头固定为level,msg,name,pid,source,subsystem,ts。
排障提示
- 输出乱序排查:
kata-ctl log-parser已按ts排序,若怀疑某事件顺序,可直接用--output-format csv导出后按时间列核查。 - 大文件内存:解析器一次性读入整个文件(源码
open_file_into_memory的注释明确提示该局限),采集时应使用--since控制时间范围或分批处理。 - 混入非 Kata 日志:journald 中同一
-t kata标识下可能出现非 JSON 文本行;默认模式会将其作为解析错误打印到 stderr 并跳过,--quiet可静默丢弃,--strict则会终止分析——用于快速确认日志流是否纯净。 - "没有任何记录":若所有文件均无有效记录,工具返回
NoRecordsError;排查时先确认步骤 3 的grep "^{"是否确实产生了输出。 - 只校验不输出:CI 或脚本中可使用
--check-only,仅在日志有问题时才有输出(非零语义通过错误返回体现)。
延伸阅读
- 工具主文档:src/tools/kata-ctl/README.md
- 解析器源码目录:src/tools/kata-ctl/src/log_parser
- 命令行参数定义:args.rs
- 主流程与分发:log_parser.rs、main.rs
- containerd debug 开启方法:docs/Developer-Guide.md#enabling-full-containerd-debug
- 被取代的旧 Go 版工具:src/tools/log-parser
- 云原生
- 容器运行时
【免费下载链接】kata-containers
Kata Containers is an open source project and community working to build a standard implementation of lightweight Virtual Machines (VMs) that feel and perform like containers, but provide the workload isolation and security advantages of VMs. https://katacontainers.io/
相关推荐
Kata Containers 日志解析利器:kata-log-parser 合并、排序与校验实战指南
Kata Containers 日志解析利器:kata log parser 合并、排序与校验实战指南 kata log parser 是 Kata Conta
云原生容器运行时Terragrunt 日志格式化完全指南:用 `--log-custom-format` 自定义日志输出
Terragrunt 日志格式化完全指南:用 log custom format 自定义日志输出 Terragrunt 作为 OpenTofu/Terrafor
CLIDevOps云原生Kata Containers 日志接入 Fluentd 实战:systemd journal 与 JSON 日志导入 EFK/ELK 全流程
Kata Containers 日志接入 Fluentd 实战:systemd journal 与 JSON 日志导入 EFK/ELK 全流程 导读 本文基于
云原生容器运行时
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考