parent
a665a8175a
commit
0fb7c6bea2
14
.env.example
14
.env.example
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
CREATE DATABASE metin2 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
|
@ -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/*
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue