Skip to content

Podman 6: Automatic BoltDB to SQLite migration#28569

Open
mheon wants to merge 3 commits intocontainers:mainfrom
mheon:60_migrate
Open

Podman 6: Automatic BoltDB to SQLite migration#28569
mheon wants to merge 3 commits intocontainers:mainfrom
mheon:60_migrate

Conversation

@mheon
Copy link
Copy Markdown
Member

@mheon mheon commented Apr 22, 2026

@Luap99 I don't think we are vulnerable to the issues we have in 5.8 as there is no possibility of ever getting a BoltDB backend for Podman, but eyes on this would be appreciated.

This is an alternative to https://github.com/chttps://github.com/containers/podman/pull/28553ontainers/podman/pull/28553 and, instead of warning folks to use an external binary or downgrade, adds just enough BoltDB back in to do a migration.

The bad news: I don't think we can actually test this in CI. The ability to make new Bolt databases, and to interact with them in a meaningful way, is entirely gone. Though, now that I think about it, maybe I can ship a Bolt database in the tests directory and do a test migration off it?

Does this PR introduce a user-facing change?

The BoltDB to SQLite migration possible in 5.8, which was planned to be removed in 6.0, has been left in place to ensure users are still able to recover their data if they move from Podman 5.7 or earlier to Podman 6.0 without stopping at Podman 5.8 for a migration.

@packit-as-a-service
Copy link
Copy Markdown

tmt tests failed for commit b36dad6. @lsm5, @psss, @thrix please check.

@mheon mheon added the bloat_approved Approve a PR in which binary file size grows by over 50k label Apr 22, 2026
@packit-as-a-service
Copy link
Copy Markdown

tmt tests failed for commit 5301b8c. @lsm5, @psss, @thrix please check.

@TomSweeneyRedHat
Copy link
Copy Markdown
Member

@mheon tests aren't happy, most notably the FreeBSD cross

@Honny1 Honny1 added the 6.0 Breaking changes for Podman 6.0 label Apr 23, 2026
Copy link
Copy Markdown
Member

@Honny1 Honny1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some comments. Also, I think you'll need to run make vendor.

Comment thread libpod/container_graph.go Outdated
// Add and save the container
if node.container.config.Pod == "" {
if err := sqliteState.AddContainer(node.container); err != nil {
if errors.Is(err, define.ErrPodExists) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be here?

Suggested change
if errors.Is(err, define.ErrPodExists) {
if errors.Is(err, define.ErrCtrExists) {

Comment thread libpod/container_graph.go Outdated
Comment on lines +345 to +350
// We don't actually *use* the pod in this operation, other than its ID...
// So fake it
pod := new(Pod)
pod.config = new(PodConfig)
pod.config.ID = node.container.config.Pod
pod.valid = true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that correct? This pod isn't used anywhere, not even for ID.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent point. This was needed in 5.8, but in 6.0 I removed the dedicated AddContainerToPod function in the database and now it's not necessary to fake a pod

Comment thread libpod/boltdb_state.go Outdated
@@ -0,0 +1,598 @@
//go:build !remote
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//go:build !remote
//go:build !remote && (linux || freebsd)

Comment thread libpod/boltdb_state_internal.go Outdated
@@ -0,0 +1,391 @@
//go:build !remote
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//go:build !remote
//go:build !remote && (linux || freebsd)

Comment thread libpod/boltdb_state.go
Comment thread libpod/runtime_migrate.go Outdated
// So we need a completely new state from disk to see what the user set.
newCfg, err := config.New(nil)
if err != nil {
return fmt.Errorf("reloading configuration to check database backend in use")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should err be wrapped here?

Comment thread libpod/runtime_migrate.go Outdated
if err := r.checkCanMigrate(); err != nil {
switch {
case errors.Is(err, errCannotMigrateNoBolt):
fmt.Printf("No migration is necessary: %v", err)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmt.Printf("No migration is necessary: %v", err)
fmt.Printf("No migration is necessary: %v\n", err)


// ocicniPortsToNetTypesPorts convert the old port format to the new one
// while deduplicating ports into ranges
func ocicniPortsToNetTypesPorts(ports []types.OCICNIPortMapping) []types.PortMapping {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func ocicniPortsToNetTypesPorts(ports []types.OCICNIPortMapping) []types.PortMapping {
//nolint:staticcheck
func ocicniPortsToNetTypesPorts(ports []types.OCICNIPortMapping) []types.PortMapping {

// 2) protocol
// 3) hostPort
// 4) container port
func compareOCICNIPorts(i, j types.OCICNIPortMapping) bool {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func compareOCICNIPorts(i, j types.OCICNIPortMapping) bool {
//nolint:staticcheck
func compareOCICNIPorts(i, j types.OCICNIPortMapping) bool {

@packit-as-a-service
Copy link
Copy Markdown

tmt tests failed for commit 17d11c3. @lsm5, @psss, @thrix please check.

mheon and others added 3 commits April 23, 2026 12:18
If we're going to maintain migration capability for the full
lifespan of 6 - and I think we're going to have to - the only
sane options are a separate binary that exclusively performs
migrations, or re-adding BoltDB code - in a very minimal way - to
allow us to perform migrations within the standard 6 binary.
After attempting the separate binary approach, results are not
promising - it's impossible to strip enough out to make a truly
small binary that still does what we need to perform a migration.
That leaves re-adding BoltDB code.

This adds a minimal version of the BoltDB code that no longer
claims to be a valid State (freeing us from the requirement of
continued maintenance - we should never touch these bits again
until they get removed in 7) which has just enough to get every
container, pod, and volume in the DB, so we can migrate them to
SQLite.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This is gated behind a new option in `podman system migrate`,
`--migrate-db`, or by a system restart being performed.

BoltDB support was removed in Podman 6, so we are certain that,
when we start Podman, a SQLite state is in use. However, if we
also detect a valid BoltDB state, we will attempt a migration.

Migration is performed by retrieving all volumes, pods, and
containers (in that order, to ensure there are no dependency
conflicts) from the Bolt database, when adding them to the SQLite
database. If there is a conflict - IE, a container exists in both
SQLite and Bolt - we skip migration for that object. The old DB
is then renamed so we do not try to migrate it again.

Our ability to test complex migration scenarios is limited, but
this should handle simple migrations easily.

This is a heavily adapted version of containers#27660 rebuilt to work with
Podman 6.0.

This cannot be tested automatically, as the ability to create Bolt
databases has been entirely removed with Podman 6.

Signed-off-by: Matt Heon <matthew.heon@pm.me>
It makes more sense for the callers.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>

<MH: Fix cherry-pick conflicts>

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
@packit-as-a-service
Copy link
Copy Markdown

[NON-BLOCKING] Packit jobs failed. @containers/packit-build please check. Everyone else, feel free to ignore.

Copy link
Copy Markdown
Member

@Honny1 Honny1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a non-blocking comment.

CI is super flaky now.

Comment thread libpod/runtime_migrate.go
if ctrError != nil {
logrus.Errorf("Migrating containers to SQLite: %v", ctrError)
}
ctrError = fmt.Errorf("migrating container %s: %w", id, err)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: I would use errors.Join to aggregate errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.0 Breaking changes for Podman 6.0 bloat_approved Approve a PR in which binary file size grows by over 50k

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants