Conversation
Docker is pre-installed on the server, so the install block is no longer needed. This also eliminates the apt source mismatch error (ubuntu vs debian repo). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server has docker.io + docker-compose standalone binary installed, not the Docker Compose V2 plugin. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server uses docker-compose V1 standalone binary. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…bility docker-compose V1 does not reliably respect condition: service_healthy without a version field, causing the migrator to run before MySQL is ready. restart: on-failure ensures it retries until MySQL accepts connections. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds migrate-entrypoint.sh which detects 'Dirty database version' errors, forces the version back to the last successful migration, and retries. Eliminates the need for manual intervention on dirty migration state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded api.gamers.io.kr with DOMAIN env var across all configs. - nginx: use templates/default.conf.template with envsubst (nginx:alpine built-in) - init-letsencrypt.sh: read DOMAIN from .env - deploy.sh: read DOMAIN from .env for cert path check - .env.example: add DOMAIN field Set DOMAIN=api.gamers.io.kr in production .env Set DOMAIN=staging.gamers.io.kr in staging .env Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- prometheus: scrapes api, mysql, redis, rabbitmq metrics (30d retention) - grafana: admin credentials via env vars, sign-up disabled - mysql-exporter: prom/mysqld-exporter - redis-exporter: oliver006/redis_exporter - rabbitmq: enable rabbitmq_prometheus plugin via enabled_plugins - prometheus/grafana ports bound to 127.0.0.1 (SSH tunnel access only) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…compose starts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…itmq config files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t loop Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uance Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e starts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nied Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…panels Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…erences Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rmat Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request implements a comprehensive monitoring stack including Prometheus, Grafana, and exporters for MySQL, Redis, and RabbitMQ. It also refactors the deployment process by introducing Nginx configuration templates, environment-based domain handling, and a dedicated database migration entrypoint script. Feedback focuses on the high-risk automatic recovery of "dirty" database states which could lead to data corruption, the redundant generation of Prometheus configuration within the deployment script, and the use of deprecated Docker Compose V1 commands. Additionally, a potential issue with MySQL DSN parsing was identified regarding special characters in passwords.
| # Dirty state 감지 → 자동 복구 | ||
| if echo "$output" | grep -q "Dirty database version"; then | ||
| VERSION=$(echo "$output" | grep -oE "Dirty database version [0-9]+" | grep -oE "[0-9]+$") | ||
| PREV=$((VERSION - 1)) | ||
| echo "⚠️ Dirty migration detected at version $VERSION → forcing to $PREV..." | ||
| migrate -path ./db/migrations -database "$DB_URL" force $PREV | ||
| echo "🔄 Retrying migrations..." | ||
| make migrate-up | ||
| echo "✅ Migrations recovered and completed" | ||
| exit 0 | ||
| fi |
There was a problem hiding this comment.
Automatically performing a migrate force when a 'dirty' state is detected is a high-risk operation. A dirty database state usually indicates that a previous migration failed midway, leaving the schema in an inconsistent or partial state. Forcing the version back and retrying the migration (make migrate-up) will likely fail again with errors like 'table already exists' or 'column already exists' because the partial changes from the failed run are still present. This could potentially lead to data loss or further corruption. It is strongly recommended to handle dirty states manually to ensure data integrity.
| if [ ! -f prometheus/prometheus.yml ]; then | ||
| cat > prometheus/prometheus.yml << 'EOF' | ||
| global: | ||
| scrape_interval: 15s | ||
| evaluation_interval: 15s | ||
|
|
||
| scrape_configs: | ||
| - job_name: "prometheus" | ||
| static_configs: | ||
| - targets: ["localhost:9090"] | ||
|
|
||
| - job_name: "gamers-api" | ||
| static_configs: | ||
| - targets: ["web-app:8080"] | ||
| metrics_path: /metrics | ||
|
|
||
| - job_name: "mysql" | ||
| static_configs: | ||
| - targets: ["gamers-mysql-exporter:9104"] | ||
|
|
||
| - job_name: "redis" | ||
| static_configs: | ||
| - targets: ["gamers-redis-exporter:9121"] | ||
|
|
||
| - job_name: "rabbitmq" | ||
| static_configs: | ||
| - targets: ["gamers-rabbitmq:15692"] | ||
| metrics_path: /metrics | ||
| EOF | ||
| echo "✅ prometheus.yml created" | ||
| else | ||
| echo "✅ prometheus.yml already exists" | ||
| fi |
There was a problem hiding this comment.
This block dynamically generates prometheus/prometheus.yml, but the file is already included in the repository in this pull request. Maintaining the configuration in two places (the script and the actual file) is error-prone and redundant. It is better to remove this generation logic and rely on the version-controlled file as the single source of truth.
| # Stop and remove old containers | ||
| echo "🛑 Stopping old containers..." | ||
| docker compose down || true | ||
| docker-compose down || true |
There was a problem hiding this comment.
The script has been updated to use the deprecated docker-compose (V1) command instead of docker compose (V2). Docker Compose V2 is the modern standard, offers better performance, and was used in the previous version of this script. Unless the production environment specifically lacks V2 support, it is recommended to revert to the non-hyphenated command.
| docker-compose down || true | |
| docker compose down || true |
| env_file: | ||
| - .env | ||
| environment: | ||
| - DATA_SOURCE_NAME=${DB_USER}:${DB_PASSWORD}@(gamers-mysql:3306)/ |
There was a problem hiding this comment.
The DATA_SOURCE_NAME for the MySQL exporter is constructed by concatenating environment variables. If DB_PASSWORD contains special characters such as @, :, or /, the resulting DSN will be invalid and the exporter will fail to connect. Consider using a credentials file mounted as a volume or ensuring the password is properly URL-encoded for the DSN string.
No description provided.