@@ -42,49 +42,68 @@ function get_docker_info_once() {
4242 if [[ -z " ${DOCKER_INFO} " ]]; then
4343 declare -g DOCKER_INFO
4444 declare -g DOCKER_IN_PATH=" no"
45- declare -g DOCKER_IS_PODMAN
46-
47- # if "docker" is in the PATH...
45+ declare -g DOCKER_IS_PODMAN=" "
46+ declare -g DOCKER_COMMAND=" docker"
47+ declare -g DOCKER_NETWORK=" "
48+
49+ # Detect container engine - prefer Docker for compatibility, but support Podman
50+ # Podman support requires additional host-side setup on some distributions:
51+ #
52+ # For Fedora/RHEL/derivatives, install QEMU user-mode emulation on the HOST:
53+ # sudo dnf install qemu-user-binfmt qemu-user-static-aarch64 \
54+ # qemu-user-static-arm qemu-user-static-riscv
55+ #
56+ # This is required because Podman relies on host binfmt_misc handlers with the "F" (Fix) flag
57+ # for cross-architecture builds. Docker can work with QEMU inside containers, but host installation
58+ # is recommended for both engines.
4859 if [[ -n " $( command -v docker) " ]]; then
4960 display_alert " Docker is in the path" " Docker in PATH" " debug"
61+ DOCKER_COMMAND=" docker"
5062 DOCKER_IN_PATH=" yes"
63+ # Check if 'docker' is actually podman (e.g., podman-docker package)
64+ if docker --version | grep -q podman; then
65+ DOCKER_IS_PODMAN=" yes"
66+ display_alert " Podman detected" " docker command is podman alias" " info"
67+ fi
68+ elif [[ -n " $( command -v podman) " ]]; then
69+ # Standalone podman (no docker alias) - requires sudo for privileged operations
70+ DOCKER_COMMAND=" sudo podman"
71+ DOCKER_NETWORK=" --network host"
72+ DOCKER_IS_PODMAN=" yes"
73+ display_alert " Podman detected" " Using standalone Podman with sudo" " info"
5174 fi
5275
5376 # Shenanigans to go around error control & capture output in the same effort.
54- DOCKER_INFO=" $( { docker info 2> /dev/null && echo " DOCKER_INFO_OK" ; } || true) "
77+ DOCKER_INFO=" $( { $DOCKER_COMMAND info 2> /dev/null && echo " DOCKER_INFO_OK" ; } || true) "
5578 declare -g -r DOCKER_INFO=" ${DOCKER_INFO} " # readonly
5679
57- if docker --version | grep -q podman; then
58- DOCKER_IS_PODMAN=" yes"
59- # when `docker` is a shim to `podman`, it will report its version as "podman version #.#.#"
60- else
61- DOCKER_IS_PODMAN=" "
62- fi
63- declare -g -r DOCKER_IS_PODMAN=" ${DOCKER_IS_PODMAN} " # readonly
64-
65-
6680 declare -g DOCKER_INFO_OK=" no"
6781 if [[ " ${DOCKER_INFO} " =~ " DOCKER_INFO_OK" ]]; then
6882 DOCKER_INFO_OK=" yes"
6983 fi
7084 declare -g -r DOCKER_INFO_OK=" ${DOCKER_INFO_OK} " # readonly
85+ declare -g -r DOCKER_IS_PODMAN=" ${DOCKER_IS_PODMAN} "
86+ declare -g -r DOCKER_COMMAND=" ${DOCKER_COMMAND} "
87+ declare -g -r DOCKER_NETWORK=" ${DOCKER_NETWORK} "
7188 fi
7289 return 0
7390}
7491
7592# Usage: if is_docker_ready_to_go; then ...; fi
93+ # This function checks if a container engine (Docker or Podman) is available and functional.
94+ # It prefers Docker for compatibility but will automatically fall back to Podman if Docker is not found.
7695function is_docker_ready_to_go() {
7796 # For either Linux or Darwin.
7897 # Gotta tick all these boxes:
79- # 0) NOT ALREADY UNDER DOCKER.
80- # 1) can find the `docker` command in the path, via command -v
81- # 2) can run `docker info` without errors
98+ # 0) NOT ALREADY UNDER DOCKER/PODMAN .
99+ # 1) can find the `docker` or `podman` command in the path, via command -v
100+ # 2) can run `docker info` or `podman info` without errors
82101 if [[ " ${ARMBIAN_RUNNING_IN_CONTAINER} " == " yes" ]]; then
83102 display_alert " Can't use Docker" " Actually ALREADY UNDER DOCKER!" " debug"
84103 return 1
85104 fi
86- if [[ -z " $( command -v docker) " ]]; then
87- display_alert " Can't use Docker" " docker command not found" " debug"
105+ if [[ -z " $( command -v docker) " ]] && [[ -z " $( command -v podman ) " ]] ; then
106+ display_alert " Can't use Docker/Podman " " neither docker nor podman command found" " debug"
88107 return 1
89108 fi
90109
@@ -107,19 +126,19 @@ function cli_handle_docker() {
107126 # Purge Armbian Docker images
108127 if [[ " ${1} " == dockerpurge && -f /etc/debian_version ]]; then
109128 display_alert " Purging Armbian Docker containers" " " " wrn"
110- docker container ls -a | grep armbian | awk ' {print $1}' | xargs docker container rm & > /dev/null
111- docker image ls | grep armbian | awk ' {print $3}' | xargs docker image rm & > /dev/null
129+ $DOCKER_COMMAND container ls -a | grep armbian | awk ' {print $1}' | xargs $DOCKER_COMMAND container rm & > /dev/null
130+ $DOCKER_COMMAND image ls | grep armbian | awk ' {print $3}' | xargs $DOCKER_COMMAND image rm & > /dev/null
112131 # removes "dockerpurge" from $1, thus $2 becomes $1
113132 shift
114- set -- " docker " " $@ "
133+ set -- $DOCKER_COMMAND " $@ "
115134 fi
116135
117136 # Docker shell
118137 if [[ " ${1} " == docker-shell ]]; then
119138 # this swaps the value of $1 with 'docker', and life continues
120139 shift
121140 SHELL_ONLY=yes
122- set -- " docker " " $@ "
141+ set -- $DOCKER_COMMAND " $@ "
123142 fi
124143
125144}
@@ -336,7 +355,7 @@ function docker_cli_build_dockerfile() {
336355
337356 if [[ " ${do_force_pull} " == " no" ]]; then
338357 # Check if the base image is up to date.
339- local_image_sha=" $( docker images --no-trunc --quiet " ${DOCKER_ARMBIAN_BASE_IMAGE} " ) "
358+ local_image_sha=" $( $DOCKER_COMMAND images --no-trunc --quiet " ${DOCKER_ARMBIAN_BASE_IMAGE} " ) "
340359 display_alert " Checking if base image exists at all" " local_image_sha: '${local_image_sha} '" " debug"
341360 if [[ -n " ${local_image_sha} " ]]; then
342361 display_alert " Armbian docker image" " already exists: ${DOCKER_ARMBIAN_BASE_IMAGE} " " info"
@@ -349,10 +368,10 @@ function docker_cli_build_dockerfile() {
349368 if [[ " ${do_force_pull:- yes} " == " yes" ]]; then
350369 display_alert " Pulling" " ${DOCKER_ARMBIAN_BASE_IMAGE} " " info"
351370 local pull_failed=" yes"
352- run_host_command_logged docker pull " ${DOCKER_ARMBIAN_BASE_IMAGE} " && pull_failed=" no"
371+ run_host_command_logged $DOCKER_COMMAND pull " ${DOCKER_ARMBIAN_BASE_IMAGE} " && pull_failed=" no"
353372
354373 if [[ " ${pull_failed} " == " no" ]]; then
355- local_image_sha=" $( docker images --no-trunc --quiet " ${DOCKER_ARMBIAN_BASE_IMAGE} " ) "
374+ local_image_sha=" $( $DOCKER_COMMAND images --no-trunc --quiet " ${DOCKER_ARMBIAN_BASE_IMAGE} " ) "
356375 display_alert " New local image sha after pull" " local_image_sha: ${local_image_sha} " " debug"
357376 # print current date and time in epoch format; touches mtime of file
358377 echo " ${DOCKER_ARMBIAN_BASE_IMAGE} |${local_image_sha} |$( date +%s) " >> " ${docker_marker_dir} " /last-pull
@@ -373,7 +392,7 @@ function docker_cli_build_dockerfile() {
373392 display_alert " Building" " Dockerfile via '${DOCKER_BUILDX_OR_BUILD[*]} '" " info"
374393
375394 BUILDKIT_COLORS=" run=123,20,245:error=yellow:cancel=blue:warning=white" \
376- run_host_command_logged docker " ${DOCKER_BUILDX_OR_BUILD[@]} " -t " ${DOCKER_ARMBIAN_INITIAL_IMAGE_TAG} " -f " ${SRC} " /Dockerfile " ${SRC} "
395+ run_host_command_logged $DOCKER_COMMAND " ${DOCKER_BUILDX_OR_BUILD[@]} " -t " ${DOCKER_ARMBIAN_INITIAL_IMAGE_TAG} " -f " ${SRC} " /Dockerfile " ${SRC} "
377396}
378397
379398function docker_cli_prepare_launch() {
@@ -521,7 +540,7 @@ function docker_cli_prepare_launch() {
521540 bind)
522541 display_alert " Mounting" " bind mount for '${MOUNT_DIR} '" " debug"
523542 mkdir -p " ${SRC} /${MOUNT_DIR} "
524- DOCKER_ARGS+=(" --mount" " type=bind,source=${SRC} /${MOUNT_DIR} ,target=${DOCKER_ARMBIAN_TARGET_PATH} /${MOUNT_DIR} " )
543+ DOCKER_ARGS+=(" --mount" " type=bind,source=${SRC} /${MOUNT_DIR} ,target=${DOCKER_ARMBIAN_TARGET_PATH} /${MOUNT_DIR}${DOCKER_IS_PODMAN : +,exec,dev} " )
525544 ;;
526545 namedvolume)
527546 display_alert " Mounting" " named volume id '${volume_id} ' for '${MOUNT_DIR} '" " debug"
@@ -598,13 +617,13 @@ function docker_cli_launch() {
598617 # The amount of privileges and capabilities given is a bare minimum needed for losetup to work
599618 if [[ ! -e /dev/loop0 ]]; then
600619 display_alert " Running losetup in a temporary container" " because no loop devices exist" " info"
601- run_host_command_logged docker run --rm --privileged --cap-add=MKNOD " ${DOCKER_ARMBIAN_INITIAL_IMAGE_TAG} " /usr/sbin/losetup -f
620+ run_host_command_logged $DOCKER_COMMAND run $DOCKER_NETWORK --rm --privileged --cap-add=MKNOD " ${DOCKER_ARMBIAN_INITIAL_IMAGE_TAG} " /usr/sbin/losetup -f
602621 fi
603622
604623 display_alert " -----------------Relaunching in Docker after ${SECONDS} s------------------" " here comes the 🐳" " info"
605624
606625 local -i docker_build_result
607- if docker run " ${DOCKER_ARGS[@]} " " ${DOCKER_ARMBIAN_INITIAL_IMAGE_TAG} " /bin/bash " ${DOCKER_ARMBIAN_TARGET_PATH} /compile.sh" " ${ARMBIAN_CLI_FINAL_RELAUNCH_ARGS[@]} " ; then
626+ if $DOCKER_COMMAND run $DOCKER_NETWORK " ${DOCKER_ARGS[@]} " " ${DOCKER_ARMBIAN_INITIAL_IMAGE_TAG} " /bin/bash " ${DOCKER_ARMBIAN_TARGET_PATH} /compile.sh" " ${ARMBIAN_CLI_FINAL_RELAUNCH_ARGS[@]} " ; then
608627 docker_build_result=$? # capture exit code of test done in the line above.
609628 display_alert " -------------Docker run finished after ${SECONDS} s------------------------" " 🐳 successful" " info"
610629 else
@@ -636,8 +655,8 @@ function docker_purge_deprecated_volumes() {
636655 for mountpoint in " ${ARMBIAN_MOUNTPOINTS_DEPRECATED[@]} " ; do
637656 local volume_id=" armbian-${mountpoint// \/ / -} "
638657 display_alert " Purging deprecated Docker volume" " ${volume_id} " " info"
639- if docker volume inspect " ${volume_id} " & > /dev/null; then
640- run_host_command_logged docker volume rm " ${volume_id} "
658+ if $DOCKER_COMMAND volume inspect " ${volume_id} " & > /dev/null; then
659+ run_host_command_logged $DOCKER_COMMAND volume rm " ${volume_id} "
641660 display_alert " Purged deprecated Docker volume" " ${volume_id} OK" " info"
642661 else
643662 display_alert " Deprecated Docker volume not found" " ${volume_id} OK" " info"
0 commit comments