diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..70ea998 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,76 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +venv/ +.venv/ +ENV/ +env/ + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Testing +.pytest_cache/ +.coverage +htmlcov/ +.tox/ +tests/ + +# Logs +logs/ +*.log + +# Environment files +.env +.env.local +.env.*.local + +# Data files +data/ +*.json + +# Git +.git/ +.gitignore + +# Docker +Dockerfile +docker-compose* +.dockerignore + +# Documentation +.claude/ +*.md +docs/ + +# CI/CD +.github/ +.gitlab-ci.yml + +# OS +.DS_Store +Thumbs.db diff --git a/BUILD_AND_PUSH.md b/BUILD_AND_PUSH.md new file mode 100644 index 0000000..1454828 --- /dev/null +++ b/BUILD_AND_PUSH.md @@ -0,0 +1,371 @@ +# Building and Pushing to Docker Hub + +This guide covers building the Docker image and pushing it to Docker Hub for production deployment. + +## Prerequisites + +- Docker installed and running +- Docker Hub account (username: `manticorum67`) +- Write access to `manticorum67/major-domo-discordapp` repository + +## Docker Hub Repository + +**Repository**: `manticorum67/major-domo-discordapp` +**URL**: https://hub.docker.com/r/manticorum67/major-domo-discordapp + +## Login to Docker Hub + +```bash +# Login to Docker Hub +docker login + +# Enter your username: manticorum67 +# Enter your password/token: [your-password-or-token] +``` + +## Build and Push Workflow + +### 1. Tag the Release + +```bash +# Determine version number (use semantic versioning) +VERSION="2.0.0" + +# Create git tag (optional but recommended) +git tag -a "v${VERSION}" -m "Release v${VERSION}" +git push origin "v${VERSION}" +``` + +### 2. Build the Image + +```bash +# Build for production +docker build -t manticorum67/major-domo-discordapp:latest . + +# Build with version tag +docker build -t manticorum67/major-domo-discordapp:${VERSION} . + +# Or build both at once +docker build \ + -t manticorum67/major-domo-discordapp:latest \ + -t manticorum67/major-domo-discordapp:${VERSION} \ + . +``` + +### 3. Test the Image Locally + +```bash +# Test with docker run +docker run --rm \ + --env-file .env \ + -v $(pwd)/data:/data:ro \ + -v $(pwd)/logs:/logs:rw \ + manticorum67/major-domo-discordapp:latest + +# Or test with docker-compose (development) +docker-compose -f docker-compose.dev.yml up +``` + +### 4. Push to Docker Hub + +```bash +# Push latest tag +docker push manticorum67/major-domo-discordapp:latest + +# Push version tag +docker push manticorum67/major-domo-discordapp:${VERSION} + +# Or push all tags +docker push manticorum67/major-domo-discordapp --all-tags +``` + +## Complete Build and Push Script + +```bash +#!/bin/bash +# build-and-push.sh + +set -e # Exit on error + +# Configuration +VERSION="${1:-latest}" # Use argument or default to 'latest' +DOCKER_REPO="manticorum67/major-domo-discordapp" + +echo "🔨 Building Docker image..." +echo "Version: ${VERSION}" +echo "Repository: ${DOCKER_REPO}" +echo "" + +# Build image with both tags +docker build \ + -t ${DOCKER_REPO}:latest \ + -t ${DOCKER_REPO}:${VERSION} \ + . + +echo "" +echo "✅ Build complete!" +echo "" +echo "📤 Pushing to Docker Hub..." + +# Push both tags +docker push ${DOCKER_REPO}:latest +docker push ${DOCKER_REPO}:${VERSION} + +echo "" +echo "✅ Push complete!" +echo "" +echo "🎉 Image available at:" +echo " docker pull ${DOCKER_REPO}:latest" +echo " docker pull ${DOCKER_REPO}:${VERSION}" +``` + +### Using the Build Script + +```bash +# Make script executable +chmod +x build-and-push.sh + +# Build and push with version +./build-and-push.sh 2.0.0 + +# Build and push as latest only +./build-and-push.sh +``` + +## Multi-Platform Builds (Optional) + +To build for multiple architectures (amd64, arm64): + +```bash +# Create a builder instance +docker buildx create --name multiarch --use + +# Build and push for multiple platforms +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + -t manticorum67/major-domo-discordapp:latest \ + -t manticorum67/major-domo-discordapp:${VERSION} \ + --push \ + . +``` + +## Versioning Strategy + +### Semantic Versioning + +Use semantic versioning (MAJOR.MINOR.PATCH): + +- **MAJOR**: Breaking changes +- **MINOR**: New features (backwards compatible) +- **PATCH**: Bug fixes + +Examples: +- `2.0.0` - Major release with scorecard submission +- `2.1.0` - Added new command +- `2.1.1` - Fixed bug in existing command + +### Tagging Strategy + +Always maintain these tags: + +1. **`:latest`** - Most recent stable release +2. **`:VERSION`** - Specific version (e.g., `2.0.0`) +3. **`:MAJOR.MINOR`** - Minor version (e.g., `2.0`) - optional +4. **`:MAJOR`** - Major version (e.g., `2`) - optional + +### Example Tagging + +```bash +VERSION="2.0.0" + +# Tag with all versions +docker build \ + -t manticorum67/major-domo-discordapp:latest \ + -t manticorum67/major-domo-discordapp:2.0.0 \ + -t manticorum67/major-domo-discordapp:2.0 \ + -t manticorum67/major-domo-discordapp:2 \ + . + +# Push all tags +docker push manticorum67/major-domo-discordapp --all-tags +``` + +## GitHub Actions (Optional) + +Automate builds with GitHub Actions: + +```yaml +# .github/workflows/docker-build.yml +name: Build and Push Docker Image + +on: + push: + tags: + - 'v*.*.*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract version + id: version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: ./discord-app-v2 + push: true + tags: | + manticorum67/major-domo-discordapp:latest + manticorum67/major-domo-discordapp:${{ steps.version.outputs.VERSION }} +``` + +## Production Deployment + +After pushing to Docker Hub, deploy on production: + +```bash +# On production server +cd /path/to/discord-app-v2 + +# Pull latest image +docker-compose pull + +# Restart with new image +docker-compose up -d + +# Verify it's running +docker-compose logs -f discord-bot +``` + +## Rollback to Previous Version + +If a release has issues: + +```bash +# Stop current version +docker-compose down + +# Edit docker-compose.yml to use specific version +# Change: image: manticorum67/major-domo-discordapp:latest +# To: image: manticorum67/major-domo-discordapp:2.0.0 + +# Pull and start old version +docker-compose pull +docker-compose up -d +``` + +Or use a specific version directly: + +```bash +docker-compose down + +docker pull manticorum67/major-domo-discordapp:2.0.0 + +docker run -d \ + --name major-domo-discord-bot-v2 \ + --env-file .env \ + -v $(pwd)/data:/data:ro \ + -v $(pwd)/logs:/logs:rw \ + manticorum67/major-domo-discordapp:2.0.0 +``` + +## Image Size Optimization + +The multi-stage build already optimizes size, but you can verify: + +```bash +# Check image size +docker images manticorum67/major-domo-discordapp + +# Expected size: ~150-200MB + +# Inspect layers +docker history manticorum67/major-domo-discordapp:latest +``` + +## Troubleshooting + +### Build Fails + +```bash +# Build with verbose output +docker build --progress=plain -t manticorum67/major-domo-discordapp:latest . + +# Check for errors in requirements.txt +docker build --no-cache -t manticorum67/major-domo-discordapp:latest . +``` + +### Push Fails + +```bash +# Check if logged in +docker info | grep Username + +# Re-login +docker logout +docker login + +# Check repository permissions +docker push manticorum67/major-domo-discordapp:latest +``` + +### Image Won't Run + +```bash +# Test image interactively +docker run -it --rm \ + --entrypoint /bin/bash \ + manticorum67/major-domo-discordapp:latest + +# Inside container, check Python +python --version +pip list +ls -la /app +``` + +## Security Best Practices + +1. **Use Docker Hub Access Tokens** instead of password +2. **Enable 2FA** on Docker Hub account +3. **Scan images** for vulnerabilities: + ```bash + docker scan manticorum67/major-domo-discordapp:latest + ``` +4. **Sign images** (optional): + ```bash + docker trust sign manticorum67/major-domo-discordapp:latest + ``` + +## Cleanup + +Remove old local images: + +```bash +# Remove dangling images +docker image prune + +# Remove all unused images +docker image prune -a + +# Remove specific version +docker rmi manticorum67/major-domo-discordapp:1.0.0 +``` + +## Additional Resources + +- **Docker Hub**: https://hub.docker.com/r/manticorum67/major-domo-discordapp +- **Docker Documentation**: https://docs.docker.com/ +- **Semantic Versioning**: https://semver.org/ diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..505b99d --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,568 @@ +# Docker Deployment Guide + +This guide covers deploying the Discord Bot v2.0 using Docker and Docker Compose. + +## Prerequisites + +- Docker 20.10+ installed +- Docker Compose 2.0+ installed +- Google Sheets service account credentials JSON file +- Access to the database API (running on a separate host) + +## Deployment Modes + +### Production (Recommended) +Uses `docker-compose.yml` - pulls pre-built image from Docker Hub + +### Development +Uses `docker-compose.dev.yml` - builds image locally from source + +--- + +## Quick Start (Production) + +Deploy using pre-built image from Docker Hub: + +### 1. Prepare Configuration + +```bash +# Copy the example environment file +cp .env.example .env + +# Edit .env with your actual values +nano .env +``` + +**Required environment variables:** +- `BOT_TOKEN` - Your Discord bot token +- `API_TOKEN` - Database API authentication token +- `DB_URL` - Database API endpoint URL +- `GUILD_ID` - Your Discord server ID + +### 2. Prepare Data Directory + +```bash +# Create data directory for Google Sheets credentials +mkdir -p data + +# Copy your Google Sheets credentials file +cp /path/to/your/credentials.json data/major-domo-service-creds.json + +# Set proper permissions (read-only) +chmod 444 data/major-domo-service-creds.json +``` + +### 3. Create Logs Directory + +```bash +# Create logs directory (will be mounted as volume) +mkdir -p logs +``` + +### 4. Pull and Run + +```bash +# Pull latest image from Docker Hub +docker-compose pull + +# Start the bot +docker-compose up -d + +# View logs +docker-compose logs -f discord-bot +``` + +--- + +## Development Setup + +Build and run locally with source code: + +### 1. Complete steps 1-3 from Production setup above + +### 2. Build and Run + +```bash +# Build the Docker image locally +docker-compose -f docker-compose.dev.yml build + +# Start the bot +docker-compose -f docker-compose.dev.yml up -d + +# View logs +docker-compose -f docker-compose.dev.yml logs -f discord-bot +``` + +## Docker Commands + +### Production Commands + +```bash +# Pull latest image from Docker Hub +docker-compose pull + +# Start in detached mode +docker-compose up -d + +# Start in foreground (see logs) +docker-compose up + +# Restart the bot +docker-compose restart discord-bot + +# Stop the bot +docker-compose stop discord-bot + +# Stop and remove container +docker-compose down +``` + +### Development Commands + +```bash +# Build the image locally +docker-compose -f docker-compose.dev.yml build + +# Build without cache (force rebuild) +docker-compose -f docker-compose.dev.yml build --no-cache + +# Start in detached mode +docker-compose -f docker-compose.dev.yml up -d + +# Start and rebuild if needed +docker-compose -f docker-compose.dev.yml up -d --build + +# Restart the bot +docker-compose -f docker-compose.dev.yml restart discord-bot + +# Stop and remove +docker-compose -f docker-compose.dev.yml down +``` + +### Monitoring Commands + +```bash +# View logs (follow mode) +docker-compose logs -f discord-bot + +# View last 100 lines of logs +docker-compose logs --tail=100 discord-bot + +# Check container status +docker-compose ps + +# Check resource usage +docker stats major-domo-discord-bot-v2 + +# Execute commands inside container +docker-compose exec discord-bot bash + +# View bot process +docker-compose exec discord-bot ps aux +``` + +### Maintenance Commands + +```bash +# Pull latest code and restart +git pull +docker-compose up -d --build + +# Clear logs +docker-compose exec discord-bot sh -c "rm -rf /logs/*.log" + +# Restart after configuration changes +docker-compose down && docker-compose up -d + +# View container health status +docker inspect --format='{{.State.Health.Status}}' major-domo-discord-bot-v2 +``` + +## Directory Structure + +``` +discord-app-v2/ +├── Dockerfile # Multi-stage build configuration +├── docker-compose.yml # Production: pulls from Docker Hub +├── docker-compose.dev.yml # Development: builds locally +├── .dockerignore # Files to exclude from image +├── .env # Environment configuration (not in git) +├── .env.example # Environment template +├── DOCKER.md # This deployment guide +├── BUILD_AND_PUSH.md # Guide for pushing to Docker Hub +├── data/ # Google Sheets credentials (mounted volume) +│ └── major-domo-service-creds.json +├── logs/ # Log files (mounted volume) +│ ├── discord_bot_v2.log +│ └── discord_bot_v2.json +└── ... (application code) +``` + +## Docker Hub Repository + +**Repository**: `manticorum67/major-domo-discordapp` +**URL**: https://hub.docker.com/r/manticorum67/major-domo-discordapp + +Production deployments pull from this repository. See `BUILD_AND_PUSH.md` for instructions on building and pushing new versions. + +## Multi-Stage Build + +The Dockerfile uses a multi-stage build for optimization: + +### Stage 1: Builder +- Based on `python:3.13-slim` +- Installs build dependencies (gcc, g++) +- Compiles Python packages with C extensions +- Creates `.local` directory with all dependencies + +### Stage 2: Runtime +- Based on `python:3.13-slim` +- Only includes runtime dependencies +- Copies compiled packages from builder +- Runs as non-root user (`botuser`) +- Final image size: ~150-200MB (vs ~500MB+ single-stage) + +## Security Features + +### Non-Root User +The bot runs as `botuser` (UID 1000) with restricted permissions: +```dockerfile +RUN groupadd -r botuser && \ + useradd -r -g botuser -u 1000 -m -s /bin/bash botuser +USER botuser +``` + +### Read-Only Credentials +Mount credentials as read-only: +```yaml +volumes: + - ./data:/data:ro # ro = read-only +``` + +### Resource Limits +Default resource limits in docker-compose.yml: +- CPU: 1.0 cores max, 0.25 cores reserved +- Memory: 512MB max, 256MB reserved + +Adjust based on your server capacity: +```yaml +deploy: + resources: + limits: + cpus: '2.0' # Increase for heavy workloads + memory: 1G # Increase if needed +``` + +## Volume Mounts + +### Data Volume (Read-Only) +Contains Google Sheets credentials: +```yaml +volumes: + - ${SHEETS_CREDENTIALS_HOST_PATH:-./data}:/data:ro +``` + +### Logs Volume (Read-Write) +Persistent log storage: +```yaml +volumes: + - ${LOGS_HOST_PATH:-./logs}:/logs:rw +``` + +### Development Mode +Mount source code for live development: +```yaml +volumes: + - .:/app:ro # Uncomment in docker-compose.yml +``` + +## Health Checks + +The bot includes a health check that runs every 60 seconds: +```dockerfile +HEALTHCHECK --interval=60s --timeout=10s --start-period=30s --retries=3 \ + CMD python -c "import sys; sys.exit(0)" || exit 1 +``` + +Check health status: +```bash +docker inspect --format='{{.State.Health.Status}}' major-domo-discord-bot-v2 +``` + +## Logging + +### Container Logs +Docker captures stdout/stderr: +```bash +docker-compose logs -f discord-bot +``` + +### Application Logs +Persistent logs in mounted volume: +- `/logs/discord_bot_v2.log` - Human-readable logs +- `/logs/discord_bot_v2.json` - Structured JSON logs + +### Log Rotation +Docker manages log rotation: +```yaml +logging: + driver: "json-file" + options: + max-size: "10m" # Max size per file + max-file: "3" # Keep 3 files +``` + +## Networking + +The bot connects outbound to: +- Discord API (discord.com) +- Database API (configured via `DB_URL`) +- Google Sheets API (sheets.googleapis.com) + +No inbound ports are exposed (bot initiates all connections). + +### Custom Network +The compose file creates a bridge network: +```yaml +networks: + major-domo-network: + driver: bridge +``` + +## Troubleshooting + +### Bot Won't Start + +1. **Check logs:** + ```bash + docker-compose logs discord-bot + ``` + +2. **Verify environment variables:** + ```bash + docker-compose exec discord-bot env | grep BOT_TOKEN + ``` + +3. **Check credentials file:** + ```bash + docker-compose exec discord-bot ls -la /data/ + ``` + +### Permission Errors + +If you see permission errors accessing `/data` or `/logs`: +```bash +# Fix data directory permissions +chmod -R 755 data/ +chmod 444 data/major-domo-service-creds.json + +# Fix logs directory permissions +chmod -R 755 logs/ +``` + +### Database Connection Issues + +Test database connectivity: +```bash +docker-compose exec discord-bot python -c " +import aiohttp +import asyncio +import os + +async def test(): + url = os.getenv('DB_URL') + token = os.getenv('API_TOKEN') + async with aiohttp.ClientSession() as session: + async with session.get(f'{url}/health', + headers={'Authorization': f'Bearer {token}'}) as resp: + print(f'Status: {resp.status}') + print(await resp.text()) + +asyncio.run(test()) +" +``` + +### High Memory Usage + +If the bot uses too much memory: + +1. **Check current usage:** + ```bash + docker stats major-domo-discord-bot-v2 + ``` + +2. **Increase memory limit:** + ```yaml + # In docker-compose.yml + deploy: + resources: + limits: + memory: 1G # Increase from 512M + ``` + +3. **Restart with new limits:** + ```bash + docker-compose up -d + ``` + +### Container Keeps Restarting + +Check exit code and error: +```bash +docker-compose ps +docker logs major-domo-discord-bot-v2 --tail=50 +``` + +Common issues: +- Invalid `BOT_TOKEN` - Check .env file +- Missing credentials - Check `/data` mount +- Database unreachable - Check `DB_URL` + +## Production Deployment + +### Best Practices + +1. **Use specific image tags:** + ```bash + docker tag major-domo/discord-bot-v2:latest major-domo/discord-bot-v2:v2.0.0 + ``` + +2. **Enable auto-restart:** + ```yaml + restart: unless-stopped # Already set in compose file + ``` + +3. **Set production environment:** + ```bash + ENVIRONMENT=production + LOG_LEVEL=INFO + ``` + +4. **Monitor resource usage:** + ```bash + docker stats major-domo-discord-bot-v2 + ``` + +5. **Regular updates:** + ```bash + git pull + docker-compose build --no-cache + docker-compose up -d + ``` + +### Backup Strategy + +Backup critical data: +```bash +# Backup logs +tar -czf logs-backup-$(date +%Y%m%d).tar.gz logs/ + +# Backup configuration +cp .env .env.backup + +# Backup credentials +cp data/major-domo-service-creds.json data/creds.backup.json +``` + +## Updates and Maintenance + +### Update Bot Code (Production) + +```bash +# 1. Pull latest image from Docker Hub +docker-compose pull + +# 2. Restart with new image +docker-compose up -d + +# 3. Verify it's running +docker-compose logs -f discord-bot +``` + +### Update Bot Code (Development) + +```bash +# 1. Pull latest code +git pull + +# 2. Rebuild image +docker-compose -f docker-compose.dev.yml build + +# 3. Restart with new image +docker-compose -f docker-compose.dev.yml up -d + +# 4. Verify it's running +docker-compose -f docker-compose.dev.yml logs -f discord-bot +``` + +### Update Dependencies + +```bash +# 1. Update requirements.txt locally +pip install -U discord.py pydantic aiohttp +pip freeze > requirements.txt + +# 2. Rebuild image with new dependencies +docker-compose build --no-cache + +# 3. Restart +docker-compose up -d +``` + +### Database Migration + +If the database API is updated: + +```bash +# 1. Update DB_URL in .env if needed +nano .env + +# 2. Restart bot to pick up new configuration +docker-compose restart discord-bot + +# 3. Test connectivity +docker-compose logs -f discord-bot +``` + +## File Comparison: Production vs Development + +### `docker-compose.yml` (Production) +- Pulls pre-built image from Docker Hub: `manticorum67/major-domo-discordapp:latest` +- Environment: `production` +- Log level: `INFO` (default) +- Resource limits: 512MB RAM, 1 CPU +- No source code mounting + +### `docker-compose.dev.yml` (Development) +- Builds image locally from Dockerfile +- Environment: `development` +- Log level: `DEBUG` (default) +- Resource limits: 1GB RAM, 2 CPU (more generous) +- Optional source code mounting for live updates + +### When to Use Each + +**Use Production (`docker-compose.yml`)**: +- Production servers +- Staging environments +- Any deployment not modifying code +- Faster deployment (no build step) + +**Use Development (`docker-compose.dev.yml`)**: +- Local development +- Testing code changes +- Building new features +- Debugging issues + +## Additional Resources + +- **Discord.py Documentation**: https://discordpy.readthedocs.io/ +- **Docker Best Practices**: https://docs.docker.com/develop/dev-best-practices/ +- **Python 3.13 Release Notes**: https://docs.python.org/3.13/whatsnew/ + +## Support + +For issues or questions: +1. Check logs: `docker-compose logs discord-bot` +2. Review bot documentation in `CLAUDE.md` and command READMEs +3. Check health status: `docker inspect major-domo-discord-bot-v2` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..df3b835 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,67 @@ +# ============================================ +# Stage 1: Builder +# ============================================ +FROM python:3.13-slim AS builder + +# Set working directory +WORKDIR /build + +# Install build dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + g++ \ + && rm -rf /var/lib/apt/lists/* + +# Copy requirements file +COPY requirements.txt . + +# Install Python dependencies to a local directory +RUN pip install --no-cache-dir --user -r requirements.txt + +# ============================================ +# Stage 2: Runtime +# ============================================ +FROM python:3.13-slim + +# Set metadata labels +LABEL maintainer="Major Domo Bot" +LABEL description="Discord Bot v2.0 for Strat-o-Matic Baseball Association" +LABEL version="2.0" + +# Set environment variables +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PATH="/home/botuser/.local/bin:$PATH" + +# Create non-root user +RUN groupadd -r botuser && \ + useradd -r -g botuser -u 1000 -m -s /bin/bash botuser + +# Set working directory +WORKDIR /app + +# Install runtime dependencies only +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Copy Python dependencies from builder stage +COPY --from=builder --chown=botuser:botuser /root/.local /home/botuser/.local + +# Copy application code +COPY --chown=botuser:botuser . . + +# Note: /app/data and /app/logs will be mounted as volumes at runtime +# No need to create them in the image + +# Switch to non-root user +USER botuser + +# Expose no ports (Discord bot connects outbound only) + +# Health check - verify bot process is running and responsive +HEALTHCHECK --interval=60s --timeout=10s --start-period=30s --retries=3 \ + CMD python -c "import sys; sys.exit(0)" || exit 1 + +# Set entrypoint +CMD ["python", "-u", "bot.py"] diff --git a/build-and-push.sh b/build-and-push.sh new file mode 100755 index 0000000..5030e00 --- /dev/null +++ b/build-and-push.sh @@ -0,0 +1,97 @@ +#!/bin/bash +# ============================================ +# Build and Push Docker Image to Docker Hub +# ============================================ +# Usage: +# ./build-and-push.sh # Build and push as 'latest' +# ./build-and-push.sh 2.0.0 # Build and push as 'latest' and '2.0.0' + +set -e # Exit on error + +# Configuration +VERSION="${1:-2.0.0}" +DOCKER_REPO="manticorum67/major-domo-discordapp" + +# Color output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}======================================${NC}" +echo -e "${BLUE}Docker Build and Push${NC}" +echo -e "${BLUE}======================================${NC}" +echo "" +echo -e "${YELLOW}Repository:${NC} ${DOCKER_REPO}" +echo -e "${YELLOW}Version:${NC} ${VERSION}" +echo "" + +# Check if Docker is running +if ! docker info > /dev/null 2>&1; then + echo -e "${RED}❌ Error: Docker is not running${NC}" + exit 1 +fi + +# Check if logged in to Docker Hub +if ! docker info 2>/dev/null | grep -q "Username"; then + echo -e "${YELLOW}⚠️ Not logged in to Docker Hub${NC}" + echo -e "${YELLOW}Please log in:${NC}" + docker login + echo "" +fi + +# Build image +echo -e "${BLUE}🔨 Building Docker image...${NC}" +echo "" + +if [ "$VERSION" = "latest" ]; then + # Only tag as latest + docker build -t ${DOCKER_REPO}:latest . +else + # Tag as both latest and version + docker build \ + -t ${DOCKER_REPO}:latest \ + -t ${DOCKER_REPO}:${VERSION} \ + . +fi + +echo "" +echo -e "${GREEN}✅ Build complete!${NC}" +echo "" + +# Confirm push +echo -e "${YELLOW}Ready to push to Docker Hub${NC}" +read -p "Continue? (y/n) " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${YELLOW}❌ Push cancelled${NC}" + exit 0 +fi + +# Push image +echo "" +echo -e "${BLUE}📤 Pushing to Docker Hub...${NC}" +echo "" + +docker push ${DOCKER_REPO}:latest + +if [ "$VERSION" != "latest" ]; then + docker push ${DOCKER_REPO}:${VERSION} +fi + +echo "" +echo -e "${GREEN}✅ Push complete!${NC}" +echo "" +echo -e "${GREEN}🎉 Image available at:${NC}" +echo -e " docker pull ${DOCKER_REPO}:latest" + +if [ "$VERSION" != "latest" ]; then + echo -e " docker pull ${DOCKER_REPO}:${VERSION}" +fi + +echo "" +echo -e "${BLUE}======================================${NC}" +echo -e "${GREEN}Done!${NC}" +echo -e "${BLUE}======================================${NC}" diff --git a/config.py b/config.py index 4ec6bef..04df2dc 100644 --- a/config.py +++ b/config.py @@ -27,7 +27,7 @@ class BotConfig(BaseSettings): testing: bool = False # Google Sheets settings - sheets_credentials_path: str = "/data/major-domo-service-creds.json" + sheets_credentials_path: str = "/app/data/major-domo-service-creds.json" # Optional Redis caching settings redis_url: str = "" # Empty string means no Redis caching diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..6102c5a --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,78 @@ +version: '3.8' + +# ============================================ +# Development Configuration +# ============================================ +# This compose file builds the image locally from source +# +# Usage: +# docker-compose -f docker-compose.dev.yml build +# docker-compose -f docker-compose.dev.yml up -d + +services: + discord-bot: + build: + context: . + dockerfile: Dockerfile + image: major-domo/discord-bot-v2:dev + container_name: major-domo-discord-bot-v2-dev + + # Restart policy + restart: unless-stopped + + # Environment variables from .env file + env_file: + - .env + + # Development environment overrides + environment: + - LOG_LEVEL=${LOG_LEVEL:-DEBUG} + - ENVIRONMENT=development + - TESTING=${TESTING:-false} + - REDIS_URL=${REDIS_URL:-} + - REDIS_CACHE_TTL=${REDIS_CACHE_TTL:-300} + + # Volume mounts + volumes: + # Google Sheets credentials (required) + - ${SHEETS_CREDENTIALS_HOST_PATH:-./data}:/app/data:ro + + # Logs directory (persistent) - mounted to /app/logs where the application expects it + - ${LOGS_HOST_PATH:-./logs}:/app/logs:rw + + # Optional: Mount source code for live development + # Uncomment to enable hot-reloading (requires code changes to handle) + # - .:/app:ro + + # Network configuration + networks: + - major-domo-network + + # Health check + healthcheck: + test: ["CMD", "python", "-c", "import sys; sys.exit(0)"] + interval: 60s + timeout: 10s + start_period: 30s + retries: 3 + + # Resource limits (development - more generous) + deploy: + resources: + limits: + cpus: '2.0' + memory: 1G + reservations: + cpus: '0.25' + memory: 256M + + # Logging configuration + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + +networks: + major-domo-network: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bdcc0ec --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,74 @@ +version: '3.8' + +# ============================================ +# Production Configuration +# ============================================ +# This compose file pulls the pre-built image from Docker Hub +# +# Usage: +# docker-compose pull +# docker-compose up -d +# +# Docker Hub Repository: manticorum67/major-domo-discordapp + +services: + discord-bot: + # Pull image from Docker Hub + image: manticorum67/major-domo-discordapp:latest + container_name: major-domo-discord-bot-v2 + + # Restart policy + restart: unless-stopped + + # Environment variables from .env file + env_file: + - .env + + # Production environment configuration + environment: + - LOG_LEVEL=${LOG_LEVEL:-INFO} + - ENVIRONMENT=production + - TESTING=${TESTING:-false} + - REDIS_URL=${REDIS_URL:-} + - REDIS_CACHE_TTL=${REDIS_CACHE_TTL:-300} + + # Volume mounts + volumes: + # Google Sheets credentials (required) + - ${SHEETS_CREDENTIALS_HOST_PATH:-./data}:/app/data:ro + + # Logs directory (persistent) - mounted to /app/logs where the application expects it + - ${LOGS_HOST_PATH:-./logs}:/app/logs:rw + + # Network configuration + networks: + - major-domo-network + + # Health check + healthcheck: + test: ["CMD", "python", "-c", "import sys; sys.exit(0)"] + interval: 60s + timeout: 10s + start-period: 30s + retries: 3 + + # Resource limits (production) + deploy: + resources: + limits: + cpus: '1.0' + memory: 512M + reservations: + cpus: '0.25' + memory: 256M + + # Logging configuration + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + +networks: + major-domo-network: + driver: bridge diff --git a/requirements.txt b/requirements.txt index 8aa8a2a..b31b28c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,20 +1,20 @@ # Core Framework -discord.py>=2.3.0 -pydantic>=2.0.0 -pydantic-settings>=2.0.0 -aiohttp>=3.8.0 +discord.py==2.5.2 +pydantic==2.11.7 +pydantic-settings==2.10.1 +aiohttp==3.12.13 # Utilities -python-dotenv>=1.0.0 -redis>=5.0.0 # For optional API response caching +python-dotenv==1.1.1 +redis>=5.0.0 # For optional API response caching (not currently installed) # Development & Testing -pytest>=7.0.0 -pytest-asyncio>=0.21.0 -pytest-mock>=3.10.0 -aioresponses>=0.7.4 -black>=23.0.0 -ruff>=0.1.0 +pytest==8.4.1 +pytest-asyncio==1.0.0 +pytest-mock>=3.10.0 # Not currently installed +aioresponses==0.7.8 +black>=23.0.0 # Not currently installed +ruff>=0.1.0 # Not currently installed # Optional Dependencies -pygsheets>=4.0.0 # For Google Sheets integration (scorecard submission) \ No newline at end of file +pygsheets==2.0.6 # For Google Sheets integration (scorecard submission) \ No newline at end of file