我尚未遇到过完美的软件。错误、故障和缺陷是软件开发人员的现实。它们通常也有好处,无论是学习大型应用程序中代码的新领域,还是提出防止问题的想法。
我们最近遇到一个有趣的问题,Podman 数据库损坏了。数据库的主要工作是跟踪容器、它们的状态和它们的配置。在这种情况下,报告者正在测试 Podman,模拟特殊设备上的断电。虽然 Podman 团队和我们的用户有意或无意地进行了有限的断电测试,但我们很少看到数据库损坏,因为要使数据库损坏,它必须正在写入(至少理论上是这样)。而且写入我们的数据库通常是一个非常快速的操作,因此窗口很小。
虽然我们无法立即查明根本原因,但我们被问及如何从此类故障中恢复。如果您的数据库损坏,大多数 Podman 命令将无法工作。在这种情况下,他们的容器通常在每次启动时都会重新创建,并且是通过 RESTFul API 以编程方式完成的。
Podman 数据库损坏
如果您的 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
选项将执行从文件系统中移除先前容器的操作,并使用相同的名称运行或创建新容器。此选项也适用于数据库中和常规存储中的容器。
发表评论