feat: Update README and .gitignore for Docker deployment

- Added Docker deployment instructions to the README, including steps for creating data directories, updating configuration paths, and starting the application with Docker Compose.
- Updated .gitignore to include a new data directory structure, ensuring user-specific configurations, databases, and logs are ignored while maintaining the directory structure.
This commit is contained in:
agessaman
2026-01-17 08:34:38 -08:00
parent db0db96f7e
commit 61445b4811
9 changed files with 708 additions and 0 deletions

76
.dockerignore Normal file
View File

@@ -0,0 +1,76 @@
# Git
.git
.gitignore
.gitattributes
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
dist/
build/
*.egg
# Virtual environments
venv/
env/
ENV/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Project specific
*.db
*.db-shm
*.db-wal
*.log
logs/
backups/
*.ini
config.ini
config.ini.example
config.ini.minimal-example
config.min.ini
# Documentation
docs/
*.md
!README.md
# Test files
test_scripts/
*.test.py
*_test.py
# Development
dev/
flake.lock
flake.nix
nix/
# Service files
*.service
*.plist
*.sh
!install-service.sh
!uninstall-service.sh
# Website
website/
# MQTT bridge
mctomqtt.py
# Database backups
backup_database.py

65
.github/workflows/docker-build.yml vendored Normal file
View File

@@ -0,0 +1,65 @@
name: Build and Push Docker Image
on:
push:
branches:
- main
- master
tags:
- 'v*'
pull_request:
branches:
- main
- master
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64

5
.gitignore vendored
View File

