change: MariaDB > PG.

add: Redis.
master
WildEgo 2026-02-14 17:36:14 +00:00
parent a665a8175a
commit 0fb7c6bea2
6 changed files with 335 additions and 44 deletions

View File

@ -5,14 +5,14 @@ GAME_IMAGE=git.old-metin2.com/metin2/server:latest
WEB_IMAGE=git.old-metin2.com/metin2/web:latest
################################################################################
# MariaDB settings
# Database settings
################################################################################
MARIADB_HOST=mariadb
MARIADB_USER=root
MARIADB_PASSWORD=metin2
MARIADB_PORT=3306
MARIADB_EXTERNAL_PORT=3306
MARIADB_DB=metin2
DATABASE_HOST=database
DATABASE_USER=metin2
DATABASE_PASSWORD=metin2
DATABASE_PORT=5432
DATABASE_EXTERNAL_PORT=33065432
DATABASE_DATABASE=metin2
################################################################################
# Web app settings

View File

@ -14,9 +14,7 @@ sure that you have a compatible Linux + Docker environment - for more
information, check out the [compatibility matrix](https://git.old-metin2.com/metin2/deploy#compatibility-matrix).
### Architecture description
The MySQL database is currently pinned on version 5.5. We're using the
[biarms/mysql](https://github.com/biarms/mysql) project in order to provide ARM
compatibility for such an old version of MySQL.
The PostgreSQL database is currently pinned on version 18..
The game cores (`db`, `auth`, `game-*`) are ran by using pre-built images
containing the server binaries and game files, provided in the
@ -93,7 +91,7 @@ need a database and website, but want to run the server in some other way (for
example, in an IDE), you can just bring up only the services you need:
```shell
docker compose up -d mysql web
docker compose up -d database web
```
## Compatibility matrix

View File

@ -1 +0,0 @@
CREATE DATABASE metin2 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

View File

@ -0,0 +1,23 @@
FROM postgres:18
# Install build dependencies and redis-tools
RUN apt-get update && apt-get install -y \
build-essential \
git \
postgresql-server-dev-18 \
libhiredis-dev \
ca-certificates \
redis-tools \
&& rm -rf /var/lib/apt/lists/*
# Clone and build redis_fdw
RUN git clone https://github.com/pg-redis-fdw/redis_fdw.git /tmp/redis_fdw && \
cd /tmp/redis_fdw && \
make USE_PGXS=1 && \
make USE_PGXS=1 install && \
rm -rf /tmp/redis_fdw
# Clean up build dependencies to reduce image size (but keep redis-tools)
RUN apt-get update && \
apt-get purge -y --auto-remove build-essential git postgresql-server-dev-18 && \
rm -rf /var/lib/apt/lists/*

View File

@ -0,0 +1,212 @@
#!/bin/bash
set -e
# Function to log errors
log_error() {
echo "ERROR: $1" >&2
}
log_info() {
echo "INFO: $1"
}
# Trap errors and log them
trap 'log_error "Script failed at line $LINENO"' ERR
log_info "Starting Redis FDW initialization..."
log_info "Redis connection details:"
log_info " Host: ${REDIS_HOST:-redis}"
log_info " Port: 6379"
log_info " Password: $(if [ -n "$REDIS_PASSWORD" ]; then echo "[SET]"; else echo "[NOT SET]"; fi)"
# Wait for Redis to be ready
log_info "Waiting for Redis to be ready..."
REDIS_READY=false
MAX_ATTEMPTS=30
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
if redis-cli -h ${REDIS_HOST:-redis} -a "${REDIS_PASSWORD}" ping 2>/dev/null | grep -q PONG; then
REDIS_READY=true
log_info "Redis is ready after $ATTEMPT attempts"
break
fi
ATTEMPT=$((ATTEMPT + 1))
log_info "Redis is unavailable - attempt $ATTEMPT/$MAX_ATTEMPTS"
sleep 2
done
if [ "$REDIS_READY" = false ]; then
log_error "Redis failed to become ready after $MAX_ATTEMPTS attempts"
log_error "Check if Redis container is running and accessible at ${REDIS_HOST:-redis}:6379"
exit 1
fi
# Get Redis info
log_info "Fetching Redis server information..."
REDIS_VERSION=$(redis-cli -h ${REDIS_HOST:-redis} -a "${REDIS_PASSWORD}" INFO server 2>/dev/null | grep "redis_version" | cut -d: -f2 | tr -d '\r' || echo "unknown")
REDIS_MODE=$(redis-cli -h ${REDIS_HOST:-redis} -a "${REDIS_PASSWORD}" INFO server 2>/dev/null | grep "redis_mode" | cut -d: -f2 | tr -d '\r' || echo "unknown")
REDIS_UPTIME=$(redis-cli -h ${REDIS_HOST:-redis} -a "${REDIS_PASSWORD}" INFO server 2>/dev/null | grep "uptime_in_seconds" | cut -d: -f2 | tr -d '\r' || echo "unknown")
TOTAL_KEYS=$(redis-cli -h ${REDIS_HOST:-redis} -a "${REDIS_PASSWORD}" DBSIZE 2>/dev/null | awk '{print $2}' || echo "0")
log_info "Redis server info:"
log_info " Version: $REDIS_VERSION"
log_info " Mode: $REDIS_MODE"
log_info " Uptime: $REDIS_UPTIME seconds"
log_info " Total keys in DB 0: $TOTAL_KEYS"
# Test Redis connectivity with a test key
log_info "Testing Redis write/read operations..."
if redis-cli -h ${REDIS_HOST:-redis} -a "${REDIS_PASSWORD}" SET fdw_test_key "fdw_init_$(date +%s)" EX 60 >/dev/null 2>&1; then
TEST_VALUE=$(redis-cli -h ${REDIS_HOST:-redis} -a "${REDIS_PASSWORD}" GET fdw_test_key 2>/dev/null)
log_info "Redis write/read test successful (value: $TEST_VALUE)"
else
log_error "Redis write/read test failed"
exit 1
fi
log_info "Setting up redis_fdw extension..."
log_info "PostgreSQL connection:"
log_info " User: $POSTGRES_USER"
log_info " Database: $POSTGRES_DB"
# Run SQL setup as postgres user with error handling
if psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL; then
-- Create redis_fdw extension
DO \$\$
BEGIN
CREATE EXTENSION IF NOT EXISTS redis_fdw;
RAISE NOTICE 'redis_fdw extension created/verified';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to create redis_fdw extension: %', SQLERRM;
END;
\$\$;
-- Create foreign server
DO \$\$
BEGIN
DROP SERVER IF EXISTS redis_server CASCADE;
CREATE SERVER redis_server
FOREIGN DATA WRAPPER redis_fdw
OPTIONS (
address '${REDIS_HOST:-redis}',
port '6379'
);
RAISE NOTICE 'Foreign server redis_server created (host: ${REDIS_HOST:-redis}, port: 6379)';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to create foreign server: %', SQLERRM;
END;
\$\$;
-- Create user mapping
DO \$\$
BEGIN
CREATE USER MAPPING FOR CURRENT_USER
SERVER redis_server
OPTIONS (password '${REDIS_PASSWORD}');
RAISE NOTICE 'User mapping created for CURRENT_USER';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to create user mapping: %', SQLERRM;
END;
\$\$;
-- Create foreign table for Redis hashes
DO \$\$
BEGIN
DROP FOREIGN TABLE IF EXISTS redis_hashes;
CREATE FOREIGN TABLE redis_hashes (
key TEXT,
value TEXT
)
SERVER redis_server
OPTIONS (
database '0',
tabletype 'hash'
);
RAISE NOTICE 'Foreign table redis_hashes created (database: 0, tabletype: hash)';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to create redis_hashes: %', SQLERRM;
END;
\$\$;
-- Create foreign table for Redis lists
DO \$\$
BEGIN
DROP FOREIGN TABLE IF EXISTS redis_lists;
CREATE FOREIGN TABLE redis_lists (
key TEXT,
value TEXT
)
SERVER redis_server
OPTIONS (
database '0',
tabletype 'list'
);
RAISE NOTICE 'Foreign table redis_lists created (database: 0, tabletype: list)';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to create redis_lists: %', SQLERRM;
END;
\$\$;
-- Create foreign table for Redis sets
DO \$\$
BEGIN
DROP FOREIGN TABLE IF EXISTS redis_sets;
CREATE FOREIGN TABLE redis_sets (
key TEXT,
value TEXT
)
SERVER redis_server
OPTIONS (
database '0',
tabletype 'set'
);
RAISE NOTICE 'Foreign table redis_sets created (database: 0, tabletype: set)';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to create redis_sets: %', SQLERRM;
END;
\$\$;
-- Create foreign table for Redis sorted sets
DO \$\$
BEGIN
DROP FOREIGN TABLE IF EXISTS redis_zsets;
CREATE FOREIGN TABLE redis_zsets (
key TEXT,
value TEXT
)
SERVER redis_server
OPTIONS (
database '0',
tabletype 'zset'
);
RAISE NOTICE 'Foreign table redis_zsets created (database: 0, tabletype: zset)';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to create redis_zsets: %', SQLERRM;
END;
\$\$;
-- Grant permissions
DO \$\$
BEGIN
GRANT SELECT ON redis_hashes TO PUBLIC;
GRANT SELECT ON redis_lists TO PUBLIC;
GRANT SELECT ON redis_sets TO PUBLIC;
GRANT SELECT ON redis_zsets TO PUBLIC;
RAISE NOTICE 'Permissions granted on all Redis foreign tables';
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Failed to grant permissions: %', SQLERRM;
END;
\$\$;
-- Final verification
SELECT 'Redis FDW setup completed successfully!' as status;
EOSQL
log_info "Redis FDW SQL setup completed successfully"
else
log_error "Redis FDW SQL setup failed with exit code $?"
exit 1
fi
log_info "Redis FDW initialization complete"

View File

@ -1,12 +1,18 @@
x-environment: &common-environment
MARIADB_HOST: ${MARIADB_HOST}
MARIADB_USER: ${MARIADB_USER}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
MARIADB_PORT: ${MARIADB_PORT}
MARIADB_DB: ${MARIADB_DB}
DATABASE_HOST: ${DATABASE_HOST}
DATABASE_USER: ${DATABASE_USER}
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
DATABASE_PORT: ${DATABASE_PORT}
DATABASE_DB: ${DATABASE_DB}
REDIS_HOST: ${REDIS_HOST}
REDIS_PASSWORD: ${REDIS_PASSWORD}
REDIS_EXTERNAL_PORT: ${REDIS_EXTERNAL_PORT}
TEST_SERVER: ${TEST_SERVER}
DATABASE_ADDR: ${DATABASE_ADDR}
DB_ADDR: ${DB_ADDR}
DB_PORT: ${DB_PORT}
@ -15,32 +21,86 @@ x-environment: &common-environment
WEB_APP_URL: ${WEB_APP_URL}
WEB_APP_KEY: ${WEB_APP_KEY}
ADMIN_PAGE_IP: ${ADMIN_PAGE_IP}
ADMIN_PAGE_IP1: ${ADMIN_PAGE_IP1}
ADMIN_PAGE_IP2: ${ADMIN_PAGE_IP2}
ADMIN_PAGE_IP3: ${ADMIN_PAGE_IP3}
name: Metin2
services:
# MariaDB Database
mariadb:
image: mariadb:lts
# Database
database:
image: ${DB_IMAGE}
restart: always
environment:
# Password for root access
MARIADB_ROOT_PASSWORD: ${MARIADB_PASSWORD}
POSTGRES_USER: ${DATABASE_USER:-root}
POSTGRES_DB: ${DATABASE_DB:-metin2}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-rootpassword}
REDIS_HOST: ${REDIS_HOST:-redis}
REDIS_PASSWORD: ${REDIS_PASSWORD}
ports:
- "${MARIADB_EXTERNAL_PORT}:${MARIADB_PORT}"
- "${DATABASE_EXTERNAL_PORT:-5432}:${DATABASE_PORT:-5432}"
expose:
- ${MARIADB_PORT}
- "${DATABASE_PORT:-5432}"
volumes:
- ./storage/database/:/var/lib/mysql/
- ./assets/db-init/:/docker-entrypoint-initdb.d/:ro
- ./storage/database:/var/lib/postgresql
- ./assets/postgres/db-init:/docker-entrypoint-initdb.d:ro
healthcheck:
test:
[
"CMD",
"healthcheck.sh",
"--su-mysql",
"--connect",
"--innodb_initialized",
]
test: ["CMD-SHELL", "pg_isready -U ${DATABASE_USER:-root}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- metin2
depends_on:
redis:
condition: service_healthy
pgbouncer:
image: docker.io/bitnamilegacy/pgbouncer:latest
restart: always
environment:
POSTGRESQL_HOST: database
POSTGRESQL_PORT: ${DATABASE_PORT:-5432}
POSTGRESQL_USERNAME: ${DATABASE_USER:-root}
POSTGRESQL_PASSWORD: ${DATABASE_PASSWORD:-rootpassword}
POSTGRESQL_DATABASE: ${DATABASE_DB:-metin2}
PGBOUNCER_DATABASE: ${DATABASE_DB:-metin2}
PGBOUNCER_PORT: 6432
PGBOUNCER_POOL_MODE: transaction
PGBOUNCER_MAX_CLIENT_CONN: 500
PGBOUNCER_DEFAULT_POOL_SIZE: 20
PGBOUNCER_MIN_POOL_SIZE: 5
PGBOUNCER_RESERVE_POOL_SIZE: 3
PGBOUNCER_MAX_DB_CONNECTIONS: 50
PGBOUNCER_QUERY_TIMEOUT: 30
PGBOUNCER_IDLE_TRANSACTION_TIMEOUT: 60
PGBOUNCER_SERVER_IDLE_TIMEOUT: 600
PGBOUNCER_STATS_USERS: ${DATABASE_USER:-root}
PGBOUNCER_IGNORE_STARTUP_PARAMETERS: extra_float_digits
ports:
- "${PGBOUNCER_EXTERNAL_PORT:-6432}:6432"
expose:
- "6432"
depends_on:
database:
condition: service_healthy
networks:
- metin2
redis:
image: redis:7
restart: always
ports:
- "${REDIS_EXTERNAL_PORT:-6379}:6379"
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD}
volumes:
- ./storage/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
@ -58,7 +118,7 @@ services:
volumes:
- ./storage/log/db/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -69,7 +129,6 @@ services:
restart: always
environment:
<<: *common-environment
MARIADB_DB: ${MARIADB_DB}
GAME_HOSTNAME: auth
GAME_CHANNEL: 1
GAME_AUTH_SERVER: master
@ -84,7 +143,7 @@ services:
volumes:
- ./storage/log/auth/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -111,7 +170,7 @@ services:
- ./storage/log/ch1/first/:/app/log/
- ./storage/mark/:/app/mark/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -136,7 +195,7 @@ services:
volumes:
- ./storage/log/ch1/game1/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -161,7 +220,7 @@ services:
volumes:
- ./storage/log/ch1/game2/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -186,7 +245,7 @@ services:
volumes:
- ./storage/log/ch1/game3/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -211,7 +270,7 @@ services:
volumes:
- ./storage/log/ch1/game4/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -236,7 +295,7 @@ services:
volumes:
- ./storage/log/ch1/game5/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2
@ -262,7 +321,7 @@ services:
volumes:
- ./storage/log/game99/:/app/log/
depends_on:
mariadb:
database:
condition: service_healthy
networks:
- metin2