First live end-to-end install on real Unraid hardware (all 8 built
packages installed via upgradepkg, rc.podman started, containers
pulled/run/networked/port-mapped) — surfaced five genuine bugs no
amount of container-based CI testing could have caught, since none of
them exist inside the vbatts/slackware:15.0 build container:
1. rc.podman never created $PODMAN_LOG_DIR before redirecting the
podman system service's output into it, so the service failed to
even start ("No such file or directory"). Added it alongside the
existing PODMAN_RUN_DIR mkdir.
2. config/storage.conf hardcoded a [storage] table, and
podman-config.sh's `sync` step appended a second one at boot with
the real graphroot/runroot — TOML forbids defining the same table
twice. Removed the template's [storage] entirely; sync already
generates the whole thing.
3. config/policy.json had a "_comment" pseudo-field for
documentation, but containers/image's policy parser rejects any
unknown top-level key outright. JSON has no comment syntax; moved
the rationale into docs/ARCHITECTURE.md instead.
4. netavark >= 2.0 dropped its iptables firewall driver entirely
(verified: passing "iptables" is flatly rejected) — nftables or
firewalld are the only remaining options, and firewalld needs
systemd/dbus, which Unraid has neither of. Set firewall_driver =
"nftables" explicitly and documented that Unraid OS doesn't ship
the `nft` binary this needs (a slackware64 nftables package works;
not yet wired into the build/install pipeline — see follow-up).
5. Every container failed with "crun: pivot_root: Invalid argument".
Root cause: Unraid's / is permanently the kernel's initial "rootfs"
pseudo-filesystem (Unraid never pivots to a real one at boot — the
whole OS runs from RAM), and pivot_root(2) unconditionally rejects
that as the old root. This is not new: Docker/runc hits the exact
same kernel restriction on this exact host and silently falls back
to an MS_MOVE-based chroot; crun has no such fallback, only a
--no-pivot flag with no config-file equivalent. Added
plugin/sbin/crun-no-pivot.sh, a thin wrapper that scans crun's full
argument list (podman puts global flags before the subcommand, so
the subcommand isn't reliably $1) and injects --no-pivot right
after create/run, and pointed containers.conf's crun runtime at it.
Also fixed the podman.plg postinstall's chmod glob
(`podman-*.sh` -> `*.sh`), which would have skipped this new
non-podman-prefixed sbin script.
Verified end-to-end on the real host: pull, run, real network
connectivity (wget through the container's bridge), and a published
port actually serving HTTP (curl through -p 8099:80 to nginx) all
work. --no-pivot's security tradeoff (disabling one particular
container-escape mitigation) was explicitly discussed with and
approved by the user before committing, given it must be the default
for any container to start at all on this platform.
Follow-up not yet done: nftables (needed for #4) is not yet a
packages/ component in the reproducible build pipeline — it was only
installed manually on the test host for this verification run.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
366 lines
15 KiB
XML
366 lines
15 KiB
XML
<?xml version="1.0" standalone="yes"?>
|
|
|
|
<!--
|
|
podman.plg — Unraid plugin manifest for unraid-podman.
|
|
|
|
This file is the single entry point Unraid's Plugin Manager uses to
|
|
install, update, and remove the plugin. Everything it does is built on
|
|
OFFICIAL Unraid plugin mechanisms only — verified directly against the
|
|
real source of two long-established, widely used Unraid plugins
|
|
(unraid/community.applications and unraid/unassigned.devices) rather than
|
|
guessed:
|
|
|
|
- A FILE block with a Name attribute, an upgradepkg Run command (using
|
|
its install new and reinstall flags together), and a URL/MD5 child
|
|
pair is the standard way to download and install a Slackware .txz
|
|
package, and the same command works for both a fresh install and an
|
|
update in one step (confirmed: both reference plugins use exactly
|
|
this pattern rather than separate installpkg/upgradepkg branches).
|
|
- Plugin uninstall logic lives in a <FILE Run="/bin/bash" Method="remove">
|
|
block — this exact `Method="remove"` attribute is what Unraid's
|
|
plugin manager looks for when the user clicks "Remove" (confirmed
|
|
against community.applications.plg).
|
|
- Boot/shutdown integration uses the official Unraid plugin EVENT
|
|
mechanism: any executable at
|
|
/usr/local/emhttp/plugins/<name>/event/<eventname> is run automatically
|
|
by emhttpd as the corresponding event fires (confirmed against
|
|
unassigned.devices, which uses this exact convention for its own
|
|
disks_mounted/started/stopping_svcs hooks). This project deliberately
|
|
does NOT hand-edit /boot/config/go — see plugin/event/disks_mounted
|
|
and plugin/event/stopping for the two hooks used here, and
|
|
docs/ARCHITECTURE.md section 6.2 for the full event-ordering rationale.
|
|
|
|
Structure of this file:
|
|
1. DOCTYPE entity block — plugin metadata + one version/file/md5 triple
|
|
per package (the seven upstream components plus this project's own
|
|
"unraid-podman" scaffolding package, see packages/unraid-podman/).
|
|
Entities are rewritten automatically by scripts/release.sh; never
|
|
hand-edit a *_txz_version/_file/_md5 entity — see that script.
|
|
2. <PLUGIN> body:
|
|
a. <CHANGES> — kept in sync with CHANGELOG.md by hand for now.
|
|
b. Pre-install architecture sanity check.
|
|
c. Eight <FILE> package install/update blocks.
|
|
d. Postinstall <FILE Run="/bin/bash"> — directory/config seeding,
|
|
install-manifest generation, first start.
|
|
e. <FILE Run="/bin/bash" Method="remove"> — uninstall.
|
|
-->
|
|
|
|
<!DOCTYPE PLUGIN [
|
|
<!ENTITY name "podman">
|
|
<!ENTITY author "unraid-podman contributors">
|
|
<!ENTITY version "0.0.0">
|
|
<!-- "Podman" (no parent) — Podman.page declares Menu="Podman", making it
|
|
its own top-level nav tab next to Docker/VMs, not nested under
|
|
Settings — see webui/plugins/podman/Podman.page. -->
|
|
<!ENTITY launch "Podman">
|
|
<!ENTITY github "OWNER/unraid-podman">
|
|
<!ENTITY gitURL "https://raw.githubusercontent.com/&github;/main">
|
|
<!ENTITY pluginURL "&gitURL;/plugin/podman.plg">
|
|
<!ENTITY supportURL "https://github.com/&github;/discussions">
|
|
|
|
<!-- Release asset base — matches scripts/release.sh's RELEASE_BASE_URL
|
|
exactly; both must agree since release.sh is what publishes the
|
|
packages this URL is expected to find. -->
|
|
<!ENTITY baseURL "https://github.com/&github;/releases/download/v&version;">
|
|
|
|
<!-- Slackware package naming components — must match versions.env's
|
|
PKG_ARCH/PKG_BUILD/PKG_TAG (see that file). Kept as entities here so
|
|
the eight removepkg calls in the Method="remove" block don't have to
|
|
repeat "x86_64-1_unraidpodman" eight times by hand. -->
|
|
<!ENTITY pkgArch "x86_64">
|
|
<!ENTITY pkgBuild "1">
|
|
<!ENTITY pkgTag "_unraidpodman">
|
|
|
|
<!-- One version/file/md5 entity triple per package, filled in by
|
|
scripts/release.sh from dist/*.txz.md5 at release time (see that
|
|
script's "Update per-package entities" step). Until a release has been
|
|
cut, these are placeholders and the FILE blocks below will correctly
|
|
fail to download anything — that is intentional; there is nothing to
|
|
install before the first tagged release. -->
|
|
|
|
<!ENTITY podman_txz_version "0.0.0">
|
|
<!ENTITY podman_txz_file "podman-&podman_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY podman_txz_md5 "00000000000000000000000000000000">
|
|
|
|
<!ENTITY conmon_txz_version "0.0.0">
|
|
<!ENTITY conmon_txz_file "conmon-&conmon_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY conmon_txz_md5 "00000000000000000000000000000000">
|
|
|
|
<!ENTITY crun_txz_version "0.0.0">
|
|
<!ENTITY crun_txz_file "crun-&crun_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY crun_txz_md5 "00000000000000000000000000000000">
|
|
|
|
<!ENTITY netavark_txz_version "0.0.0">
|
|
<!ENTITY netavark_txz_file "netavark-&netavark_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY netavark_txz_md5 "00000000000000000000000000000000">
|
|
|
|
<!ENTITY aardvark_dns_txz_version "0.0.0">
|
|
<!ENTITY aardvark_dns_txz_file "aardvark-dns-&aardvark_dns_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY aardvark_dns_txz_md5 "00000000000000000000000000000000">
|
|
|
|
<!ENTITY passt_txz_version "0.0.0">
|
|
<!ENTITY passt_txz_file "passt-&passt_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY passt_txz_md5 "00000000000000000000000000000000">
|
|
|
|
<!ENTITY fuse_overlayfs_txz_version "0.0.0">
|
|
<!ENTITY fuse_overlayfs_txz_file "fuse-overlayfs-&fuse_overlayfs_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY fuse_overlayfs_txz_md5 "00000000000000000000000000000000">
|
|
|
|
<!-- unraid-podman is this project's OWN scaffolding package (rc.podman,
|
|
sbin/ scripts, event/ hooks, config templates — see
|
|
packages/unraid-podman/README.md), not an upstream component. Its
|
|
version always equals the plugin's own &version; — see
|
|
packages/unraid-podman/unraid-podman.SlackBuild, which reads it
|
|
straight out of this very file rather than tracking it twice. -->
|
|
<!ENTITY unraid_podman_txz_version "&version;">
|
|
<!ENTITY unraid_podman_txz_file "unraid-podman-&unraid_podman_txz_version;-&pkgArch;-&pkgBuild;&pkgTag;.txz">
|
|
<!ENTITY unraid_podman_txz_md5 "00000000000000000000000000000000">
|
|
]>
|
|
|
|
<PLUGIN name="&name;"
|
|
author="&author;"
|
|
version="&version;"
|
|
launch="&launch;"
|
|
pluginURL="&pluginURL;"
|
|
support="&supportURL;"
|
|
icon="cubes"
|
|
min="6.12.0">
|
|
<!--
|
|
min="6.12.0": Unraid 6.12 introduced folder-based (non-loopback) Docker
|
|
storage and is a reasonably conservative baseline for the cgroup v2 /
|
|
kernel networking features netavark, aardvark-dns, and passt assume. See
|
|
docs/ARCHITECTURE.md section 21 (open question — revisit if real-world
|
|
testing shows an earlier or later minimum is actually required).
|
|
-->
|
|
|
|
<CHANGES>
|
|
##podman
|
|
|
|
###0.0.0
|
|
- Initial scaffolding. Not a functional release — see CHANGELOG.md for the
|
|
authoritative, up-to-date history; this block is kept in sync with it by
|
|
hand at release time (scripts/release.sh does not touch this section).
|
|
</CHANGES>
|
|
|
|
<!--
|
|
Pre-install sanity check: this project only builds/ships x86_64 packages
|
|
(see versions.env's PKG_ARCH) — fail with a clear message on any other
|
|
architecture rather than letting eight package downloads 404 one by one.
|
|
-->
|
|
<FILE Run="/bin/bash">
|
|
<INLINE>
|
|
if [ "$(uname -m)" != "x86_64" ]; then
|
|
echo "unraid-podman only supports x86_64 (detected: $(uname -m)) - aborting install."
|
|
exit 1
|
|
fi
|
|
</INLINE>
|
|
</FILE>
|
|
|
|
<!--
|
|
The seven upstream component packages. Each is downloaded straight into
|
|
its backup slot under /boot/config/plugins/&name;/backup/packages/&version;/
|
|
(grouped by PLUGIN version, not each component's own version — a rollback
|
|
targets "this plugin release" as one unit, see
|
|
plugin/sbin/podman-backup.sh's header comment) and installed from there
|
|
in place via upgradepkg's install new / reinstall flags, which handle
|
|
both a fresh install and an update to a newer version identically (see
|
|
file header comment). This download-destination-doubles-as-backup approach is
|
|
what makes plugin/sbin/podman-backup.sh's restore-packages command work
|
|
with no separate copy step.
|
|
-->
|
|
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&podman_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&podman_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&podman_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&conmon_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&conmon_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&conmon_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&crun_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&crun_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&crun_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&netavark_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&netavark_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&netavark_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&aardvark_dns_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&aardvark_dns_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&aardvark_dns_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&passt_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&passt_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&passt_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&fuse_overlayfs_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&fuse_overlayfs_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&fuse_overlayfs_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<!--
|
|
The plugin's own scaffolding package — rc.podman, sbin/ helper scripts,
|
|
the event/ hooks below, and default config templates. See
|
|
packages/unraid-podman/README.md.
|
|
-->
|
|
<FILE Name="/boot/config/plugins/&name;/backup/packages/&version;/&unraid_podman_txz_file;" Run="upgradepkg --install-new --reinstall">
|
|
<URL>
|
|
&baseURL;/&unraid_podman_txz_file;
|
|
</URL>
|
|
<MD5>
|
|
&unraid_podman_txz_md5;
|
|
</MD5>
|
|
</FILE>
|
|
|
|
<!--
|
|
Postinstall: everything that has to happen AFTER the eight packages above
|
|
are on disk, but isn't itself package content — directory/config
|
|
seeding, the install-manifest that plugin/sbin/podman-verify-packages.sh
|
|
and podman-update-packages.sh read, and the first start. Runs on both
|
|
fresh install and every update (Unraid re-runs the whole .plg either way)
|
|
— every step here is written to be idempotent, per
|
|
docs/ARCHITECTURE.md section 7.
|
|
-->
|
|
<!--
|
|
IMPORTANT for anyone editing this block: it is deliberately NOT wrapped
|
|
in <![CDATA[ ]]>. CDATA sections suppress XML entity expansion entirely,
|
|
which would leave literal, unexpanded text like "&version;" in the
|
|
generated installed-versions.env instead of the real version number —
|
|
confirmed by direct testing against this exact file. This is also why
|
|
real Unraid plugins (community.applications, unassigned.devices) never
|
|
wrap their entity-referencing INLINE scripts in CDATA either. The
|
|
practical consequence: avoid literal '<' in this script (heredocs
|
|
included) — a sequence of individual "echo >>" lines is used below
|
|
instead for exactly that reason. A lone '>' is fine unescaped in XML
|
|
content (only '<' and '&' are not) — verified empirically, not assumed.
|
|
-->
|
|
<FILE Run="/bin/bash">
|
|
<INLINE>
|
|
set -u
|
|
|
|
echo "Setting permissions..."
|
|
chmod 0755 /etc/rc.d/rc.podman
|
|
chmod 0755 /usr/local/sbin/*.sh
|
|
chmod 0755 /usr/local/emhttp/plugins/podman/event/disks_mounted
|
|
chmod 0755 /usr/local/emhttp/plugins/podman/event/stopping
|
|
|
|
echo "Writing installed-package manifest..."
|
|
mkdir -p /usr/local/share/unraid-podman
|
|
MANIFEST=/usr/local/share/unraid-podman/installed-versions.env
|
|
echo "# Generated by podman.plg postinstall - do not edit by hand." > "$MANIFEST"
|
|
echo "# Read by podman-verify-packages.sh and podman-update-packages.sh." >> "$MANIFEST"
|
|
echo "PLUGIN_VERSION=\"&version;\"" >> "$MANIFEST"
|
|
echo "PODMAN_INSTALLED_VERSION=\"&podman_txz_version;\"" >> "$MANIFEST"
|
|
echo "CONMON_INSTALLED_VERSION=\"&conmon_txz_version;\"" >> "$MANIFEST"
|
|
echo "CRUN_INSTALLED_VERSION=\"&crun_txz_version;\"" >> "$MANIFEST"
|
|
echo "NETAVARK_INSTALLED_VERSION=\"&netavark_txz_version;\"" >> "$MANIFEST"
|
|
echo "AARDVARK_DNS_INSTALLED_VERSION=\"&aardvark_dns_txz_version;\"" >> "$MANIFEST"
|
|
echo "PASST_INSTALLED_VERSION=\"&passt_txz_version;\"" >> "$MANIFEST"
|
|
echo "FUSE_OVERLAYFS_INSTALLED_VERSION=\"&fuse_overlayfs_txz_version;\"" >> "$MANIFEST"
|
|
echo "UNRAID_PODMAN_INSTALLED_VERSION=\"&unraid_podman_txz_version;\"" >> "$MANIFEST"
|
|
|
|
echo "Seeding /boot/config/plugins/podman/ configuration (existing files left untouched)..."
|
|
/usr/local/sbin/podman-config.sh seed
|
|
|
|
echo "Verifying package installation..."
|
|
if /usr/local/sbin/podman-verify-packages.sh --quiet; then
|
|
echo "Package verification OK."
|
|
else
|
|
echo "WARNING: package verification reported problems - see /boot/config/plugins/podman/plugin.log"
|
|
fi
|
|
|
|
echo "Starting podman..."
|
|
if /etc/rc.d/rc.podman start; then
|
|
echo ""
|
|
echo "----------------------------------------------------"
|
|
echo " unraid-podman &version; has been installed and started."
|
|
echo " CLI: podman --url unix:///var/run/podman/podman.sock ..."
|
|
echo " Docs: https://github.com/&github;"
|
|
echo "----------------------------------------------------"
|
|
echo ""
|
|
else
|
|
echo ""
|
|
echo "----------------------------------------------------"
|
|
echo " unraid-podman &version; was installed but did not start cleanly."
|
|
echo " It will be retried automatically the next time the array starts"
|
|
echo " (see /usr/local/emhttp/plugins/podman/event/disks_mounted)."
|
|
echo " Check /boot/config/plugins/podman/plugin.log for details."
|
|
echo "----------------------------------------------------"
|
|
echo ""
|
|
fi
|
|
</INLINE>
|
|
</FILE>
|
|
|
|
<!--
|
|
Uninstall. Triggered by Unraid's Plugin Manager when the user clicks
|
|
"Remove" — the Method="remove" attribute is what makes this block
|
|
(rather than any of the install blocks above) run in that case.
|
|
|
|
Order matters: podman-uninstall-cleanup.sh runs FIRST, while the
|
|
unraid-podman package (which contains it, at /usr/local/sbin/) is still
|
|
on disk — removepkg-ing it out from under itself mid-script would be a
|
|
mistake. See that script's own header comment for exactly what is and
|
|
is not removed by default (user data is preserved unless the purge-data
|
|
flag is passed, which this normal removal flow deliberately never does).
|
|
-->
|
|
<!-- Not CDATA-wrapped — see the comment above the postinstall block for why: this content needs its &..._txz_file; entity references expanded, and CDATA would suppress that. Nothing here needs an unescaped '<'. -->
|
|
<FILE Run="/bin/bash" Method="remove">
|
|
<INLINE>
|
|
echo "Running unraid-podman cleanup..."
|
|
/usr/local/sbin/podman-uninstall-cleanup.sh
|
|
|
|
echo "Removing packages..."
|
|
removepkg &podman_txz_file;
|
|
removepkg &conmon_txz_file;
|
|
removepkg &crun_txz_file;
|
|
removepkg &netavark_txz_file;
|
|
removepkg &aardvark_dns_txz_file;
|
|
removepkg &passt_txz_file;
|
|
removepkg &fuse_overlayfs_txz_file;
|
|
removepkg &unraid_podman_txz_file;
|
|
|
|
echo ""
|
|
echo "unraid-podman removed. Your configuration, backups, and container"
|
|
echo "storage under /boot/config/plugins/podman/ and the configured"
|
|
echo "STORAGE_PATH were left in place - see docs/INSTALL.md if you want"
|
|
echo "to remove them too."
|
|
echo ""
|
|
</INLINE>
|
|
</FILE>
|
|
|
|
</PLUGIN>
|