checkpoint-restore/checkpointctl
GitHub: checkpoint-restore/checkpointctl
checkpointctl 是一个用于深入分析和比较 Podman、CRI-O 及 Kubernetes 容器检查点归档文件的命令行工具。
Stars: 152 | Forks: 38
# checkpointctl - 用于深入分析容器检查点的工具
[](https://github.com/checkpoint-restore/checkpointctl/actions/workflows/tests.yml)
[](https://codecov.io/gh/checkpoint-restore/checkpointctl)
诸如 *Podman* 和 *CRI-O* 之类的容器引擎具备检查点(checkpoint)容器的功能。与检查点相关的所有数据都会收集在检查点归档文件中。借助 `checkpointctl` 这个工具,可以展示有关这些检查点归档文件的信息。
有关如何借助 [CRIU][criu] 创建检查点的详细信息,请访问:
* [Kubernetes 中的取证容器检查点][forensic]
* [Podman 检查点][podman]
## 用法
### `show` 子命令
要展示检查点归档文件的概览,只需使用
`checkpointctl show`:
```
$ checkpointctl show /tmp/dump.tar
Displaying container checkpoint data from /tmp/dump.tar
CONTAINER IMAGE ID RUNTIME CREATED ENGINE CHKPT SIZE ROOT FS DIFF SIZE
--------- ----- -- ------- ------- ------ ---------- -----------------
looper docker.io/library/busybox:latest 8b5c2ca15082 crun 2021-09-28T10:03:56Z Podman 130.8 KiB 204 B
```
对于由 Kubernetes 使用 *CRI-O* 创建的检查点归档文件,输出结果如下所示:
```
$ checkpointctl show /var/lib/kubelet/checkpoints/checkpoint-checkpoint-test_default-checkpoint-test-2026-03-13T21:43:06Z.tar
Displaying container checkpoint data from /var/lib/kubelet/checkpoints/checkpoint-checkpoint-test_default-checkpoint-test-2026-03-13T21:43:06Z.tar
CONTAINER IMAGE ID RUNTIME CREATED ENGINE CHKPT SIZE ROOT FS DIFF SIZE
--------- ----- -- ------- ------- ------ ---------- -----------------
checkpoint-test docker.io/library/busybox:latest 68bb2fa6a176 crun 2026-03-13T21:42:59.05135916Z CRI-O 314.6 KiB 3.5 KiB
```
### `inspect` 子命令
要检索有关容器检查点的底层信息,请使用 `checkpointctl inspect` 命令:
```
Displaying container checkpoint tree view from /tmp/ubuntu_looper.tar.gz
awesome_booth
├── Image: docker.io/library/ubuntu:latest
├── ID: 2076a99c49c959375c6ae406818a2c841744a019d30221f134db657232f133f5
├── Runtime: crun
├── Created: 2026-03-16T08:00:17Z
├── Engine: Podman
├── Network Interfaces
│ └── podman (eth0)
│ ├── IP: 10.88.0.4/16
│ ├── MAC: 2e:e1:db:6b:68:93
│ └── Gateway: 10.88.0.1
├── Checkpoint size: 1018.3 KiB
│ └── Memory pages size: 952.0 KiB
├── Root FS diff size: 2.0 KiB
└── Process tree
└── [1] bash
└── [4] su
└── [5] bash
└── [6] sleep
```
有关支持的功能标志(flag)的完整列表,请使用 `checkpointctl inspect --help`。
### `diff` 子命令
要比较两个容器检查点并分析它们之间的变化,请使用 checkpointctl `diff` 命令。
```
$ checkpointctl diff --show-unchanged --ps-tree-cmd --sockets ./cp1.tar cp2.tar
╔════════════════════════════════════════════════════════════════╗
║ Checkpoint Diff ║
╠════════════════════════════════════════════════════════════════╣
║ Container: optimistic_mclean ║
║ Image: docker.io/library/python:alpine ║
║ ID: 6ebe04dda2005962a8fb4e971caedfda5e03e22c882e2334... ║
╚════════════════════════════════════════════════════════════════╝
Checkpoint A:
Created: 2026-04-18T10:15:41+01:00
Size: 15186908 bytes
Checkpoint B:
Created: 2026-04-18T10:15:41+01:00
Size: 15212641 bytes
┌─ Memory Changes ─────────────────────────────────────────────┐
│ ↑ Increased by 0.02 MB
└──────────────────────────────────────────────────────────────┘
┌─ Process Tree ───────────────────────────────────────────────┐
│ Process tree
│ └── [= PID 1] sleep infinity
│ └── [= PID 2] python3 -m http.server 8080
└──────────────────────────────────────────────────────────────┘
┌─ Socket Changes ──────────────────────────────────────────────────────┐
│ PID PROTO STATE LOCAL PEER
│ + 2 TCP ESTABLISHED 10.88.0.3:8080 10.88.0.1:39838
│ = 2 TCP LISTEN 0.0.0.0:8080 -
└───────────────────────────────────────────────────────────────────────┘
Summary:
Checkpoint comparison for container optimistic_mclean
Sockets: +1 -0
Memory: +0.02 MB
```
### `memparse` 子命令
要对容器检查点进行内存分析,你可以使用 `checkpointctl memparse` 命令。
```
$ checkpointctl memparse /tmp/jira.tar.gz --pid=1 | less
Displaying memory pages content for Process ID 1 from checkpoint: /tmp/jira.tar.gz
ADDRESS HEXADECIMAL ASCII
-------------------------------------------------------------------------------------
00005633bb080000 f3 0f 1e fa 48 83 ec 08 48 8b 05 d1 4f 00 00 48 |....H...H...O..H|
00005633bb080010 85 c0 74 02 ff d0 48 83 c4 08 c3 00 00 00 00 00 |..t...H.........|
00005633bb080020 ff 35 b2 4e 00 00 f2 ff 25 b3 4e 00 00 0f 1f 00 |.5.N....%.N.....|
00005633bb080030 f3 0f 1e fa 68 00 00 00 00 f2 e9 e1 ff ff ff 90 |....h...........|
*
00005633bb0800a0 f3 0f 1e fa 68 07 00 00 00 f2 e9 71 ff ff ff 90 |....h......q....|
00005633bb0800b0 f3 0f 1e fa 68 08 00 00 00 f2 e9 61 ff ff ff 90 |....h......a....|
00005633bb0800c0 f3 0f 1e fa 68 09 00 00 00 f2 e9 51 ff ff ff 90 |....h......Q....|
00005633bb0800d0 f3 0f 1e fa 68 0a 00 00 00 f2 e9 41 ff ff ff 90 |....h......A....|
00005633bb0800e0 f3 0f 1e fa 68 0b 00 00 00 f2 e9 31 ff ff ff 90 |....h......1....|
```
这是一个针对 PostgreSQL 容器进行内存分析的示例。在本例中,我们启动了一个密码设置为 'mysecret' 的 PostgreSQL 容器。然后,我们为该容器创建一个检查点,并使用 `memparse` 来查找存储的密码。
```
$ sudo podman run --name postgres -e POSTGRES_PASSWORD=mysecret -d postgres
$ sudo podman container checkpoint -l --export=/tmp/postgres.tar.gz
$ sudo checkpointctl memparse --pid 1 /tmp/postgres.tar.gz | grep -B 1 -A 1 mysecret
000055dd725c1e60 50 4f 53 54 47 52 45 53 5f 50 41 53 53 57 4f 52 |POSTGRES_PASSWOR|
000055dd725c1e70 44 3d 6d 79 73 65 63 72 65 74 00 00 00 00 00 00 |D=mysecret......|
000055dd725c1e80 00 00 00 00 00 00 00 00 31 00 00 00 00 00 00 00 |........1.......|
```
这是另一个针对 Web 应用容器的内存分析场景。我们启动了一个存在漏洞的 Web 应用容器,执行了任意代码执行攻击,在不停止容器运行的情况下创建了一个用于取证分析的检查点,最后分析该检查点的内存以识别注入的代码。
```
# 启动易受攻击的 web 应用程序
$ sudo podman run --name dsvw -p 1234:8000 -d quay.io/rst0git/dsvw
# 执行任意代码执行攻击:$(echo secret)
$ curl "http://localhost:1234/?domain=www.google.com%3B%20echo%20secret"
nslookup: can't resolve '(null)': Name does not resolve
Name: www.google.com
Address 1: 142.250.187.228 lhr25s34-in-f4.1e100.net
Address 2: 2a00:1450:4009:820::2004 lhr25s34-in-x04.1e100.net
secret
# 创建用于取证分析的 checkpoint 并保持容器运行
$ sudo podman container checkpoint --leave-running -l -e /tmp/dsvw.tar
# 分析 checkpoint 内存以识别攻击者注入的代码
$ sudo checkpointctl memparse --pid 1 /tmp/dsvw.tar | grep 'echo secret'
00007faac5711f60 6f 6d 3b 20 65 63 68 6f 20 73 65 63 72 65 74 00 |om; echo secret.|
```
对于较大的进程,建议将进程内存页的内容写入文件,而不是直接输出到标准输出。
要概览检查点内的进程内存大小,请在不带任何参数的情况下运行 `checkpointctl memparse`。
```
$ sudo checkpointctl memparse /tmp/jira.tar.gz
Displaying processes memory sizes from /tmp/jira.tar.gz
PID PROCESS NAME MEMORY SIZE SHARED MEMORY SIZE
--- ------------ ----------- ------------------
1 tini 100.0 KiB 0 B
2 java 553.5 MiB 0 B
```
在本示例中,鉴于 java 进程体积较大,最好将其输出写入文件中。
```
$ sudo checkpointctl memparse --pid=2 /tmp/jira.tar.gz --output=/tmp/java-memory-pages.txt
Writing memory pages content for process ID 2 from checkpoint: /tmp/jira.tar.gz to file: /tmp/java-memory-pages.txt...
```
请注意,将大量内存页写入文件可能需要几分钟的时间。
### `build` 子命令
在 Kubernetes 中从检查点恢复容器,需要将检查点归档文件转换为 OCI 镜像。
`build` 命令通过从检查点中提取必要的元数据,并创建一个带有适当注解的兼容 OCI 的镜像,从而简化了这一过程。
示例:
```
checkpointctl build ./checkpoint.tar quay.io/foo/bar:latest
buildah push quay.io/foo/bar:latest
```
在这个示例中,`checkpointctl build` 命令将 `checkpoint.tar` 归档文件转换为了
兼容 OCI 的镜像,并将其标记为 `quay.io/foo/bar:latest`。随后的 `buildah push` 命令
会将新创建的 OCI 镜像上传到容器镜像仓库,从而使其可用于部署。
### `plugin` 子命令
`plugin` 子命令用于管理通过额外子命令扩展 checkpointctl 功能的外部插件。插件是存放在 PATH 中的独立可执行文件,其名称需匹配 `checkpointctl-` 的格式。
```
$ checkpointctl plugin list
Available plugins:
hello My custom plugin description
/usr/local/bin/checkpointctl-hello
```
这种插件架构允许在不增加核心工具二进制文件大小的情况下扩展 checkpointctl 的功能。包含较大依赖项的插件
可以单独分发,并且可以使用任何编程语言来实现。
#### 创建插件
要创建一个插件,请创建一个名为 `checkpointctl-` 的可执行文件:
```
#!/bin/sh
# 支持 --plugin-description 帮助文本(必须以 code 42 退出)
if [ "$1" = "--plugin-description" ]; then
echo "Say hello"
exit 42
fi
echo "Hello, world!"
```
将其保存为 `checkpointctl-hello` 并存放在你 PATH 路径下的目录中,然后赋予其可执行权限。随后,它就可以作为 `checkpointctl hello` 来使用了。
注意:必须使用退出代码 42 来指示该插件支持 `--plugin-description` 标志。任何其他的退出代码都将导致
系统使用默认描述。
## 从源代码安装
1. 克隆仓库。
git clone https://github.com/checkpoint-restore/checkpointctl.git
2. 安装依赖项。
在 Fedora、CentOS 及相关发行版上:
sudo yum install -y make asciidoctor
在 Debian、Ubuntu 及相关发行版上:
sudo apt-get install -y make asciidoctor
Linux 发行版通常提供旧版本的 golang 编译器。我们建议从[官方压缩包](https://go.dev/doc/install)安装 Go。
3. 构建。
make
4. checkpointctl 编译完成后,只需键入以下命令即可将其安装到系统中
sudo make install
此命令接受以下变量:
* **DESTDIR**,用于指定所有组件将要放置在其下的全局根目录(默认为空);
* **PREFIX**,用于指定每个已安装组件路径的额外前缀(默认为 `/usr/local`);
* **BINDIR**,用于指定 checkpointctl 工具的安装位置(默认为 `$(PREFIX)/bin`);
因此,要将所有内容安装在 `/some/new/place` 下,请使用以下命令:
make DESTDIR=/some/new/place install
## 启用自动补全
现在你需要确保在所有的 shell 会话中都能加载自动补全脚本。
你可以通过以下两种方式来实现:
### 用户级别
```
echo 'source <(checkpointctl completion bash)' >>~/.bashrc
```
### 系统级别
```
checkpointctl completion bash | sudo tee /etc/bash_completion.d/checkpointctl > /dev/null
sudo chmod a+r /etc/bash_completion.d/checkpointctl
```
这两种方法是等效的。在重新加载你的 shell 之后,自动补全应该就可以工作了。
要在当前的 shell 会话中启用 bash 自动补全,请加载 `~/.bashrc` 文件:
```
source ~/.bashrc
```
## 卸载
可以使用以下命令来清理先前安装的 checkpointctl 实例。
```
make uninstall
```
请注意,如果在安装过程中使用了某些变量(例如 **DESTDIR**、**BINDIR**),
在执行卸载操作时*必须*传入相同的变量。
## 许可证与版权
除非在特定文件的头部另有说明,否则本项目的所有代码均
遵循 Apache 2.0 许可证发布。
变更的作者仍保留其代码的版权
(无需转让版权)。作者和贡献者列表可以
从 git 提交历史中获取,在某些情况下,也可以从文件头部获取。
标签:CRIU, EVTX分析, 分析工具, 子域名突变, 容器, 数字取证, 日志审计, 系统运维, 自动化脚本