, ,

数据库损坏时的生存之道

我还没有遇到过完美的软件。错误、故障和缺陷是软件开发者的现实。它们通常有积极的一面,无论是学习大型应用程序中新代码区域,还是想出防止问题的想法。

我们最近遇到一个有趣的问题,Podman 数据库已损坏。数据库的主要作用是跟踪容器、其状态及其配置。在这种情况下,报告者正在测试 Podman,模拟特殊设备上的电源故障。虽然 Podman 团队以及我们的用户或多或少地进行了一些电源故障测试,无论是故意还是意外,我们很少看到数据库损坏,因为数据库要损坏,它必须在写入(至少在理论上)。而写入我们的数据库通常是一个非常快的操作,因此窗口非常小。

虽然我们无法立即确定根本原因,但我们被问到如何从这种故障中恢复。如果你的数据库已损坏,大多数 Podman 命令将无法正常工作。在这种情况下,他们的容器通常在每次启动时都会重新创建,并且是通过 RESTFul API 以编程方式完成的。

Podman DB 损坏

如果你的 Podman 数据库已损坏,在几乎所有情况下,你都 **无法恢复** 任何现有的容器。

在这种情况下,容器由特权用户运行:root。因此,我将展示特权用户的恢复,并为无根用户添加一些说明。过程大致相同。首先,错误

$ sudo podman ps
panic: invalid freelist page: 66, page type is leaf

goroutine 1 [running]:
go.etcd.io/bbolt.(*freelist).read(0x50c95d?, 0x7f96a7e42000)
	/home/baude/go/pkg/mod/go.etcd.io/bbolt@v1.3.6/freelist.go:266 +0x22e
go.etcd.io/bbolt.(*DB).loadFreelist.func1()
	/home/baude/go/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:323 +0xb8
sync.(*Once).doSlow(0xc00011e1c8?, 0x10?)
	/usr/lib/golang/src/sync/once.go:74 +0xc2
sync.(*Once).Do(...)
	/usr/lib/golang/src/sync/once.go:65
go.etcd.io/bbolt.(*DB).loadFreelist(0xc00011e000?)
	/home/baude/go/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:316 +0x47
go.etcd.io/bbolt.Open({0x7ffd1855f26a, 0x23}, 0x1b6?, 0x0)
	/home/baude/go/pkg/mod/go.etcd.io/bbolt@v1.3.6/db.go:293 +0x48b
main.(*CheckCommand).Run(0xc00005fe58, {0xc0000141a0, 0x1, 0x1})
	/home/baude/go/pkg/mod/go.etcd.io/bbolt@v1.3.6/cmd/bbolt/main.go:202 +0x1a5
main.(*Main).Run(0xc000104f40, {0xc000014190, 0x2, 0x2})
	/home/baude/go/pkg/mod/go.etcd.io/bbolt@v1.3.6/cmd/bbolt/main.go:112 +0x979
main.main()
	/home/baude/go/pkg/mod/go.etcd.io/bbolt@v1.3.6/cmd/bbolt/main.go:70 +0xae

恢复的第一步是删除现有数据库。

$ sudo rm /var/lib/containers/storage/libpod/bolt_state.db

无根数据库路径

特权用户的数据库默认存储在 /var/lib/containers/storage/libpod/bolt_state.db 中。无根用户的数据库默认存储在 ~/.local/share/containers/storage/libpod/bolt_state.db 中。

当 Podman 无法找到其数据库时,它将创建一个新的空数据库。

$ sudo podman ps -a
CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES

现在我们可以重新创建我们的容器,这些容器被称为 container1、container2 和 container3。

$ sudo podman create --name container1 alpine top
Error: creating container storage: the container name "container1" is already in use by e77786c096e083b258bad2e196255f7dc1a2859cfb9dd35436648e1541bdce23. You have to remove that container to be able to reuse that name: that name is already in use

容器如何已经存在,但不在所有容器列表中?错误信息 可能更有帮助。有一个鲜为人知的选项称为 `–external`,用于 `podman ps`,用于查看此外部存储状态下的容器。

$ sudo podman ps -a --external
CONTAINER ID  IMAGE                            COMMAND     CREATED             STATUS                    PORTS       NAMES
69f78dfaa0a6  docker.io/library/alpine:latest  storage     About a minute ago  Storage                               container1
e5db3ad9125e  docker.io/library/alpine:latest  storage     About a minute ago  Storage                               container2
52591b8b7676  docker.io/library/alpine:latest  storage     About a minute ago  Storage                               container3

注意,STATUS 列为所有三个容器列出了 STORAGE。同样,这是因为这些容器仍然存在于文件系统中,这解释了之前的错误。与其尝试删除它们并重新创建容器(这也很有效),我们可以简单地使用 `--replace` 选项,该选项适用于 podman `run` 和 `create`。

$ sudo podman create --replace --name container1 alpine top
container1
128876a5b3828350c7bfbc268dee99f69fb2374b5c8ce94cff879b4f83e78c6d

--replace 选项将从文件系统中删除之前的容器,并使用该名称运行或创建新容器。此选项也适用于数据库和常规存储中的容器。

发表评论

订阅

使用您的电子邮件地址注册,以便从本网站接收电子邮件更新。


类别


搜索