APT package versioning for side-by-side application migration
0 reputation · 23 Mar 2022, 13:21 UTC
0 reputation · 23 Mar 2022, 13:21 UTC
A small application on Debian Stable requires a migration strategy that avoids downtime by utilizing side-by-side installations of different versions. The goal is to deploy a new version of a binary to a distinct path while the previous version remains active, eventually rotating a symbolic link to point to the new release.
While dpkg and apt manage package installation, standard Debian package naming often prevents multiple versions of the same package from coexisting if they share the same package name. This creates a constraint when attempting to maintain two active versions of a binary for a blue-green switchover without relying on external orchestration tools.
What is the recommended naming convention or configuration for .deb packages to allow simultaneous installation of multiple versions on the same system? How should dependency conflicts be managed if both versions require different versions of the same shared library?
Give each version a unique package name (e.g., myapp-1.0, myapp-2.0) and install binaries into versioned directories such as /opt/myapp/1.0/bin/. Manage a current symlink via postinst/prerm scripts. For conflicting shared libraries, package each required library under its own name (e.g., libfoo1, libfoo2) and declare Provides: libfoo.so=1.2 so each application version depends on the exact library it needs.
Debian policy forbids two packages with the same name from being installed simultaneously. The standard workaround is to embed the major/minor version or a release identifier in the package name:
myapp-1.0 and myapp-2.0 (semantic version)myapp-v1 and myapp-v2 (branch suffix)myapp-202401 and myapp-202402 (date-based)Choose a scheme that your deployment automation can parse reliably.
Each package installs its payload under a versioned prefix, keeping the binary name identical:
/opt/myapp/1.0/bin/myapp
/opt/myapp/1.0/lib/libfoo-myapp.so.1
/opt/myapp/2.0/bin/myapp
/opt/myapp/2.0/lib/libfoo-myapp.so.2
The DEBIAN/postinst script of the newly installed package updates the active symlink:
#!/bin/sh
set -e
ln -sfn /opt/myapp/2.0 /opt/myapp/current
# optional: systemctl reload myapp
The prerm script of the version being removed should only delete the symlink if it still points to that version.
If version 1.0 needs libfoo.so.1 and version 2.0 needs libfoo.so.2, do not rely on the system libfoo package. Instead, build two separate library packages:
libfoo1-myapp — installs /opt/myapp/1.0/lib/libfoo.so.1libfoo2-myapp — installs /opt/myapp/2.0/lib/libfoo.so.2In each library package's control file, add a Provides line so the application package can depend on the virtual capability:
Package: libfoo1-myapp
Provides: libfoo.so.1 (= 1.2.3)
...
Package: myapp-1.0
Depends: libfoo.so.1 (= 1.2.3)
This lets apt resolve the correct library for each application version without file conflicts.
Link each binary with -Wl,-rpath,$ORIGIN/../lib so it finds its private library at runtime without LD_LIBRARY_PATH. This keeps the library search isolated to the versioned directory.
Declare mutual conflicts so apt will not silently replace one version with another:
Package: myapp-1.0
Conflicts: myapp-2.0
Breaks: myapp-2.0
...
Package: myapp-2.0
Conflicts: myapp-1.0
Breaks: myapp-1.0
This forces an explicit removal before the other version can be installed, which matches a deliberate blue-green cutover.
.deb packages on a clean Debian VM.myapp-1.0, verify /opt/myapp/1.0/bin/myapp exists and /opt/myapp/current points to it.myapp-2.0, verify both version directories exist and the symlink now points to 2.0.ldd /opt/myapp/1.0/bin/myapp and ldd /opt/myapp/2.0/bin/myapp to confirm each links against its private libfoo.apt policy myapp-1.0 myapp-2.0 — both should show Installed with no conflict errors.Does the application depend on any system library that cannot be vendored (e.g., glibc, libstdc++) and whose ABI differs between the two versions? If yes, side-by-side .deb packages on the same host will not work; you would need containers or separate hosts.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.