Skip to content

Conversation

@tmshlvck
Copy link

@tmshlvck tmshlvck commented Sep 21, 2025

Description

There were multiple requests for podman support:

Since rootless podman support is probably intractable at this point I am suggesting the basic support in rootful mode.

This RFC implements Podman support for Armbian builds to address mounting issues experienced with Podman while maintaining Docker compatibility.

Key changes:

  • Auto-detect container engine: prefers Docker, falls back to Podman
  • Use sudo with Podman (runs in root mode - not more secure than Docker)
  • Add required mount options (suid,dev) and --network host for Podman
  • Update all docker commands to use dynamic DOCKER_COMMAND variable

Technical notes:

  • Podman runs with sudo/root privileges, so security model matches Docker
  • Requires sudo access when using Podman (security consideration)
  • Solves Podman-specific mount permission and networking issues
  • Maintains full backward compatibility with existing Docker workflows
  • May need documentation updates

Documentation summary for feature / change

I believe that if this gets merged we could mention podman support as a note to the docker requirements.

How Has This Been Tested?

  • I tested multiple board image builds: bananapif3, rpi4b, orangepi5 - all OK

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes generate no new warnings

Summary by CodeRabbit

Release Notes

  • New Features
    • Added support for Podman as an alternative container runtime. The system now automatically detects and configures the appropriate container engine, with Docker remaining the default option.

@tmshlvck tmshlvck requested a review from a team as a code owner September 21, 2025 21:24
@github-actions github-actions bot added size/medium PR with more then 50 and less then 250 lines 11 Milestone: Fourth quarter release labels Sep 21, 2025
@github-actions
Copy link
Contributor

Hey @tmshlvck! 👋

Thanks for submitting your first pull request to the Armbian project — we're excited to have you contributing! 🧡
Your effort doesn’t just improve Armbian — it benefits the entire community of users and developers.

If you'd like to stay informed about project updates or collaborate more closely with the team,
you can optionally share some personal contact preferences at armbian.com/update-data.
This helps us keep in touch without relying solely on GitHub notifications.

Also, don’t forget to ⭐ star the repo if you haven’t already — and welcome aboard! 🚀

@github-actions github-actions bot added Needs review Seeking for review Framework Framework components labels Sep 21, 2025
@EvilOlaf EvilOlaf added the Needs Documentation New feature needs documentation entry label Sep 22, 2025
@EvilOlaf
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 22, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 22, 2025

Walkthrough

Adds runtime detection and abstraction for the container engine in lib/functions/host/docker.sh. Introduces three globals—DOCKER_COMMAND, DOCKER_NETWORK, and DOCKER_MOUNT_OPTS—initialized during a one-time info check to select between Docker and Podman (via sudo). Replaces direct docker calls with the dynamic command across info, image pull/list, volume/purge, build, launch, and preparation flows. Updates readiness checks and messages to accept either engine. Mount preparation now appends engine-specific options, and host networking is applied when Podman is used. New globals are exposed as readonly.

Changes

Cohort / File(s) Change summary
Host container runtime abstraction
lib/functions/host/docker.sh
Added runtime detection (Docker vs Podman) and three readonly globals: DOCKER_COMMAND, DOCKER_NETWORK, DOCKER_MOUNT_OPTS. Replaced direct docker invocations with $DOCKER_COMMAND across info, image operations, purge, build, launch, losetup/run, shell fallbacks. Appended mount options for Podman compatibility and adjusted readiness/error messages.

Sequence Diagram(s)

sequenceDiagram
    participant Init as Init script
    participant Detect as runtime detector
    participant Engine as Container engine (docker/podman)
    participant Runner as Container runner actions

    Init->>Detect: call detect_docker_info()
    Detect-->>Init: set DOCKER_COMMAND, DOCKER_NETWORK, DOCKER_MOUNT_OPTS (readonly)
    alt Docker selected
        Init->>Engine: run `docker info` via $DOCKER_COMMAND
    else Podman selected
        Init->>Engine: run `sudo podman info` via $DOCKER_COMMAND
    end

    Note over Init,Runner: Subsequent operations use $DOCKER_COMMAND and DOCKER_* settings
    Init->>Runner: image pull/list, build, launch, purge, mount with DOCKER_MOUNT_OPTS
    Runner->>Engine: execute container operations using $DOCKER_COMMAND and DOCKER_NETWORK
    Engine-->>Runner: return status/results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Potential review focal points:

  • Correctness of all substitutions from docker to $DOCKER_COMMAND in command contexts and quoting.
  • Proper readonly initialization and fallback behavior when both engines are absent.
  • Mount option concatenation and compatibility with Podman bind/volume syntax.
  • Network flag application for Podman launches and any sudo implications.

