Skip to content

Commit 03efdad

Browse files
committed
feat: podman kubedock enhancement
Signed-off-by: Mattia Mascia <[email protected]>
1 parent 4a1e80b commit 03efdad

File tree

7 files changed

+355
-3
lines changed

7 files changed

+355
-3
lines changed

base/ubi9/Dockerfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,15 @@ RUN KUBEDOCK_ARCH="linux_amd64" && \
145145
COPY --chown=0:0 kubedock_setup.sh /usr/local/bin/kubedock_setup
146146

147147
# Configure Podman wrapper
148-
ENV PODMAN_WRAPPER_PATH=/usr/bin/podman.wrapper
149-
ENV ORIGINAL_PODMAN_PATH=/usr/bin/podman.orig
148+
COPY --chown=0:0 kubedock_setup.sh /usr/local/bin/kubedock_setup
149+
ENV PODMAN_WRAPPER_PATH=/usr/bin/podman.wrapper \
150+
ORIGINAL_PODMAN_PATH=/usr/bin/podman.orig
150151
COPY --chown=0:0 podman-wrapper.sh "${PODMAN_WRAPPER_PATH}"
152+
COPY --chown=0:0 podman-compose-down-wrapper.sh "/usr/bin/podman-compose-down-wrapper.sh"
153+
COPY --chown=0:0 podman-interactive-wrapper.sh "/usr/bin/podman-interactive-wrapper.sh"
154+
COPY --chown=0:0 podman-cp-wrapper.sh "/usr/bin/podman-cp-wrapper.sh"
151155
RUN mv /usr/bin/podman "${ORIGINAL_PODMAN_PATH}"
156+
COPY --chown=0:0 docker.sh "/usr/bin/docker"
152157

153158
COPY --chown=0:0 entrypoint.sh /
154159
COPY --chown=0:0 .stow-local-ignore /home/tooling/

base/ubi9/docker.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/sh
2+
3+
[ -e /etc/containers/nodocker ] || \
4+
echo "Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg." >&2
5+
if [ "${KUBEDOCK_ENABLED:-false}" = "true" ]; then
6+
exec /usr/bin/podman.wrapper "$@"
7+
else
8+
exec /usr/bin/podman "$@"
9+
fi

base/ubi9/kubedock_setup.sh

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,28 @@ if [ "${KUBEDOCK_ENABLED:-false}" = "true" ]; then
2525
if [ -f $KUBECONFIG ]; then
2626
echo "Kubeconfig found."
2727

28-
KUBEDOCK_PARAMS=${KUBEDOCK_PARAMS:-"--reverse-proxy --kubeconfig $KUBECONFIG"}
28+
echo "Fix Kubeconfig permission."
29+
attempts=5
30+
while [ $attempts -gt 0 ]; do
31+
if [ -f /home/user/.kube/config ]; then
32+
chmod 600 /home/user/.kube/config
33+
break
34+
else
35+
echo "Config file not found. Retrying..."
36+
attempts=$((attempts - 1))
37+
sleep 5
38+
fi
39+
done
40+
41+
if [ -z "$KUBEDOCK_PARAMS" ]; then
42+
KUBEDOCK_PARAMS="--reverse-proxy --kubeconfig $KUBECONFIG"
43+
if [ -n "$REQUEST_CPU" ] && [ -n "$REQUEST_MEMORY" ]; then
44+
KUBEDOCK_PARAMS="$KUBEDOCK_PARAMS --request-cpu=$REQUEST_CPU --request-memory=$REQUEST_MEMORY"
45+
fi
46+
if [ -n "$REAPER_KEEPMAX" ]; then
47+
KUBEDOCK_PARAMS="$KUBEDOCK_PARAMS --reapmax=$REAPER_KEEPMAX"
48+
fi
49+
fi
2950