@@ -142,3 +142,8 @@ tests/
test_scripts/
dev/
website/
# Docker data directory (user-specific config, databases, logs)
# Ignore contents but keep directory structure
data/*
!data/.gitkeep

368
DOCKER.md Normal file
View File

@@ -0,0 +1,368 @@
# Docker Deployment Guide
This guide explains how to deploy meshcore-bot using Docker and Docker Compose.
## Prerequisites
- Docker Engine 20.10+ or Docker Desktop
- Docker Compose 2.0+ (included with Docker Desktop)
## Quick Start
1. **Clone the repository** (if you haven't already):
```bash
git clone <repository-url>
cd meshcore-bot
```
2. **Run the setup script** (recommended):
```bash
./docker-setup.sh
```
This will create the necessary directories and copy the example config file.
**Or manually:**
```bash
mkdir -p data/{config,databases,logs,backups}
cp config.ini.example data/config/config.ini
```
3. **Edit configuration file**:
```bash
# Edit data/config/config.ini with your settings
nano data/config/config.ini # or your preferred editor
```
4. **Update database paths in config.ini**:
Make sure your `config.ini` uses paths that will be mapped to `/data/databases`:
```ini
[Bot]
db_path = /data/databases/meshcore_bot.db
[Web_Viewer]
db_path = /data/databases/bot_data.db
[Logging]
log_file = /data/logs/meshcore_bot.log
```
5. **Start the container**:
```bash
docker-compose up -d
```
6. **View logs**:
```bash
docker-compose logs -f
```
## Configuration
### Volume Mappings
The `docker-compose.yml` file maps the following directories:
- `./data/config` → `/data/config` (read-only) - Configuration files
- `./data/databases` → `/data/databases` - SQLite database files
- `./data/logs` → `/data/logs` - Log files
- `./data/backups` → `/data/backups` - Database backups
### Serial Port Access
**⚠️ Important: Docker Desktop on macOS does NOT support serial device passthrough.**
If you're using a serial connection, you have several options:
**Option 1: Use TCP Connection (Recommended for macOS)**
If your MeshCore device supports TCP/IP (via gateway or bridge), configure it in `config.ini`:
```ini
[Connection]
connection_type = tcp
hostname = 192.168.1.60 # Your device's IP or hostname
tcp_port = 5000
```
Then comment out or remove the `devices` section in `docker-compose.yml`.
**Option 2: Serial-to-TCP Bridge (macOS workaround)**
Use a tool like `socat` to bridge the serial port to TCP on the host:
```bash
# On macOS host, create TCP bridge
socat TCP-LISTEN:5000,reuseaddr,fork FILE:/dev/cu.usbmodem1101,raw,nonblock,waitlock=/var/run/socat.pid
```
Then configure the bot to use TCP connection to `localhost:5000`.
**Option 3: Device Mapping (Linux only)**
On Linux, you can map the serial device directly:
```yaml
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
```
**Option 4: Host Network Mode (Linux only, for BLE)**
For BLE connections on Linux, you may need host network access:
```yaml
network_mode: host
```
**Note**: Host network mode gives the container full access to the host network, which has security implications.
### Web Viewer Port
If you enable the web viewer, uncomment and adjust the `ports` section:
```yaml
ports:
- "8080:8080"
```
Make sure your `config.ini` has:
```ini
[Web_Viewer]
enabled = true
host = 0.0.0.0 # Required for Docker port mapping
port = 8080
```
## Building the Image
### Using Docker Compose
The `docker-compose.yml` file will automatically build the image if it doesn't exist:
```bash
docker-compose build
```
### Using Docker directly
```bash
docker build -t meshcore-bot:latest .
```
## Running the Container
### Start in background
```bash
docker-compose up -d
```
### Start in foreground (see logs)
```bash
docker-compose up
```
### Stop the container
```bash
docker-compose down
```
### Restart the container
```bash
docker-compose restart
```
## Managing the Container
### View logs
```bash
# Follow logs
docker-compose logs -f
# Last 100 lines
docker-compose logs --tail=100
# Logs for specific service
docker-compose logs meshcore-bot
```
### Execute commands in container
```bash
docker-compose exec meshcore-bot bash
```
### Update the container
```bash
# Pull latest changes
git pull
# Rebuild and restart
docker-compose up -d --build
```
## Using Pre-built Images
If you're using GitHub Container Registry images:
1. **Update docker-compose.yml** to use the image:
```yaml
services:
meshcore-bot:
image: ghcr.io/your-username/meshcore-bot:latest
# Remove or comment out the 'build' section
```
2. **Pull and start**:
```bash
docker-compose pull
docker-compose up -d
```
## Troubleshooting
### Permission Issues
If you encounter permission issues with database or log files:
1. **Check file ownership**:
```bash
ls -la data/databases/
ls -la data/logs/
```
2. **Fix permissions** (if needed):
```bash
sudo chown -R 1000:1000 data/
```
The container runs as user ID 1000 (meshcore user).
### Serial Port Not Found
1. **Check device exists**:
```bash
ls -l /dev/ttyUSB0 # or your device
```
2. **Add user to dialout group** (on host):
```bash
sudo usermod -a -G dialout $USER
# Log out and back in
```
3. **Use host network mode** if device mapping doesn't work:
```yaml
network_mode: host
```
### Database Locked Errors
If you see database locked errors:
1. **Stop the container**:
```bash
docker-compose down
```
2. **Check for leftover database files**:
```bash
ls -la data/databases/*.db-*
```
3. **Remove lock files** (if safe):
```bash
rm data/databases/*.db-shm data/databases/*.db-wal
```
4. **Restart**:
```bash
docker-compose up -d
```
### Container Won't Start
1. **Check logs**:
```bash
docker-compose logs
```
2. **Verify config file exists**:
```bash
ls -la data/config/config.ini
```
3. **Test config file syntax**:
```bash
docker-compose run --rm meshcore-bot python3 -c "import configparser; c = configparser.ConfigParser(); c.read('/data/config/config.ini'); print('Config OK')"
```
## Production Deployment
For production deployments:
1. **Use specific image tags** instead of `latest`:
```yaml
image: ghcr.io/your-username/meshcore-bot:v1.0.0
```
2. **Set resource limits** in `docker-compose.yml`:
```yaml
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
```
3. **Use secrets management** for sensitive configuration:
- Use Docker secrets (Docker Swarm)
- Use environment variables for API keys
- Mount secret files as read-only volumes
4. **Enable log rotation** (already configured in docker-compose.yml):
```yaml
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
```
5. **Set up health checks** (already included in Dockerfile):
The container includes a basic health check. Monitor with:
```bash
docker-compose ps
```
## Backup and Restore
### Backup
```bash
# Backup databases
docker-compose exec meshcore-bot tar czf /data/backups/backup-$(date +%Y%m%d).tar.gz /data/databases
# Or from host
tar czf backups/backup-$(date +%Y%m%d).tar.gz data/databases/
```
### Restore
```bash
# Stop container
docker-compose down
# Restore databases
tar xzf backups/backup-YYYYMMDD.tar.gz -C data/
# Start container
docker-compose up -d
```
## Security Considerations
1. **Non-root user**: The container runs as a non-root user (UID 1000)
2. **Read-only config**: Config directory is mounted read-only to prevent accidental modifications
3. **Network isolation**: By default, containers are isolated. Only expose ports you need
4. **Secrets**: Never commit API keys or sensitive data to version control. Use environment variables or secrets management
5. **Web viewer**: If enabled, ensure it's only accessible on trusted networks or use a reverse proxy with authentication
## Additional Resources
- [Docker Documentation](https://docs.docker.com/)
- [Docker Compose Documentation](https://docs.docker.com/compose/)
- [Main README](README.md) for general bot configuration

57
Dockerfile Normal file
View File

@@ -0,0 +1,57 @@
# Multi-stage build for meshcore-bot
FROM python:3.11-slim as builder
# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /build
# Copy dependency files
COPY requirements.txt pyproject.toml ./
# Install Python dependencies
RUN pip install --no-cache-dir --user -r requirements.txt
# Final stage
FROM python:3.11-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
# For serial port access
udev \
# For BLE support (optional, but commonly needed)
libbluetooth3 \
# Cleanup
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN useradd -m -u 1000 meshcore && \
mkdir -p /app /data/config /data/databases /data/logs /data/backups && \
chown -R meshcore:meshcore /app /data
# Copy Python dependencies from builder
COPY --from=builder /root/.local /home/meshcore/.local
# Set working directory
WORKDIR /app
# Copy application files
COPY --chown=meshcore:meshcore . /app/
# Set PATH to include user's local bin
ENV PATH=/home/meshcore/.local/bin:$PATH \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# Switch to non-root user
USER meshcore
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD python3 -c "import sys; sys.exit(0)" || exit 1
# Default command
CMD ["python3", "meshcore_bot.py", "--config", "/data/config/config.ini"]

View File

@@ -84,6 +84,37 @@ sudo systemctl status meshcore-bot
See [SERVICE-INSTALLATION.md](SERVICE-INSTALLATION.md) for detailed service installation instructions.
### Docker Deployment
For containerized deployment using Docker:
1. **Create data directories and configuration**:
```bash
mkdir -p data/{config,databases,logs,backups}
cp config.ini.example data/config/config.ini
# Edit data/config/config.ini with your settings
```
2. **Update paths in config.ini** to use `/data/` directories:
```ini
[Bot]
db_path = /data/databases/meshcore_bot.db
[Logging]
log_file = /data/logs/meshcore_bot.log
```
3. **Start with Docker Compose**:
```bash
docker-compose up -d
```
4. **View logs**:
```bash
docker-compose logs -f
```
See [DOCKER.md](DOCKER.md) for detailed Docker deployment instructions, including serial port access, web viewer configuration, and troubleshooting.
## NixOS
Use the Nix flake via flake.nix
```nix

3
data/.gitkeep Executable file
View File

@@ -0,0 +1,3 @@
# This file ensures the data directory structure is tracked in git
# User-specific files (config.ini, databases, logs) should not be committed
# See DOCKER.md for setup instructions

52
docker-compose.yml Normal file
View File

@@ -0,0 +1,52 @@
version: '3.8'
services:
meshcore-bot:
build:
context: .
dockerfile: Dockerfile
image: meshcore-bot:latest
container_name: meshcore-bot
restart: unless-stopped
# Device access for serial ports
# NOTE: Docker Desktop on macOS does NOT support device passthrough
# Options for macOS:
# 1. Use TCP connection (if device supports it) - configure in config.ini
# 2. Use a serial-to-TCP bridge (e.g., socat) on the host
# 3. Run the bot natively on macOS instead of Docker
# For Linux: Uncomment and adjust device path below
# devices:
# - /dev/ttyUSB0:/dev/ttyUSB0
# Network mode for host access (needed for BLE and some serial setups)
# Uncomment if you need host network access
# network_mode: host
# Environment variables (optional, can override config.ini settings)
environment:
- TZ=America/Los_Angeles # Set your timezone
# - PYTHONUNBUFFERED=1 # Already set in Dockerfile
# Volume mappings for persistent data
volumes:
# Configuration file
- ./data/config:/data/config:ro
# Databases (main bot database and web viewer database)
- ./data/databases:/data/databases
# Logs
- ./data/logs:/data/logs
# Backups (optional)
- ./data/backups:/data/backups
# Port mappings (if web viewer is enabled)
# Uncomment and adjust if using web viewer
ports:
- "8082:8080"
# Logging configuration
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

51
docker-setup.sh Executable file
View File

@@ -0,0 +1,51 @@
#!/bin/bash
# Setup script for Docker deployment
# Creates necessary directories and copies example config
set -e
echo "Setting up meshcore-bot Docker environment..."
# Create data directories
echo "Creating data directories..."
mkdir -p data/{config,databases,logs,backups}
# Copy example config if config doesn't exist
if [ ! -f "data/config/config.ini" ]; then
if [ -f "config.ini.example" ]; then
echo "Copying config.ini.example to data/config/config.ini..."
cp config.ini.example data/config/config.ini
echo ""
echo "⚠️ IMPORTANT: Please edit data/config/config.ini with your settings!"
echo " - Update database paths to use /data/databases/"
echo " - Update log file path to use /data/logs/"
echo " - Configure your connection settings"
else
echo "⚠️ Warning: config.ini.example not found. Please create data/config/config.ini manually."
fi
else
echo "✓ Config file already exists at data/config/config.ini"
fi
# Set permissions (container runs as UID 1000)
echo "Setting permissions..."
chmod -R 755 data/
chown -R 1000:1000 data/ 2>/dev/null || echo "Note: Could not set ownership (may need sudo)"
echo ""
echo "✓ Setup complete!"
echo ""
echo "Next steps:"
echo "1. Edit data/config/config.ini with your settings"
echo "2. Update database paths in config.ini:"
echo " [Bot]"
echo " db_path = /data/databases/meshcore_bot.db"
echo ""
echo " [Logging]"
echo " log_file = /data/logs/meshcore_bot.log"
echo ""
echo "3. Start the container:"
echo " docker-compose up -d"
echo ""
echo "4. View logs:"
echo " docker-compose logs -f"