Suggested reviewers

  • chraac
  • igorpecovnik
  • EvilOlaf
  • AGM1968
  • rpardini

Poem

I’m a rabbit in the shell, I hop and I probe,
Found Docker or Podman to run every globe.
DOCKER_COMMAND set, mounts snug and tight,
Networks chosen true, containers take flight.
Hooray for small changes that make launches just right! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding Podman support as a Docker alternative, which aligns with the core objective of the PR.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 23e72dc and 6b2a5f7.

📒 Files selected for processing (1)
  • lib/functions/host/docker.sh (9 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: tmshlvck
Repo: armbian/build PR: 8660
File: lib/functions/host/docker.sh:519-529
Timestamp: 2025-09-22T06:01:50.284Z
Learning: In the Armbian build framework's docker.sh, DOCKER_MOUNT_OPTS is conditionally set: empty for Docker, and ",suid,dev" for Podman to handle mount permission requirements.
Learnt from: tmshlvck
Repo: armbian/build PR: 8660
File: lib/functions/host/docker.sh:519-529
Timestamp: 2025-09-22T06:01:50.284Z
Learning: In the Armbian build framework's docker.sh, DOCKER_MOUNT_OPTS is conditionally set: empty for Docker, and ",suid,dev" for Podman to handle mount permission requirements.
📚 Learning: 2025-09-22T06:01:50.284Z
Learnt from: tmshlvck
Repo: armbian/build PR: 8660
File: lib/functions/host/docker.sh:519-529
Timestamp: 2025-09-22T06:01:50.284Z
Learning: In the Armbian build framework's docker.sh, DOCKER_MOUNT_OPTS is conditionally set: empty for Docker, and ",suid,dev" for Podman to handle mount permission requirements.

Applied to files:

  • lib/functions/host/docker.sh
📚 Learning: 2025-10-24T04:46:22.901Z
Learnt from: tabrisnet
Repo: armbian/build PR: 0
File: :0-0
Timestamp: 2025-10-24T04:46:22.901Z
Learning: In lib/functions/rootfs/rootfs-create.sh, the FIXME comment about mmdebstrap usage with --aptopt is a future note related to PR #8785, which hasn't been merged yet.

Applied to files:

  • lib/functions/host/docker.sh
📚 Learning: 2025-09-24T09:54:07.968Z
Learnt from: amazingfate
Repo: armbian/build PR: 8668
File: extensions/ufs.sh:2-2
Timestamp: 2025-09-24T09:54:07.968Z
Learning: In Armbian's build system, DOCKER_ARMBIAN_BASE_IMAGE must be set globally at file load time in extensions, not inside extension_prepare_config functions, because docker operations happen early in the build process and would default to ubuntu:noble if not set before docker_cli_prepare() runs.

Applied to files:

  • lib/functions/host/docker.sh
🧬 Code graph analysis (1)
lib/functions/host/docker.sh (2)
lib/functions/logging/runners.sh (1)
  • run_host_command_logged (204-206)
lib/functions/cli/cli-docker.sh (2)
  • cli_docker_run (32-112)
  • cli_docker_pre_run (10-30)
🔇 Additional comments (6)
lib/functions/host/docker.sh (6)

45-73: ✓ Container engine detection and globals initialization look solid.

The detection logic correctly prefers Docker (if available) and falls back to Podman with sudo. Making the globals readonly after initialization prevents accidental mutations downstream. Good defensive design.


89-103: ✓ is_docker_ready_to_go updated appropriately.

Guard clause now checks for either docker or podman, and error messaging reflects both runtimes. Clean update.


113-126: ✓ Previous quoting issue resolved.

The unquoted $DOCKER_COMMAND in set statements (lines 117, 125) and pipe expressions (lines 113-114) correctly allows word splitting for "sudo podman". The previous review comment flagged a quoted form; this version correctly uses unquoting.


339-376: ✓ Image operations use dynamic $DOCKER_COMMAND correctly.

Unquoted invocations at lines 339, 352, 355, and 376 properly allow word splitting for "sudo podman". Consistent and correct throughout this segment.


601-607: ✓ losetup and launch invocations correctly use dynamic command and network variables.

Unquoted expansion of $DOCKER_COMMAND and $DOCKER_NETWORK is appropriate here. Both expand correctly:

  • $DOCKER_COMMAND splits "sudo podman" into separate tokens.
  • $DOCKER_NETWORK expands to empty (Docker) or "--network host" (Podman), correctly passed as separate arguments.

639-640: ✓ Volume purge operations use dynamic command correctly.

Unquoted $DOCKER_COMMAND properly allows "sudo podman" word splitting.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
lib/functions/host/docker.sh (1)

63-63: Guard against sudo prompts during readiness.
If sudo requires a TTY/password, $DOCKER_COMMAND info can hang. The sudo -n tweak above prevents this; alternatively, detect sudo -n support up front and surface a clear error.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 684936e and 23e72dc.

📒 Files selected for processing (1)
  • lib/functions/host/docker.sh (9 hunks)
🔇 Additional comments (6)
lib/functions/host/docker.sh (6)

50-60: Confirm downstream expectations for DOCKER_IN_PATH.

You set DOCKER_IN_PATH="yes" only when docker is present; for Podman it remains "no". If other modules gate behavior on DOCKER_IN_PATH, Podman runs may be misclassified. Consider either setting DOCKER_IN_PATH="yes" for Podman as well or introducing a neutral ENGINE_IN_PATH flag.


89-91: Good readiness broadening to accept either engine.
This check now correctly allows Docker or Podman in PATH. LGTM.


339-356: Build/pull paths look compatible across engines.
images -q and build -t -f map well to both Docker and Podman. No issues spotted.

Also applies to: 376-377


601-602: Engine-conditional host networking is wired correctly.
Using DOCKER_NETWORK only when set cleanly applies host networking for Podman without impacting Docker.

Also applies to: 607-608


639-641: Volume purge switched to dynamic engine correctly.
Using $DOCKER_COMMAND volume … aligns with the abstraction.


45-60: Stop treating the runtime command as a single string; add non-interactive sudo and root detection for Podman.

File: lib/functions/host/docker.sh (around lines 45-60; also apply to the other Podman handling at ~71-74)

  • Reason: "sudo podman" as a single scalar breaks safe argument splitting and can hang on password prompts; prefer skipping sudo when already root and use non-interactive sudo (-n) otherwise.
-		elif [[ -n "$(command -v podman)" ]]; then
-			DOCKER_COMMAND="sudo podman"
-			DOCKER_NETWORK="--network host"
-			DOCKER_MOUNT_OPTS=",suid,dev"  # Required mount options for Podman
-			display_alert "Podman detected" "Using Podman with sudo (required for Armbian builds)" "info"
+		elif [[ -n "$(command -v podman)" ]]; then
+			if [[ $EUID -eq 0 ]]; then
+				DOCKER_COMMAND="podman"
+			else
+				DOCKER_COMMAND="sudo -n podman" # non-interactive to avoid hanging on readiness checks
+			fi
+			DOCKER_NETWORK="--network host"
+			# For --mount, supply a plain options list; used later as options=${DOCKER_MOUNT_OPTS}
+			DOCKER_MOUNT_OPTS="rw,dev,suid"
+			display_alert "Podman detected" "Using Podman ($([[ $EUID -eq 0 ]] && echo 'root' || echo 'sudo -n'))" "info"
  • Optional: refactor DOCKER_COMMAND into an array and invoke as "${DOCKER_COMMAND[@]}" everywhere to avoid future word-splitting issues.

Comment on lines 117 to 118
set -- "$DOCKER_COMMAND" "$@"
fi
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Don’t quote $DOCKER_COMMAND when resetting $@; current code makes it a single, invalid argv.

set -- "$DOCKER_COMMAND" "$@" turns "sudo podman" into one token, causing command-not-found later. Allow intended splitting or (better) switch DOCKER_COMMAND to an array.

Minimal fix:

-		set -- "$DOCKER_COMMAND" "$@"
+		# shellcheck disable=SC2086 # intentional word splitting for DOCKER_COMMAND
+		set -- $DOCKER_COMMAND "$@"

Apply to both occurrences in this function.

Also applies to: 125-126

🤖 Prompt for AI Agents
In lib/functions/host/docker.sh around lines 117-118 (and also update the
similar occurrence at 125-126), the code uses set -- "$DOCKER_COMMAND" "$@"
which quotes the whole DOCKER_COMMAND string into a single argv (e.g. "sudo
podman") causing later command-not-found; fix by either unquoting to allow
word-splitting if DOCKER_COMMAND is a plain string: set -- $DOCKER_COMMAND "$@"
; or, preferably, change DOCKER_COMMAND to an array and use safe array
expansion: set -- "${DOCKER_COMMAND[@]}" "$@"; apply the same change to both
occurrences.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, v2 patch will be submitted.

Comment on lines +519 to 529
DOCKER_ARGS+=("--mount" "type=volume,destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
;;
bind)
display_alert "Mounting" "bind mount for '${MOUNT_DIR}'" "debug"
mkdir -p "${SRC}/${MOUNT_DIR}"
DOCKER_ARGS+=("--mount" "type=bind,source=${SRC}/${MOUNT_DIR},target=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}")
DOCKER_ARGS+=("--mount" "type=bind,source=${SRC}/${MOUNT_DIR},target=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
;;
namedvolume)
display_alert "Mounting" "named volume id '${volume_id}' for '${MOUNT_DIR}'" "debug"
DOCKER_ARGS+=("--mount" "type=volume,source=armbian-${volume_id},destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}")
DOCKER_ARGS+=("--mount" "type=volume,source=armbian-${volume_id},destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
;;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

❓ Verification inconclusive

Fix invalid --mount syntax; pass options via options=… instead of appending raw flags to destination.

Appending ",suid,dev" after destination=… is not a valid key=value pair for Docker/Podman --mount. Use options=… so both engines parse mount flags correctly.

Apply this diff:

-				DOCKER_ARGS+=("--mount" "type=volume,destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
+				DOCKER_ARGS+=("--mount" "type=volume,destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS:+,options=${DOCKER_MOUNT_OPTS}}")
...
-				DOCKER_ARGS+=("--mount" "type=bind,source=${SRC}/${MOUNT_DIR},target=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
+				DOCKER_ARGS+=("--mount" "type=bind,source=${SRC}/${MOUNT_DIR},target=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS:+,options=${DOCKER_MOUNT_OPTS}}")
...
-				DOCKER_ARGS+=("--mount" "type=volume,source=armbian-${volume_id},destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
+				DOCKER_ARGS+=("--mount" "type=volume,source=armbian-${volume_id},destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS:+,options=${DOCKER_MOUNT_OPTS}}")

Fix invalid --mount syntax; pass options via options=… instead of appending raw flags to destination.

Appending ",suid,dev" (or similar) after destination=… is not a valid key=value pair for Docker/Podman --mount. Use options=… so both engines parse mount flags correctly.

Apply this diff:

-				DOCKER_ARGS+=("--mount" "type=volume,destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
+				DOCKER_ARGS+=("--mount" "type=volume,destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS:+,options=${DOCKER_MOUNT_OPTS}}")
...
-				DOCKER_ARGS+=("--mount" "type=bind,source=${SRC}/${MOUNT_DIR},target=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
+				DOCKER_ARGS+=("--mount" "type=bind,source=${SRC}/${MOUNT_DIR},target=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS:+,options=${DOCKER_MOUNT_OPTS}}")
...
-				DOCKER_ARGS+=("--mount" "type=volume,source=armbian-${volume_id},destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
+				DOCKER_ARGS+=("--mount" "type=volume,source=armbian-${volume_id},destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS:+,options=${DOCKER_MOUNT_OPTS}}")

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In lib/functions/host/docker.sh around lines 519-529, the --mount invocations
append raw mount flags to the destination (destination=...${DOCKER_MOUNT_OPTS})
which is invalid; change them to use options=... instead. For each
DOCKER_ARGS+=("--mount"
"...destination=${DOCKER_ARMBIAN_TARGET_PATH}/${MOUNT_DIR}${DOCKER_MOUNT_OPTS}")
line, split DOCKER_MOUNT_OPTS into an options clause (strip any leading comma)
and append ,options=${OPTIONS} to the --mount string (omit the options= part
entirely when DOCKER_MOUNT_OPTS is empty), e.g.
destination=.../${MOUNT_DIR}[,options=${DOCKER_MOUNT_OPTS_STRIPPED}]; apply this
for volume, bind and namedvolume cases so Docker/Podman parse mount flags
correctly.

Copy link
Author

Choose a reason for hiding this comment

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

The DOCKER_MOUNT_OPTS is set at podman detection to the required flags or kept empty for docker. There should be no potential for mixing the flags with docker.

This RFC implements Podman support for Armbian builds to address mounting
issues experienced with Podman while maintaining Docker compatibility.

Key changes:
- Auto-detect container engine: prefers Docker, falls back to Podman
- Use sudo with Podman (runs in root mode - not more secure than Docker)
- Add required mount options (suid,dev) and --network host for Podman
- Update all docker commands to use dynamic DOCKER_COMMAND variable

Technical notes:
- Podman runs with sudo/root privileges, so security model matches Docker
- Requires sudo access when using Podman (security consideration)
- Solves Podman-specific mount permission and networking issues
- Maintains full backward compatibility with existing Docker workflows
- May need documentation updates
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

11 Milestone: Fourth quarter release Framework Framework components Needs Documentation New feature needs documentation entry Needs review Seeking for review size/medium PR with more then 50 and less then 250 lines

Development

Successfully merging this pull request may close these issues.

2 participants