3051
echo "Starting kubedock with params \"${KUBEDOCK_PARAMS}\"..."
3152

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# This script is a wrapper for 'podman compose down' or 'docker compose down'
5+
# It removes the containers/services defined in the docker-compose file using 'podman rm'
6+
# This is needed when running with kubedock, as 'compose down' cannot shut down pods directly
7+
8+
usage() {
9+
echo "Usage: $0 [OPTIONS] [SERVICES]"
10+
echo " OPTIONS: Options for docker-compose down (e.g., -f docker-compose.yml)"
11+
echo " SERVICES: Optional list of services to remove"
12+
exit 1
13+
}
14+
15+
# Parse options and service names
16+
COMPOSE_FILE="docker-compose.yml"
17+
OPTIONS=()
18+
SERVICES=()
19+
while [[ $# -gt 0 ]]; do
20+
case "$1" in
21+
-f|--file)
22+
if [[ -n "${2:-}" ]]; then
23+
COMPOSE_FILE="$2"
24+
OPTIONS+=("$1" "$2")
25+
shift 2
26+
else
27+
echo "Error: Missing argument for $1"
28+
usage
29+
fi
30+
;;
31+
--file=*)
32+
COMPOSE_FILE="${1#*=}"
33+
OPTIONS+=("$1")
34+
shift
35+
;;
36+
-h|--help)
37+
usage
38+
;;
39+
-*)
40+
OPTIONS+=("$1")
41+
shift
42+
;;
43+
*)
44+
SERVICES+=("$1")
45+
shift
46+
;;
47+
esac
48+
done
49+
50+
# If no -f/--file was provided, support both docker-compose.yml and docker-compose.yaml
51+
if [[ "${COMPOSE_FILE}" == "docker-compose.yml" ]]; then
52+
if [[ -f "docker-compose.yml" ]]; then
53+
COMPOSE_FILE="docker-compose.yml"
54+
elif [[ -f "docker-compose.yaml" ]]; then
55+
COMPOSE_FILE="docker-compose.yaml"
56+
else
57+
echo "Error: No docker-compose.yml or docker-compose.yaml found in the current directory."
58+
exit 1
59+
fi
60+
fi
61+
62+
if [[ ! -f "$COMPOSE_FILE" ]]; then
63+
echo "Error: Compose file '$COMPOSE_FILE' not found."
64+
exit 1
65+
fi
66+
67+
# Get service names from compose file if none specified
68+
if [[ ${#SERVICES[@]} -eq 0 ]]; then
69+
# Try to use yq if available, else fallback to grep/sed/awk
70+
if command -v yq >/dev/null 2>&1; then
71+
mapfile -t SERVICES < <(yq '.services | keys | .[]' "$COMPOSE_FILE")
72+
else
73+
# Fallback: extract service names by finding top-level keys under 'services:'
74+
mapfile -t SERVICES < <(awk '/services:/ {flag=1; next} /^[^[:space:]]/ {flag=0} flag && /^[[:space:]]+[a-zA-Z0-9_-]+:/ {gsub(":",""); print $1}' "$COMPOSE_FILE" | sed 's/^[[:space:]]*//')
75+
fi
76+
fi
77+
78+
if [[ ${#SERVICES[@]} -eq 0 ]]; then
79+
echo "No services found in compose file '$COMPOSE_FILE'."
80+
exit 0
81+
fi
82+
83+
# Compose container name: <current-dir>-<service-name>-1
84+
PROJECT_NAME="$(basename "$PWD")"
85+
86+
echo "Removing services: ${SERVICES[*]}"
87+
for svc in "${SERVICES[@]}"; do
88+
# Try to get container_name from compose file
89+
CONTAINER_NAME=""
90+
if command -v yq >/dev/null 2>&1; then
91+
CONTAINER_NAME=$(yq ".services.${svc}.container_name // \"\"" "$COMPOSE_FILE" | tr -d '"')
92+
fi
93+
if [[ -z "$CONTAINER_NAME" ]]; then
94+
CONTAINER_NAME="${PROJECT_NAME}-${svc}-1"
95+
fi
96+
# Check if the container exists
97+
if ! podman ps -a --format '{{.Names}}' | grep -Fxq "$CONTAINER_NAME"; then
98+
echo "No container found for service '$svc' (expected name: $CONTAINER_NAME)"
99+
continue
100+
fi
101+
echo "Removing container: $CONTAINER_NAME"
102+
podman rm -f "$CONTAINER_NAME"
103+
done
104+
105+
echo "All specified services have been removed."

base/ubi9/podman-cp-wrapper.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# This script replaces 'podman cp' with 'oc cp', mapping the container to the correct pod via the kubedock label.
5+
6+
# Parse options (stop at first non-option argument)
7+
OPTIONS=()
8+
while [[ $# -gt 0 ]]; do
9+
case "$1" in
10+
-*) OPTIONS+=("$1"); shift ;;
11+
*) break ;;
12+
esac
13+
done
14+
15+
# Now $1 and $2 are [CONTAINER:]SRC_PATH [CONTAINER:]DEST_PATH
16+
if [[ $# -lt 2 || -z "${1:-}" || -z "${2:-}" ]]; then
17+
echo "Error: Both [CONTAINER:]SRC_PATH and [CONTAINER:]DEST_PATH must be specified." >&2
18+
exit 1
19+
fi
20+
21+
SRC="$1"
22+
DEST="$2"
23+
24+
get_pod_for_container() {
25+
local container_ref="$1"
26+
if [[ "$container_ref" == *:* ]]; then
27+
local container_id="${container_ref%%:*}"
28+
# Find pod with label kubedock.containerid=<container_id>
29+
local pod_name
30+
pod_name=$(oc get pods -l "kubedock.containerid=${container_id}" -o jsonpath='{.items[0].metadata.name}')
31+
if [[ -z "$pod_name" ]]; then
32+
echo "Error: No pod found for container id: $container_id" >&2
33+
exit 1
34+
fi
35+
# Return pod:rest_of_path
36+
echo "${pod_name}:${container_ref#*:}"
37+
else
38+
# No container ref, just return as is
39+
echo "$container_ref"
40+
fi
41+
}
42+
43+
OC_SRC=$(get_pod_for_container "$SRC")
44+
OC_DEST=$(get_pod_for_container "$DEST")
45+
46+
#echo exec oc cp "${OPTIONS[@]}" "$OC_SRC" "$OC_DEST"
47+
exec oc cp "${OPTIONS[@]}" "$OC_SRC" "$OC_DEST"
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# This script transparently replaces problematic 'podman run -it ...' invocations
5+
# with a workaround for kubedock compatibility:
6+
# podman exec -it $(podman run -d --rm [OPTIONS] IMAGE tail -f /dev/null) [COMMAND]
7+
8+
usage() {
9+
echo "Usage: $0 run [OPTIONS] IMAGE [COMMAND] [ARG...]"
10+
exit 1
11+
}
12+
13+
ARGS=( "$@" )
14+
if [[ "${ARGS[0]:-}" != "run" ]]; then
15+
usage
16+
fi
17+
18+
RUN_OPTS=()
19+
IMAGE=""
20+
CMD_ARGS=()
21+
22+
skip_next=0
23+
found_image=0
24+
for ((i=1; i<${#ARGS[@]}; i++)); do
25+
arg="${ARGS[$i]}"
26+
if [[ $skip_next -eq 1 ]]; then
27+
# Only skip for --tty/--interactive with space value
28+
RUN_OPTS+=("$arg")
29+
skip_next=0
30+
continue
31+
fi
32+
if [[ $found_image -eq 0 ]]; then
33+
# Remove all forms of interactive/tty options for internal run
34+
case "$arg" in
35+
-i|-t|-it|-ti)
36+
continue
37+
;;
38+
--tty|--interactive)
39+
# skip this and the next arg if it does not start with '-'
40+
if [[ $((i+1)) -lt ${#ARGS[@]} && "${ARGS[$((i+1))]}" != "-"* ]]; then
41+
skip_next=1
42+
fi
43+
continue
44+
;;
45+
--tty=*|--interactive=*)
46+
continue
47+
;;
48+
# Options that take a value
49+
-u=*|--user=*)
50+
# Handle -u=root and --user=root
51+
RUN_OPTS+=("--user=$(id -u)")
52+
continue
53+
;;
54+
-u|--user)
55+
# Handle -u root and --user root
56+
RUN_OPTS+=("--user=$(id -u)")
57+
((i++)) # Skip the next argument (the value)
58+
continue
59+
;;
60+
-v|--volume|-e|--env|-w|--workdir|--name|--hostname|--entrypoint|--add-host|--device|--label|--network|--cap-add|--cap-drop|--security-opt|--tmpfs|--ulimit|--mount|--publish|--expose|--dns|--dns-search|--dns-option|--mac-address|--memory|--memory-swap|--cpu-shares|--cpus|--cpu-period|--cpu-quota|--cpu-rt-runtime|--cpu-rt-period|--cpuset-cpus|--cpuset-mems|--blkio-weight|--blkio-weight-device|--device-read-bps|--device-write-bps|--device-read-iops|--device-write-iops|--shm-size|--sysctl|--log-driver|--log-opt|--restart|--stop-signal|--stop-timeout|--health-cmd|--health-interval|--health-retries|--health-timeout|--health-start-period|--userns|--cgroup-parent|--pid|--ipc|--uts|--runtime|--storage-opt|--tmpfs|--volume-driver|--volumes-from|--env-file|--add-host|--security-opt|--device|--group-add|--init|--isolation|--kernel-memory|--label|--log-driver|--log-opt|--memory-reservation|--memory-swappiness|--oom-kill-disable|--oom-score-adj|--pids-limit|--privileged|--publish-all|--read-only|--restart|--sig-proxy|--stop-signal|--tmpfs|--ulimit|--userns|--uts|--volume|--workdir)
61+
RUN_OPTS+=("$arg")
62+
skip_next=1
63+
continue
64+
;;
65+
--*=*)
66+
# long option with value, e.g. --workdir=/foo
67+
# filter out --tty= and --interactive=
68+
if [[ "$arg" == --tty=* || "$arg" == --interactive=* ]]; then
69+
continue
70+
fi
71+
if [[ "$arg" == --user=* ]]; then
72+
RUN_OPTS+=("--user=$(id -u)")
73+
continue
74+
fi
75+
RUN_OPTS+=("$arg")
76+
continue
77+
;;
78+
--)
79+
found_image=1
80+
continue
81+
;;
82+
-*)
83+
# Handle combined short options, e.g. -itv, -tiv, etc.
84+
# Remove i and t, keep the rest
85+
if [[ "$arg" =~ ^-([it]+)$ ]]; then
86+
# skip if only i/t/it/ti
87+
continue
88+
elif [[ "$arg" =~ ^-([it]+)(.+)$ ]]; then
89+
rest="${BASH_REMATCH[2]}"
90+
if [[ -n "$rest" ]]; then
91+
RUN_OPTS+=("-$rest")
92+
fi
93+
continue
94+
else
95+
RUN_OPTS+=("$arg")
96+
continue
97+
fi
98+
;;
99+
*)
100+
IMAGE="$arg"
101+
found_image=1
102+
continue
103+
;;
104+
esac
105+
else
106+
CMD_ARGS+=("$arg")
107+
fi
108+
done
109+
# Remove duplicate --rm if present
110+
has_rm=0
111+
for opt in "${RUN_OPTS[@]}"; do
112+
if [[ "$opt" == "--rm" ]]; then
113+
has_rm=1
114+
break
115+
fi
116+
done
117+
118+
119+
FINAL_RUN_OPTS=("${RUN_OPTS[@]}")
120+
if [[ $has_rm -eq 0 ]]; then
121+
FINAL_RUN_OPTS+=("--rm")
122+
fi
123+
124+
if [[ -z "$IMAGE" ]]; then
125+
echo "Error: Could not determine image name in podman run command."
126+
usage
127+
fi
128+
129+
# Print the command for debug
130+
# echo podman run -d "${FINAL_RUN_OPTS[@]}" "$IMAGE" tail -f /dev/null
131+
132+
CONTAINER_ID=$(podman run -d "${FINAL_RUN_OPTS[@]}" "$IMAGE" tail -f /dev/null)
133+
134+
if [[ ${#CMD_ARGS[@]} -eq 0 ]]; then
135+
CMD_ARGS=(bash)
136+
fi
137+
138+
exec podman exec -it "$CONTAINER_ID" "${CMD_ARGS[@]}"

base/ubi9/podman-wrapper.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,33 @@ KUBEDOCK_SUPPORTED_COMMANDS=${KUBEDOCK_SUPPORTED_COMMANDS:-"run ps exec cp logs
66

77
PODMAN_ARGS=( "$@" )
88

9+
# Check for 'compose down' command and delegate to the special wrapper
10+
if [[ "${PODMAN_ARGS[0]:-}" == "compose" && "${PODMAN_ARGS[1]:-}" == "down" ]]; then
11+
# Forward all args after 'compose down' to the wrapper
12+
exec "/usr/bin/podman-compose-down-wrapper.sh" "${PODMAN_ARGS[@]:2}"
13+
fi
14+
15+
# Intercept 'podman run' with interactive/tty flags and delegate to the interactive wrapper
16+
if [[ "${PODMAN_ARGS[0]:-}" == "run" ]]; then
17+
has_interactive=0
18+
has_tty=0
19+
for arg in "${PODMAN_ARGS[@]}"; do
20+
case "$arg" in
21+
-i|--interactive) has_interactive=1 ;;
22+
-t|--tty) has_tty=1 ;;
23+
-it|-ti) has_interactive=1; has_tty=1 ;;
24+
esac
25+
done
26+
if [[ $has_interactive -eq 1 && $has_tty -eq 1 ]]; then
27+
exec "/usr/bin/podman-interactive-wrapper.sh" "${PODMAN_ARGS[@]}"
28+
fi
29+
fi
30+
31+
# Intercept 'podman cp' and delegate to the cp wrapper
32+
if [[ "${PODMAN_ARGS[0]:-}" == "cp" ]]; then
33+
exec "/usr/bin/podman-cp-wrapper.sh" "${PODMAN_ARGS[@]:1}"
34+
fi
35+
936
TRUE=0
1037
FALSE=1
1138

0 commit comments

Comments
 (0)