Docker Deployment Guide
Review before exposing to production
The quick-start settings are for evaluation. Before production, revisit the MySQL password, REPLICATION_SERVER_ID, the source CIDRs, the Docker memory limit, and the persistent volume for dumps.
This guide explains how to deploy MygramDB using Docker and Docker Compose.
Quick Start
1. Prerequisites
- Docker 20.10+
- Docker Compose 2.0+
2. Setup Environment Variables
# Copy the example environment file
cp .env.example .env
# Edit .env and configure your settings
nano .envWARNING
Change the following default values in .env:
MYSQL_ROOT_PASSWORD- MySQL root passwordMYSQL_PASSWORD- MySQL replication user password; Compose requires it, and the entrypoint requires it when generating a configurationAPI_ADMIN_TOKEN- high-entropy secret for administrative commands; Compose rejects an unset value and the entrypoint rejects the sample placeholderREPLICATION_SERVER_ID- Unique server ID for this MygramDB instance
3. Start Services (Development)
# Build and start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Check status
docker-compose ps4. Stop Services
# Stop all services
docker-compose down
# Stop and remove volumes (WARNING: This deletes all data)
docker-compose down -vConfiguration
Environment Variables
The .env file configures the single-table quick-start image. The current .env.example is the complete source of supported variables; use a mounted configuration file for multi-table and advanced settings.
Environment variables vs config file
Environment variables are the fast path to a basic single-table deployment. For multiple tables, multiple databases, filters, synonyms, or detailed HTTP settings, mount a custom configuration file as described below.
Prefer a config file in production
In production, managing an explicit config.yaml makes changes easier to review than expressing everything through environment variables. Use environment variables for the values that differ per environment, such as passwords and hostnames.
MySQL Configuration
MYSQL_HOST=mysql # MySQL host
MYSQL_PORT=3306 # MySQL port
MYSQL_USER=repl_user # MySQL user
MYSQL_PASSWORD=your_password # Required MySQL password
MYSQL_DATABASE=mydb # Database name
MYSQL_USE_GTID=true # Use GTID-based replicationTable Configuration
TABLE_NAME=articles # Table to index
TABLE_PRIMARY_KEY=id # Primary key column
TABLE_TEXT_COLUMN=content # Text column to index
TABLE_NGRAM_SIZE=2 # N-gram size for ASCII
TABLE_KANJI_NGRAM_SIZE=1 # N-gram size for CJKReplication Configuration
What is server_id?
server_id identifies a MySQL replication connection. Give each MygramDB instance and MySQL replica attached to the same MySQL a value that does not collide.
REPLICATION_ENABLE=true # Enable replication
REPLICATION_SERVER_ID=12345 # Unique server ID (IMPORTANT)
REPLICATION_START_FROM=snapshot # Start from: snapshot, latest, or gtid=<UUID:txn>
REPLICATION_AUTO_INITIAL_SNAPSHOT=true # Build the initial snapshot automaticallyMemory Management
MEMORY_HARD_LIMIT_MB=8192 # Hard memory limit
MEMORY_SOFT_TARGET_MB=4096 # Soft memory target
MEMORY_NORMALIZE_NFKC=true # NFKC normalization
MEMORY_NORMALIZE_WIDTH=narrow # Width normalization
MEMORY_VERIFY_TEXT=off # off, ascii, or allDumps, Ranking, and Cache
DUMP_DIR=/var/lib/mygramdb/dumps
DUMP_INTERVAL_SEC=600
DUMP_RETAIN=3
BM25_ENABLE=false
BM25_K1=1.2
BM25_B=0.75
CACHE_ENABLED=true
CACHE_MAX_MEMORY_MB=32
CACHE_MIN_QUERY_COST_MS=10.0
CACHE_TTL_SECONDS=3600Use DUMP_*, not the removed SNAPSHOT_* variables.
MySQL TLS
Set a Docker memory limit
MygramDB's own memory settings do not forcibly cap process usage. When running in containers, set mem_limit in Compose or the equivalent limit on your orchestration platform.
MYSQL_DATETIME_TIMEZONE=+00:00
MYSQL_SSL_ENABLE=false
MYSQL_SSL_CA=
MYSQL_SSL_CERT=
MYSQL_SSL_KEY=
MYSQL_SSL_VERIFY_SERVER_CERT=trueAPI Server
Host bind and container bind are separate
The Compose file publishes TCP and HTTP ports on 127.0.0.1 on the host. Inside the Docker network, it uses API_CONTAINER_BIND and API_HTTP_CONTAINER_BIND (both default to 0.0.0.0) because a container must listen on its own interface. Do not replace the host-side loopback mappings with public mappings unless a reverse proxy or firewall is part of the design.
API_BIND=127.0.0.1 # Directly launched server bind address
API_PORT=11016 # API port
API_HTTP_ENABLE=true
API_HTTP_BIND=127.0.0.1
API_HTTP_PORT=8080
API_ADMIN_TOKEN=CHANGE_ME_GENERATE_RANDOM_SECRET
# Compose-only container listeners; host ports stay bound to 127.0.0.1
API_CONTAINER_BIND=0.0.0.0
API_HTTP_CONTAINER_BIND=0.0.0.0
API_RATE_LIMIT_ENABLE=false
API_RATE_LIMIT_CAPACITY=100
API_RATE_LIMIT_REFILL_RATE=10
API_RATE_LIMIT_MAX_CLIENTS=10000API_ADMIN_TOKEN is required by Compose because the container listener is non-loopback. Generate it with openssl rand -hex 32. Administrative TCP commands require AUTH <token> on the connection; POST /optimize requires Authorization: Bearer <token>.
Network Configuration
# The Docker bridge presents published-port clients as its gateway.
# 172.16.0.0/12 covers Docker's default bridge pool; narrow this when possible.
NETWORK_ALLOW_CIDRS=127.0.0.1/32,172.16.0.0/12WARNING
NETWORK_ALLOW_CIDRS is mandatory in Compose. Do not use 0.0.0.0/0 or ::/0 with a non-loopback API bind: MygramDB rejects that configuration at startup. For a custom container network, set only the application and operator CIDRs that need access.
Logging
LOG_LEVEL=info # Log level: debug, info, warn, error
LOG_FORMAT=json # Log format: json or textCustom Configuration File
If you need more advanced configuration (filters, multiple tables, etc.), you can mount a custom config file:
# docker-compose.override.yml
version: '3.8'
services:
mygramdb:
volumes:
- ./my-config.yaml:/etc/mygramdb/config.yaml:ro
environment:
SKIP_CONFIG_GEN: "true"
command: ["mygramdb", "-c", "/etc/mygramdb/config.yaml"]Or run directly with Docker:
# Create your config file
cp examples/config-minimal.yaml my-config.yaml
# Edit my-config.yaml as needed
# Run with custom config
docker run -d --name mygramdb \
-p 11016:11016 \
-v $(pwd)/my-config.yaml:/etc/mygramdb/config.yaml:ro \
-e SKIP_CONFIG_GEN=true \
mygramdb:latest \
mygramdb -c /etc/mygramdb/config.yamlProduction Deployment
Building Docker Images
To build a Docker image with proper version tagging:
# Get the current version from git tag
VERSION=$(git describe --tags --abbrev=0 | sed 's/^v//')
# Build with version argument
docker build --build-arg MYGRAMDB_VERSION=$VERSION -t mygramdb:$VERSION .
# Or specify version manually
docker build --build-arg MYGRAMDB_VERSION=1.2.5 -t mygramdb:1.2.5 .
# Tag as latest
docker tag mygramdb:$VERSION mygramdb:latestNote: If MYGRAMDB_VERSION build argument is not provided, the build will use version 0.0.0 or attempt to read from git tags if the .git directory is present in the build context.
Using Pre-built Images
# Pull the latest image from GitHub Container Registry
docker pull ghcr.io/libraz/mygram-db:latest
# Use production docker-compose file
docker-compose -f docker-compose.prod.yml up -dEnvironment Setup
- Create production
.envfile:
cp .env.example .env.prod
nano .env.prod- Set production values:
# Production MySQL configuration
MYSQL_HOST=production-mysql-host
MYSQL_PORT=3306
MYSQL_USER=repl_user
MYSQL_PASSWORD=strong_secure_password_here
# Generate with `openssl rand -hex 32`, then paste the output here.
API_ADMIN_TOKEN=CHANGE_ME_GENERATE_RANDOM_SECRET
NETWORK_ALLOW_CIDRS=127.0.0.1/32,172.16.0.0/12
# Production memory settings
MEMORY_HARD_LIMIT_MB=16384
MEMORY_SOFT_TARGET_MB=8192
# Production API settings. Compose publishes these ports only on localhost.
API_PORT=11016
API_HTTP_PORT=8080
# Production logging
LOG_LEVEL=info
LOG_FORMAT=json- Start with production configuration:
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -dResource Limits
Production compose file includes resource limits:
MySQL:
- CPU: 2-4 cores
- Memory: 2-4 GB
MygramDB:
- CPU: 4-8 cores
- Memory: 10-20 GB
Adjust these in docker-compose.prod.yml based on your workload.
Database Initialization
The MySQL container automatically executes scripts in support/docker/mysql/init/:
01-create-tables.sql- Creates sample tables
To add your own initialization scripts:
# Create your SQL script
cat > support/docker/mysql/init/02-my-tables.sql <<EOF
CREATE TABLE my_table (
id BIGINT PRIMARY KEY,
content TEXT
);
EOF
# Restart MySQL container
docker-compose restart mysqlMonitoring
View Logs
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f mygramdb
# Last 100 lines
docker-compose logs --tail=100 mygramdbHealth Checks
# Check service health
docker-compose ps
# Manual health check
docker exec mygramdb pgrep -x mygramdbMetrics
MygramDB exposes metrics on the HTTP API port (8080 by default). Access via:
curl http://localhost:8080/metricsBackup and Restore
Backup
# Backup MySQL data
docker exec mygramdb_mysql mysqldump -u root -p${MYSQL_ROOT_PASSWORD} mydb > backup.sql
# Backup MygramDB snapshot
docker cp mygramdb:/var/lib/mygramdb/dumps ./backup-dumps/Restore
# Restore MySQL data
docker exec -i mygramdb_mysql mysql -u root -p${MYSQL_ROOT_PASSWORD} mydb < backup.sql
# Restore and explicitly load a MygramDB dump
docker cp ./backup-dumps/mygramdb.dmp mygramdb:/var/lib/mygramdb/dumps/mygramdb.dmp
docker exec -i mygramdb sh -c 'printf "AUTH %s\nDUMP VERIFY /var/lib/mygramdb/dumps/mygramdb.dmp\n" "$API_ADMIN_TOKEN" | mygram-cli'
docker exec -i mygramdb sh -c 'printf "AUTH %s\nDUMP LOAD /var/lib/mygramdb/dumps/mygramdb.dmp\n" "$API_ADMIN_TOKEN" | mygram-cli'Troubleshooting
Connection Issues
# Check network connectivity
docker-compose exec mygramdb ping mysql
# Check MySQL connection
docker-compose exec mygramdb mysql -h mysql -u repl_user -p${MYSQL_PASSWORD} -e "SELECT 1"Configuration Issues
# Check version
docker run --rm mygramdb:latest --version
# Show help
docker run --rm mygramdb:latest --help
# Test configuration
docker-compose exec mygramdb /usr/local/bin/entrypoint.sh test-config
# Or test with environment variables (uses defaults for unspecified values)
docker run --rm -e MYSQL_HOST=testdb -e TABLE_NAME=test mygramdb:latest test-config
# View generated configuration
docker-compose exec mygramdb cat /etc/mygramdb/config.yamlPerformance Issues
- Check resource usage:
docker stats- Adjust memory limits in
.env:
MEMORY_HARD_LIMIT_MB=16384
MEMORY_SOFT_TARGET_MB=8192- Adjust build parallelism:
BUILD_PARALLELISM=4Scaling
Multiple MygramDB Instances
To run multiple MygramDB instances (e.g., for different tables):
# Create separate compose files for each instance
cp docker-compose.yml docker-compose.instance1.yml
cp docker-compose.yml docker-compose.instance2.yml
# Use different project names and ports
docker-compose -f docker-compose.instance1.yml -p mygramdb1 up -d
docker-compose -f docker-compose.instance2.yml -p mygramdb2 up -dLoad Balancing
Use nginx or HAProxy to load balance across multiple MygramDB instances:
upstream mygramdb_backend {
server localhost:11016;
server localhost:11017;
server localhost:11018;
}
server {
listen 80;
location / {
proxy_pass http://mygramdb_backend;
}
}Security Best Practices
- Use strong passwords - Change all default passwords in
.env - Network isolation - Use Docker networks to isolate services
- Bind to localhost - In production, bind MySQL to
127.0.0.1only - Enable TLS - Use TLS for MySQL connections
- Regular updates - Keep Docker images up to date
- Backup regularly - Automate backups of MySQL and MygramDB snapshots