tianon / docker-postgres-upgrade

a PoC for using "pg_upgrade" inside Docker -- learn from it, adapt it for your needs; don't expect it to work as-is!
https://hub.docker.com/r/tianon/postgres-upgrade/
MIT License
1.04k stars 114 forks source link

Error: Invalid cross-device link when using named volumes for data directory #41

Closed getaju69 closed 2 years ago

getaju69 commented 2 years ago

I am trying to upgrade my postgres 10 to 14 (on my windows machine)

When I do this, I get the error:

could not create hard link between old and new data directories: Invalid cross-device link
In link mode the old and new data directories must be on the same file system.
Failure, exiting

This is the command I used:

docker run --rm \
  -v postgresql-data-volume:/var/lib/postgresql/10/data \
  -v postgresql-data-volume-14:/var/lib/postgresql/14/data \
  tianon/postgres-upgrade:10-to-14 --link

It works, when I do not use the link option. I would need the link option to do it (as I need the same thing to be also done on production)

I would think it is due to the named volumes I use (just like how it is configured on production)

postgresql-data-volume
postgresql-data-volume-14:

Is it possible to do the in place upgrade using different named volumes, or should I be using a local directory for the same (it seems I cannot do this on windows - using named directory)

(running the test setup as per the readme file worked without any issues)

In short, does it also support a --link upgrade for named volumes ?

getaju69 commented 2 years ago

@tianon Please let me know if you have some ideas, as I am stuck here. I was able to upgrade successfully to Postgres 14, without the link option. But since we want this to be done with minimal downtime on production, with ~500 GB of data, we need to use the --link option - that's supposedly much faster.

tianon commented 2 years ago

Unfortunately, disparate bind mounts that even share the same underlying filesystem cannot share hard links directly, so for --link to work, you must be using a single volume that contains both. :disappointed:

What I would recommend in this case if you're using a named volume is to stop your database container, mount said named volume to a new container with a shell so you can move all the contents into the necessary structure, perform the --link upgrade, then optionally remove the old contents and move the new files back into place.

(If you're on Windows, I would definitely not recommend running PostgreSQL from "host" directories that map to the Windows system.)

getaju69 commented 2 years ago

@tianon Since then I need to move all the contents into the new structure (var/lib/postgres/10/data), it could potentially take a long time ? as I then need to move close to 500 GB of data - and with further steps , it means the database would be down for the period. Or did I understand it wrongly ? (We are trying to upgrade production with less downtime)

If I go this path, once I have moved to the new structure - and after running the upgrade - I just need to start the new Postgres using the new mount path (var/lib/postgres/14/data) ?

tianon commented 2 years ago

Most filesystems should handle that as a rename and be pretty much constant time (because you're not actually moving any data, just adjusting the filenames which are essentially pointers).

To actually perform the upgrade, you'll have to have some downtime. If you want to really minimize downtime, I'd suggest you spin up a new empty database, and use something like pg_dump + pg_restore to do the copy yourself, then sunset the old database (ideally making the old one read-only first, but I'm not sure whether PostgreSQL supports that). This is really fundamentally "all" pg_upgrade is doing, it just wraps it up with a neat little bow and can often do tricks to avoid copying all 500GB of your data (sometimes).

In the future (and for more help), these sorts of questions/requests would be more appropriately posted to a dedicated support forum, such as the Docker Community Forums, the Docker Community Slack, or Stack Overflow. :+1: