Added docker deployment
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.github
|
||||||
|
.venv
|
||||||
|
venv
|
||||||
|
env
|
||||||
|
__pycache__
|
||||||
|
**/__pycache__
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info
|
||||||
|
.pytest_cache
|
||||||
|
.ruff_cache
|
||||||
|
.mypy_cache
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
data
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
|
config.toml
|
||||||
|
.env
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.swp
|
||||||
|
README.md
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
# syntax=docker/dockerfile:1.7
|
||||||
|
|
||||||
|
FROM python:3.12-slim AS builder
|
||||||
|
|
||||||
|
ENV PIP_NO_CACHE_DIR=1 \
|
||||||
|
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY pyproject.toml ./
|
||||||
|
COPY src ./src
|
||||||
|
|
||||||
|
RUN python -m pip install --upgrade pip build \
|
||||||
|
&& python -m build --wheel --outdir /wheels
|
||||||
|
|
||||||
|
|
||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
MESHBOT_CONFIG=/etc/meshbot/config.toml \
|
||||||
|
MESHBOT_STORAGE__SQLITE_PATH=/data/meshbot.db
|
||||||
|
|
||||||
|
RUN useradd --system --home /app --shell /usr/sbin/nologin meshbot \
|
||||||
|
&& mkdir -p /data /etc/meshbot \
|
||||||
|
&& chown meshbot:meshbot /data
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /wheels/*.whl /tmp/wheels/
|
||||||
|
RUN pip install --no-cache-dir /tmp/wheels/*.whl \
|
||||||
|
&& rm -rf /tmp/wheels
|
||||||
|
|
||||||
|
USER meshbot
|
||||||
|
|
||||||
|
VOLUME ["/data", "/etc/meshbot"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["meshbot"]
|
||||||
@@ -27,3 +27,30 @@ Any field can be overridden via env vars, e.g. `MESHBOT_LLM__API_KEY=sk-...`.
|
|||||||
- `src/meshbot/llm.py` — `AsyncOpenAI` wrapper.
|
- `src/meshbot/llm.py` — `AsyncOpenAI` wrapper.
|
||||||
- `src/meshbot/messages.py` — UTF-8-safe byte-length trimming.
|
- `src/meshbot/messages.py` — UTF-8-safe byte-length trimming.
|
||||||
- `src/meshbot/config.py` — TOML + env-var settings (pydantic-settings).
|
- `src/meshbot/config.py` — TOML + env-var settings (pydantic-settings).
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Build and push a multi-arch image (`linux/amd64` + `linux/arm64`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker login registry.example.com # once
|
||||||
|
export MESHBOT_IMAGE=registry.example.com/team/meshbot
|
||||||
|
./scripts/build-and-push.sh # tags: latest + <git sha>
|
||||||
|
EXTRA_TAGS="v0.1.0" ./scripts/build-and-push.sh # add explicit version
|
||||||
|
PUSH=0 PLATFORMS=linux/amd64 ./scripts/build-and-push.sh # local load only
|
||||||
|
```
|
||||||
|
|
||||||
|
Run via compose (set `MESHBOT_IMAGE`, `MESHBOT_LLM_BASE_URL`, `MESHBOT_LLM_MODEL`,
|
||||||
|
optionally `MESHBOT_DEVICE`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export MESHBOT_IMAGE=registry.example.com/team/meshbot:latest
|
||||||
|
export MESHBOT_LLM_BASE_URL=http://llama:8080/v1
|
||||||
|
export MESHBOT_LLM_MODEL=llama-3.1-8b-instruct
|
||||||
|
export MESHBOT_DEVICE=/dev/ttyUSB0
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
The container expects `config.toml` mounted at `/etc/meshbot/config.toml` and
|
||||||
|
persists SQLite to a named volume at `/data`. Any field can still be overridden
|
||||||
|
via `MESHBOT_<SECTION>__<KEY>` env vars.
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
services:
|
||||||
|
meshbot:
|
||||||
|
image: ${MESHBOT_IMAGE:?set MESHBOT_IMAGE to your image reference}
|
||||||
|
container_name: meshbot
|
||||||
|
restart: unless-stopped
|
||||||
|
# MeshCore companion is on a USB serial port. Map the host device through to
|
||||||
|
# the container. Override MESHBOT_DEVICE for ttyACM0 etc.
|
||||||
|
devices:
|
||||||
|
- "${MESHBOT_DEVICE:-/dev/ttyUSB0}:${MESHBOT_DEVICE:-/dev/ttyUSB0}"
|
||||||
|
# Some serial chipsets need access to the dialout group on the host.
|
||||||
|
group_add:
|
||||||
|
- dialout
|
||||||
|
environment:
|
||||||
|
MESHBOT_MESHCORE__SERIAL_PORT: ${MESHBOT_DEVICE:-/dev/ttyUSB0}
|
||||||
|
MESHBOT_LLM__BASE_URL: ${MESHBOT_LLM_BASE_URL:?set MESHBOT_LLM_BASE_URL}
|
||||||
|
MESHBOT_LLM__API_KEY: ${MESHBOT_LLM_API_KEY:-not-needed}
|
||||||
|
MESHBOT_LLM__MODEL: ${MESHBOT_LLM_MODEL:?set MESHBOT_LLM_MODEL}
|
||||||
|
volumes:
|
||||||
|
- meshbot-data:/data
|
||||||
|
# Mount your config.toml at /etc/meshbot/config.toml. Anything not set in the
|
||||||
|
# TOML will fall back to defaults; env vars above always win.
|
||||||
|
- ./config.toml:/etc/meshbot/config.toml:ro
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
meshbot-data:
|
||||||
Executable
+72
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build a multi-arch (linux/amd64, linux/arm64) image and push it to a registry.
|
||||||
|
#
|
||||||
|
# Required:
|
||||||
|
# MESHBOT_IMAGE Full image reference, e.g. registry.example.com/team/meshbot
|
||||||
|
#
|
||||||
|
# Optional:
|
||||||
|
# PLATFORMS Comma-separated arch list (default: linux/amd64,linux/arm64)
|
||||||
|
# EXTRA_TAGS Space-separated additional tags to push (e.g. "stable v0.1.0")
|
||||||
|
# PUSH "1" (default) to push, "0" to build and load locally only
|
||||||
|
# (note: --load only works with a single platform)
|
||||||
|
# BUILDER buildx builder name (default: meshbot-builder, auto-created)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ -z "${MESHBOT_IMAGE:-}" ]]; then
|
||||||
|
echo "error: MESHBOT_IMAGE is required (e.g. registry.example.com/team/meshbot)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
|
||||||
|
PUSH="${PUSH:-1}"
|
||||||
|
BUILDER="${BUILDER:-meshbot-builder}"
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# Compute git-derived tags. Fall back to "dev" if not in a git tree.
|
||||||
|
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||||
|
GIT_SHA="$(git rev-parse --short=12 HEAD)"
|
||||||
|
if [[ -n "$(git status --porcelain)" ]]; then
|
||||||
|
GIT_SHA="${GIT_SHA}-dirty"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
GIT_SHA="dev"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAGS=(--tag "${MESHBOT_IMAGE}:latest" --tag "${MESHBOT_IMAGE}:${GIT_SHA}")
|
||||||
|
for t in ${EXTRA_TAGS:-}; do
|
||||||
|
TAGS+=(--tag "${MESHBOT_IMAGE}:${t}")
|
||||||
|
done
|
||||||
|
|
||||||
|
# Make sure a buildx builder exists. Reuse if it's already there.
|
||||||
|
if ! docker buildx inspect "${BUILDER}" >/dev/null 2>&1; then
|
||||||
|
echo ">>> creating buildx builder '${BUILDER}'"
|
||||||
|
docker buildx create --name "${BUILDER}" --driver docker-container --use >/dev/null
|
||||||
|
else
|
||||||
|
docker buildx use "${BUILDER}" >/dev/null
|
||||||
|
fi
|
||||||
|
docker buildx inspect --bootstrap >/dev/null
|
||||||
|
|
||||||
|
OUTPUT_FLAG=()
|
||||||
|
if [[ "${PUSH}" == "1" ]]; then
|
||||||
|
OUTPUT_FLAG=(--push)
|
||||||
|
echo ">>> building & pushing ${MESHBOT_IMAGE} (${PLATFORMS}) tags: latest, ${GIT_SHA}${EXTRA_TAGS:+, $EXTRA_TAGS}"
|
||||||
|
else
|
||||||
|
# --load only works with a single platform; warn if user requested multi.
|
||||||
|
if [[ "${PLATFORMS}" == *,* ]]; then
|
||||||
|
echo "error: PUSH=0 (local --load) only works with a single platform; got '${PLATFORMS}'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
OUTPUT_FLAG=(--load)
|
||||||
|
echo ">>> building ${MESHBOT_IMAGE} for ${PLATFORMS} (local load, no push)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker buildx build \
|
||||||
|
--platform "${PLATFORMS}" \
|
||||||
|
"${TAGS[@]}" \
|
||||||
|
"${OUTPUT_FLAG[@]}" \
|
||||||
|
--file Dockerfile \
|
||||||
|
.
|
||||||
|
|
||||||
|
echo ">>> done"
|
||||||
Reference in New Issue
Block a user