# sanad_api_x2 — AGIBOT X2 fleet agent: TELEMETRY + MAP sync. # # BUILD ON THE X2 COMPUTE (native arm64). There is no middleware to compile into # the image: the state source is chosen at RUNTIME # (X2_SOURCE=http|ros2|aimrt|none), so the image only needs whatever the chosen # backend requires. That is what BASE_IMAGE selects: # # http / none backend (default) — tiny, no ROS at all: # docker build -t sanad-api-x2:latest . # # ros2 backend — rclpy comes from the ROS base; match the ROBOT's distro: # docker build --build-arg BASE_IMAGE=ros:humble-ros-base -t sanad-api-x2:latest . # (or ros:foxy-ros-base, ros:jazzy-ros-base, … — must match the robot, or # ROS 2 discovery silently fails to see the robot's topics) # # Run with --network host so the robot's middleware traffic is visible (ROS 2 # discovery does not cross a NAT bridge) and the agent can reach vendor APIs on # 127.0.0.1 (the installer does this). ARG BASE_IMAGE=python:3.10-slim-bookworm FROM ${BASE_IMAGE} # iproute2 for iface checks; ca-certificates for outbound HTTPS to the fleet # server. Kept minimal — the ROS bases already carry python3 + rclpy. RUN apt-get update && apt-get install -y --no-install-recommends \ iproute2 ca-certificates python3 python3-pip \ && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt . # ROS bases ship a Debian-managed python (PEP 668), so retry with # --break-system-packages rather than failing the build. RUN python3 -m pip install --no-cache-dir -r requirements.txt \ || python3 -m pip install --no-cache-dir --break-system-packages -r requirements.txt COPY sanad_api_x2.py entrypoint.sh ./ RUN chmod +x entrypoint.sh ENV PYTHONUNBUFFERED=1 \ X2_SOURCE=auto \ MAC_INTERFACE=eth0 # entrypoint.sh sources a ROS overlay when the base has one (no-op otherwise), # then execs the agent — so ONE image definition serves every backend. ENTRYPOINT ["/app/entrypoint.sh"]