feat(docker): add host command bridge

This commit is contained in:
Federico Jaramillo Martinez
2026-06-20 21:58:53 +02:00
parent a8088483ef
commit 099d770eeb
4 changed files with 64 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@jmfederico/pi-web": patch
---
Add a Docker runtime host command bridge for explicitly running host administration commands from containerized PI WEB sessions.
+6
View File
@@ -1,6 +1,9 @@
# syntax=docker/dockerfile:1.7 # syntax=docker/dockerfile:1.7
ARG NODE_VERSION=22-bookworm-slim ARG NODE_VERSION=22-bookworm-slim
ARG DOCKER_CLI_VERSION=29-cli
FROM docker:${DOCKER_CLI_VERSION} AS docker-cli
FROM node:${NODE_VERSION} AS package FROM node:${NODE_VERSION} AS package
@@ -32,6 +35,7 @@ ENV NODE_ENV=production \
PI_WEB_DATA_DIR=/data/pi-web \ PI_WEB_DATA_DIR=/data/pi-web \
PI_WEB_SESSIOND_SOCKET=/data/pi-web/sessiond.sock \ PI_WEB_SESSIOND_SOCKET=/data/pi-web/sessiond.sock \
PI_CODING_AGENT_DIR=/data/pi-agent \ PI_CODING_AGENT_DIR=/data/pi-agent \
HOSTEXEC_IMAGE=alpine:3.22 \
SHELL=/bin/bash \ SHELL=/bin/bash \
TERM=xterm-256color TERM=xterm-256color
@@ -50,6 +54,8 @@ RUN apt-get update \
COPY --from=package /usr/local/lib/node_modules /usr/local/lib/node_modules COPY --from=package /usr/local/lib/node_modules /usr/local/lib/node_modules
COPY --from=package /usr/local/bin /usr/local/bin COPY --from=package /usr/local/bin /usr/local/bin
COPY --from=docker-cli /usr/local/bin/docker /usr/local/bin/docker
COPY --chmod=0755 bin/hostexec /usr/local/bin/hostexec
WORKDIR /workspace WORKDIR /workspace
USER node USER node
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat >&2 <<'EOF'
Usage: hostexec <command...>
Run a command on the Docker host by starting a temporary privileged helper
container through the mounted Docker socket and entering the host namespaces.
EOF
}
if [ "$#" -eq 0 ]; then
usage
exit 64
fi
if ! command -v docker >/dev/null 2>&1; then
echo "hostexec: docker CLI not found in this container" >&2
exit 127
fi
docker_host="${DOCKER_HOST:-unix:///var/run/docker.sock}"
if [[ "$docker_host" == unix://* ]]; then
socket_path="${docker_host#unix://}"
if [ ! -S "$socket_path" ]; then
echo "hostexec: Docker socket is not accessible as a Unix socket at $socket_path" >&2
exit 69
fi
fi
helper_image="${HOSTEXEC_IMAGE:-alpine:3.22}"
tty_args=(--interactive)
if [ -t 0 ] && [ -t 1 ]; then
tty_args+=(--tty)
fi
exec docker run \
--rm \
"${tty_args[@]}" \
--pull=missing \
--privileged \
--security-opt label=disable \
--pid=host \
--network=host \
--volume /:/host:rw \
"$helper_image" \
nsenter -t 1 -m -u -i -n -p -- "$@"
+5
View File
@@ -14,6 +14,7 @@ x-pi-web-environment: &pi-web-environment
PI_WEB_DATA_DIR: /data/pi-web PI_WEB_DATA_DIR: /data/pi-web
PI_WEB_SESSIOND_SOCKET: /data/pi-web/sessiond.sock PI_WEB_SESSIOND_SOCKET: /data/pi-web/sessiond.sock
PI_CODING_AGENT_DIR: /data/pi-agent PI_CODING_AGENT_DIR: /data/pi-agent
HOSTEXEC_IMAGE: ${HOSTEXEC_IMAGE:-alpine:3.22}
PI_WEB_MAX_UPLOAD_BYTES: ${PI_WEB_MAX_UPLOAD_BYTES:-67108864} PI_WEB_MAX_UPLOAD_BYTES: ${PI_WEB_MAX_UPLOAD_BYTES:-67108864}
x-pi-web-volumes: &pi-web-volumes x-pi-web-volumes: &pi-web-volumes
@@ -46,6 +47,8 @@ services:
user: "${PI_WEB_UID:-1000}:${PI_WEB_GID:-1000}" user: "${PI_WEB_UID:-1000}:${PI_WEB_GID:-1000}"
group_add: group_add:
- "${DOCKER_GID:-0}" - "${DOCKER_GID:-0}"
security_opt:
- label=disable
environment: *pi-web-environment environment: *pi-web-environment
volumes: *pi-web-volumes volumes: *pi-web-volumes
healthcheck: healthcheck:
@@ -66,6 +69,8 @@ services:
user: "${PI_WEB_UID:-1000}:${PI_WEB_GID:-1000}" user: "${PI_WEB_UID:-1000}:${PI_WEB_GID:-1000}"
group_add: group_add:
- "${DOCKER_GID:-0}" - "${DOCKER_GID:-0}"
security_opt:
- label=disable
environment: environment:
<<: *pi-web-environment <<: *pi-web-environment
PI_WEB_HOST: 0.0.0.0 PI_WEB_HOST: 0.0.0.0