From 24de8e73fb1072e323b23221344ad05617e0e10b Mon Sep 17 00:00:00 2001 From: Joel Krauska Date: Tue, 4 Nov 2025 19:51:19 -0800 Subject: [PATCH] Container using slim/uv --- .dockerignore | 3 ++ Containerfile | 52 ++++++++++++++++++++++++++++++++ container/build-container.sh | 57 ++++++++++++++++++++++++++++++++++++ container/config.patch | 37 +++++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 .dockerignore create mode 100644 Containerfile create mode 100755 container/build-container.sh create mode 100644 container/config.patch diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..41540f3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +# This keeps Docker from including hostOS virtual environment folders +env/ +.venv/ diff --git a/Containerfile b/Containerfile new file mode 100644 index 0000000..36f1581 --- /dev/null +++ b/Containerfile @@ -0,0 +1,52 @@ +# Build Image +# Uses python:3.13-slim because no native dependencies are needed for meshview itself +# (everything is available as a wheel) + +FROM docker.io/python:3.13-slim AS meshview-build +RUN apt-get update && \ + apt-get install -y --no-install-recommends curl patch && \ + rm -rf /var/lib/apt/lists/* + +# Add a non-root user/group +ARG APP_USER=app +RUN useradd -m -u 10001 -s /bin/bash ${APP_USER} + +# Install uv and put it on PATH system-wide +RUN curl -LsSf https://astral.sh/uv/install.sh | sh \ + && install -m 0755 /root/.local/bin/uv /usr/local/bin/uv + +WORKDIR /app + +# Copy deps first for caching +COPY --chown=${APP_USER}:${APP_USER} pyproject.toml uv.lock* requirements*.txt ./ + +# Optional: wheels-only to avoid slow source builds +ENV UV_NO_BUILD=1 +RUN uv venv /opt/venv +# RUN uv sync --frozen +ENV VIRTUAL_ENV=/opt/venv +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +RUN uv pip install --no-cache-dir --upgrade pip \ + && if [ -f requirements.txt ]; then uv pip install --only-binary=:all: -r requirements.txt; fi + +# Copy app code +COPY --chown=${APP_USER}:${APP_USER} . . + +# Created working directories with correct ownership/permissions +RUN mkdir -p /etc/meshview /var/lib/meshview /var/log/meshview \ + && chown -R ${APP_USER}:${APP_USER} /etc/meshview /var/lib/meshview /var/log/meshview + +RUN patch sample.config.ini < container/config.patch +RUN cp sample.config.ini /etc/meshview/config.ini +RUN chown ${APP_USER}:${APP_USER} /etc/meshview/config.ini + +# Drop privileges +USER ${APP_USER} + +ENTRYPOINT [ "uv", "run", "--active", "mvrun.py"] +CMD ["--pid_dir", "/tmp", "--py_exec", "/opt/venv/bin/python", "--config", "/etc/meshview/config.ini" ] + +EXPOSE 8081 +VOLUME [ "/etc/meshview", "/var/lib/meshview", "/var/log/meshview" ] + diff --git a/container/build-container.sh b/container/build-container.sh new file mode 100755 index 0000000..120ff5f --- /dev/null +++ b/container/build-container.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# +# build-container.sh +# +# Script to build MeshView container images + +set -e + +# Default values +IMAGE_NAME="meshview" +TAG="latest" +CONTAINERFILE="Containerfile" + +# Parse arguments +while [ $# -gt 0 ]; do + case "$1" in + --tag|-t) + TAG="$2" + shift 2 + ;; + --name|-n) + IMAGE_NAME="$2" + shift 2 + ;; + --file|-f) + CONTAINERFILE="$2" + shift 2 + ;; + --help|-h) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " -t, --tag TAG Tag for the image (default: latest)" + echo " -n, --name NAME Image name (default: meshview)" + echo " -f, --file FILE Containerfile path (default: Containerfile)" + echo " -h, --help Show this help" + exit 0 + ;; + *) + echo "Unknown option: $1" + echo "Use --help for usage information" + exit 1 + ;; + esac +done + +echo "Building MeshView container image..." +echo " Image: ${IMAGE_NAME}:${TAG}" +echo " Containerfile: ${CONTAINERFILE}" +echo "" + +# Build the container +docker build -f "${CONTAINERFILE}" -t "${IMAGE_NAME}:${TAG}" . + +echo "" +echo "Build complete!" +echo "Run with: docker run --rm -p 8081:8081 ${IMAGE_NAME}:${TAG}" diff --git a/container/config.patch b/container/config.patch new file mode 100644 index 0000000..93753bb --- /dev/null +++ b/container/config.patch @@ -0,0 +1,37 @@ +diff --git a/sample.config.ini b/sample.config.ini +index 0e64980..494685c 100644 +--- a/sample.config.ini ++++ b/sample.config.ini +@@ -3,7 +3,7 @@ + # ------------------------- + [server] + # The address to bind the server to. Use * to listen on all interfaces. +-bind = * ++bind = 0.0.0.0 + + # Port to run the web server on. + port = 8081 +@@ -64,7 +64,7 @@ net_tag = #BayMeshNet + # ------------------------- + [mqtt] + # MQTT server hostname or IP. +-server = mqtt.bayme.sh ++server = mqtt.meshtastic.org + + # Topics to subscribe to (as JSON-like list, but still a string). + topics = ["msh/US/bayarea/#", "msh/US/CA/mrymesh/#", "msh/US/CA/sacvalley"] +@@ -82,7 +82,7 @@ password = large4cats + # ------------------------- + [database] + # SQLAlchemy connection string. This one uses SQLite with asyncio support. +-connection_string = sqlite+aiosqlite:///packets.db ++connection_string = sqlite+aiosqlite:////var/lib/meshview/packets.db + + + # ------------------------- +@@ -110,4 +110,4 @@ vacuum = False + # Set to True to enable, False to disable (default: False) + access_log = False + # Database cleanup logfile +-db_cleanup_logfile = dbcleanup.log ++db_cleanup_logfile = /var/log/meshview/dbcleanup.log