From 6a42a170e7d1c177fc46fb0cb4c51775d19f8717 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Fri, 7 Nov 2025 12:38:44 +0100 Subject: [PATCH] Unify Dockerfile --- .github/workflows/build_and_push.yml | 2 +- docker/.env.example | 140 +++++++++++++++++++++++++++ docker/Dockerfile | 110 +++++++++++++++++++++ docker/docker-compose.yml | 95 ++++++++++-------- 4 files changed, 304 insertions(+), 43 deletions(-) create mode 100644 docker/.env.example create mode 100644 docker/Dockerfile diff --git a/.github/workflows/build_and_push.yml b/.github/workflows/build_and_push.yml index 3c04cdb6..23cb3a36 100644 --- a/.github/workflows/build_and_push.yml +++ b/.github/workflows/build_and_push.yml @@ -96,7 +96,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . - file: ./docker/Dockerfile.dev + file: ./docker/Dockerfile push: true tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/docker/.env.example b/docker/.env.example new file mode 100644 index 00000000..cfd1c6be --- /dev/null +++ b/docker/.env.example @@ -0,0 +1,140 @@ +# Dawarich Docker Compose Configuration +# Copy this file to .env and customize for your environment + +# ============================================================================= +# ENVIRONMENT CONFIGURATION +# ============================================================================= + +# Rails environment: development, staging, or production +RAILS_ENV=development + +# ============================================================================= +# DATABASE CONFIGURATION +# ============================================================================= + +# PostgreSQL credentials +POSTGRES_USER=postgres +POSTGRES_PASSWORD=password + +# Database name - will default to dawarich_${RAILS_ENV} +# For development: dawarich_development +# For staging: dawarich_staging +# For production: dawarich_production +POSTGRES_DB=dawarich_development + +# Database connection settings (used by Rails app) +DATABASE_HOST=dawarich_db +DATABASE_PORT=5432 +DATABASE_USERNAME=postgres +DATABASE_PASSWORD=password +DATABASE_NAME=dawarich_development + +# ============================================================================= +# REDIS CONFIGURATION +# ============================================================================= + +# Redis connection URL +REDIS_URL=redis://dawarich_redis:6379 + +# ============================================================================= +# APPLICATION SETTINGS +# ============================================================================= + +# Port to expose the application on +DAWARICH_APP_PORT=3000 + +# Application hosts (comma-separated) +# Development: localhost +# Production: your-domain.com,www.your-domain.com +APPLICATION_HOSTS=localhost,::1,127.0.0.1 + +# Application protocol (http or https) +APPLICATION_PROTOCOL=http + +# Time zone +TIME_ZONE=Europe/London + +# Minimum minutes spent in city for statistics +MIN_MINUTES_SPENT_IN_CITY=60 + +# Self-hosted flag (true for docker deployments) +SELF_HOSTED=true + +# Store geodata (reverse geocoding results) +STORE_GEODATA=true + +# ============================================================================= +# SECURITY +# ============================================================================= + +# Secret key base for production/staging +# Generate with: openssl rand -hex 64 +# Leave empty for development (will auto-generate) +SECRET_KEY_BASE= + +# ============================================================================= +# BACKGROUND JOBS +# ============================================================================= + +# Sidekiq concurrency (number of threads) +BACKGROUND_PROCESSING_CONCURRENCY=10 + +# ============================================================================= +# MONITORING & LOGGING +# ============================================================================= + +# Prometheus exporter settings +PROMETHEUS_EXPORTER_ENABLED=false +PROMETHEUS_EXPORTER_HOST=0.0.0.0 +PROMETHEUS_EXPORTER_PORT=9394 +PROMETHEUS_EXPORTER_HOST_SIDEKIQ=dawarich_app + +# Uncomment to expose Prometheus port +# PROMETHEUS_PORT=9394 + +# Rails logging +RAILS_LOG_TO_STDOUT=true + +# Docker logging settings +LOG_MAX_SIZE=100m +LOG_MAX_FILE=5 + +# ============================================================================= +# RESOURCE LIMITS +# ============================================================================= + +# CPU and memory limits for the app container +APP_CPU_LIMIT=0.50 +APP_MEMORY_LIMIT=4G + +# ============================================================================= +# EXAMPLE CONFIGURATIONS BY ENVIRONMENT +# ============================================================================= + +# --- DEVELOPMENT --- +# RAILS_ENV=development +# POSTGRES_DB=dawarich_development +# DATABASE_NAME=dawarich_development +# APPLICATION_HOSTS=localhost,::1,127.0.0.1 +# APPLICATION_PROTOCOL=http +# SECRET_KEY_BASE= +# SELF_HOSTED=true + +# --- STAGING --- +# RAILS_ENV=staging +# POSTGRES_DB=dawarich_staging +# DATABASE_NAME=dawarich_staging +# APPLICATION_HOSTS=staging.example.com +# APPLICATION_PROTOCOL=https +# SECRET_KEY_BASE=your-generated-secret-key +# SELF_HOSTED=true + +# --- PRODUCTION --- +# RAILS_ENV=production +# POSTGRES_DB=dawarich_production +# DATABASE_NAME=dawarich_production +# APPLICATION_HOSTS=dawarich.example.com,www.dawarich.example.com +# APPLICATION_PROTOCOL=https +# SECRET_KEY_BASE=your-generated-secret-key +# SELF_HOSTED=true +# PROMETHEUS_EXPORTER_ENABLED=true diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..774129a1 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,110 @@ +FROM ruby:3.4.6-slim + +ARG RAILS_ENV=production + +ENV APP_PATH=/var/app +ENV BUNDLE_VERSION=2.5.21 +ENV BUNDLE_PATH=/usr/local/bundle/gems +ENV RAILS_LOG_TO_STDOUT=true +ENV RAILS_PORT=3000 +ENV RAILS_ENV=${RAILS_ENV} + +# Development-specific environment variables +RUN if [ "$RAILS_ENV" = "development" ]; then \ + echo "export SELF_HOSTED=true" >> /etc/profile.d/rails.sh && \ + echo "export SIDEKIQ_USERNAME=sidekiq" >> /etc/profile.d/rails.sh && \ + echo "export SIDEKIQ_PASSWORD=password" >> /etc/profile.d/rails.sh && \ + echo "export PGSSENCMODE=disable" >> /etc/profile.d/rails.sh; \ + fi + +RUN apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + curl \ + wget \ + build-essential \ + git \ + postgresql-client \ + libpq-dev \ + libxml2-dev \ + libxslt-dev \ + libyaml-dev \ + libgeos-dev libgeos++-dev \ + imagemagick \ + tzdata \ + less \ + libjemalloc2 libjemalloc-dev \ + cmake \ + ca-certificates \ + && mkdir -p $APP_PATH \ + && rm -rf /var/lib/apt/lists/* + +# Install Node.js with architecture-specific logic for development +# For production/staging, use LTS version +RUN if [ "$RAILS_ENV" = "development" ]; then \ + ARCH=$(dpkg --print-architecture) && \ + if [ "$ARCH" = "amd64" ] || [ "$ARCH" = "arm64" ] || [ "$ARCH" = "armhf" ]; then \ + curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ + apt-get install -y nodejs; \ + else \ + apt-get update && \ + apt-get install -y nodejs npm; \ + fi; \ + else \ + curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ + apt-get install -y nodejs; \ + fi && \ + npm install -g yarn && \ + rm -rf /var/lib/apt/lists/* + +# Use jemalloc with check for architecture +RUN if [ "$(uname -m)" = "x86_64" ]; then \ + echo "/usr/lib/x86_64-linux-gnu/libjemalloc.so.2" > /etc/ld.so.preload; \ + else \ + echo "/usr/lib/aarch64-linux-gnu/libjemalloc.so.2" > /etc/ld.so.preload; \ + fi + +# Enable YJIT +ENV RUBY_YJIT_ENABLE=1 + +# Update RubyGems and install Bundler +RUN gem update --system 3.6.9 \ + && gem install bundler --version "$BUNDLE_VERSION" \ + && rm -rf $GEM_HOME/cache/* + +WORKDIR $APP_PATH + +COPY ../Gemfile ../Gemfile.lock ../.ruby-version ../vendor ./ + +# Install gems based on environment +RUN bundle config set --local path 'vendor/bundle' \ + && if [ "$RAILS_ENV" = "production" ] || [ "$RAILS_ENV" = "staging" ]; then \ + bundle config set --local without 'development test' && \ + bundle install --jobs 4 --retry 3; \ + else \ + bundle install --jobs 4 --retry 3; \ + fi \ + && rm -rf vendor/bundle/ruby/3.4.0/cache/*.gem + +COPY ../. ./ + +# Precompile assets for production/staging +RUN if [ "$RAILS_ENV" = "production" ] || [ "$RAILS_ENV" = "staging" ]; then \ + SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:precompile && \ + rm -rf node_modules tmp/cache; \ + fi + +# Create caching-dev.txt file for development +RUN if [ "$RAILS_ENV" = "development" ]; then \ + mkdir -p $APP_PATH/tmp && touch $APP_PATH/tmp/caching-dev.txt; \ + fi + +COPY ./docker/web-entrypoint.sh /usr/local/bin/web-entrypoint.sh +RUN chmod +x /usr/local/bin/web-entrypoint.sh + +COPY ./docker/sidekiq-entrypoint.sh /usr/local/bin/sidekiq-entrypoint.sh +RUN chmod +x /usr/local/bin/sidekiq-entrypoint.sh + +EXPOSE $RAILS_PORT + +ENTRYPOINT ["bundle", "exec"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index ca0fb27c..9154bff5 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,6 @@ networks: dawarich: + services: dawarich_redis: image: redis:7.4-alpine @@ -8,7 +9,7 @@ services: networks: - dawarich volumes: - - dawarich_shared:/data + - dawarich_redis_data:/data restart: always healthcheck: test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ] @@ -16,6 +17,7 @@ services: retries: 5 start_period: 30s timeout: 10s + dawarich_db: image: postgis/postgis:17-3.5-alpine shm_size: 1G @@ -27,17 +29,18 @@ services: networks: - dawarich environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_DB: dawarich_development + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} + POSTGRES_DB: ${POSTGRES_DB:-dawarich_development} restart: always healthcheck: - test: [ "CMD-SHELL", "pg_isready -U postgres -d dawarich_development" ] + test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-dawarich_development}" ] interval: 10s retries: 5 start_period: 30s timeout: 10s # command: postgres -c config_file=/etc/postgresql/postgresql.conf # Use custom config, uncomment if you want to use a custom config + dawarich_app: image: freikin/dawarich:latest container_name: dawarich_app @@ -49,34 +52,37 @@ services: networks: - dawarich ports: - - 3000:3000 - # - 9394:9394 # Prometheus exporter, uncomment if needed + - "${DAWARICH_APP_PORT:-3000}:3000" + # - "${PROMETHEUS_PORT:-9394}:9394" # Prometheus exporter, uncomment if needed stdin_open: true tty: true entrypoint: web-entrypoint.sh command: ['bin/rails', 'server', '-p', '3000', '-b', '::'] restart: on-failure environment: - RAILS_ENV: development - REDIS_URL: redis://dawarich_redis:6379 - DATABASE_HOST: dawarich_db - DATABASE_USERNAME: postgres - DATABASE_PASSWORD: password - DATABASE_NAME: dawarich_development - MIN_MINUTES_SPENT_IN_CITY: 60 - APPLICATION_HOSTS: localhost - TIME_ZONE: Europe/London - APPLICATION_PROTOCOL: http - PROMETHEUS_EXPORTER_ENABLED: "false" - PROMETHEUS_EXPORTER_HOST: 0.0.0.0 - PROMETHEUS_EXPORTER_PORT: 9394 - SELF_HOSTED: "true" - STORE_GEODATA: "true" + RAILS_ENV: ${RAILS_ENV:-development} + REDIS_URL: ${REDIS_URL:-redis://dawarich_redis:6379} + DATABASE_HOST: ${DATABASE_HOST:-dawarich_db} + DATABASE_PORT: ${DATABASE_PORT:-5432} + DATABASE_USERNAME: ${DATABASE_USERNAME:-postgres} + DATABASE_PASSWORD: ${DATABASE_PASSWORD:-password} + DATABASE_NAME: ${DATABASE_NAME:-dawarich_development} + MIN_MINUTES_SPENT_IN_CITY: ${MIN_MINUTES_SPENT_IN_CITY:-60} + APPLICATION_HOSTS: ${APPLICATION_HOSTS:-localhost,::1,127.0.0.1} + TIME_ZONE: ${TIME_ZONE:-Europe/London} + APPLICATION_PROTOCOL: ${APPLICATION_PROTOCOL:-http} + PROMETHEUS_EXPORTER_ENABLED: ${PROMETHEUS_EXPORTER_ENABLED:-false} + PROMETHEUS_EXPORTER_HOST: ${PROMETHEUS_EXPORTER_HOST:-0.0.0.0} + PROMETHEUS_EXPORTER_PORT: ${PROMETHEUS_EXPORTER_PORT:-9394} + SECRET_KEY_BASE: ${SECRET_KEY_BASE:-} + RAILS_LOG_TO_STDOUT: ${RAILS_LOG_TO_STDOUT:-true} + SELF_HOSTED: ${SELF_HOSTED:-true} + STORE_GEODATA: ${STORE_GEODATA:-true} logging: driver: "json-file" options: - max-size: "100m" - max-file: "5" + max-size: ${LOG_MAX_SIZE:-100m} + max-file: ${LOG_MAX_FILE:-5} healthcheck: test: [ "CMD-SHELL", "wget -qO - http://127.0.0.1:3000/api/v1/health | grep -q '\"status\"\\s*:\\s*\"ok\"'" ] interval: 10s @@ -93,8 +99,9 @@ services: deploy: resources: limits: - cpus: '0.50' # Limit CPU usage to 50% of one core - memory: '4G' # Limit memory usage to 4GB + cpus: ${APP_CPU_LIMIT:-0.50} + memory: ${APP_MEMORY_LIMIT:-4G} + dawarich_sidekiq: image: freikin/dawarich:latest container_name: dawarich_sidekiq @@ -110,25 +117,28 @@ services: command: ['sidekiq'] restart: on-failure environment: - RAILS_ENV: development - REDIS_URL: redis://dawarich_redis:6379 - DATABASE_HOST: dawarich_db - DATABASE_USERNAME: postgres - DATABASE_PASSWORD: password - DATABASE_NAME: dawarich_development - APPLICATION_HOSTS: localhost - BACKGROUND_PROCESSING_CONCURRENCY: 10 - APPLICATION_PROTOCOL: http - PROMETHEUS_EXPORTER_ENABLED: "false" - PROMETHEUS_EXPORTER_HOST: dawarich_app - PROMETHEUS_EXPORTER_PORT: 9394 - SELF_HOSTED: "true" - STORE_GEODATA: "true" + RAILS_ENV: ${RAILS_ENV:-development} + REDIS_URL: ${REDIS_URL:-redis://dawarich_redis:6379} + DATABASE_HOST: ${DATABASE_HOST:-dawarich_db} + DATABASE_PORT: ${DATABASE_PORT:-5432} + DATABASE_USERNAME: ${DATABASE_USERNAME:-postgres} + DATABASE_PASSWORD: ${DATABASE_PASSWORD:-password} + DATABASE_NAME: ${DATABASE_NAME:-dawarich_development} + APPLICATION_HOSTS: ${APPLICATION_HOSTS:-localhost,::1,127.0.0.1} + BACKGROUND_PROCESSING_CONCURRENCY: ${BACKGROUND_PROCESSING_CONCURRENCY:-10} + APPLICATION_PROTOCOL: ${APPLICATION_PROTOCOL:-http} + PROMETHEUS_EXPORTER_ENABLED: ${PROMETHEUS_EXPORTER_ENABLED:-false} + PROMETHEUS_EXPORTER_HOST: ${PROMETHEUS_EXPORTER_HOST_SIDEKIQ:-dawarich_app} + PROMETHEUS_EXPORTER_PORT: ${PROMETHEUS_EXPORTER_PORT:-9394} + SECRET_KEY_BASE: ${SECRET_KEY_BASE:-} + RAILS_LOG_TO_STDOUT: ${RAILS_LOG_TO_STDOUT:-true} + SELF_HOSTED: ${SELF_HOSTED:-true} + STORE_GEODATA: ${STORE_GEODATA:-true} logging: driver: "json-file" options: - max-size: "100m" - max-file: "5" + max-size: ${LOG_MAX_SIZE:-100m} + max-file: ${LOG_MAX_FILE:-5} healthcheck: test: [ "CMD-SHELL", "pgrep -f sidekiq" ] interval: 10s @@ -148,6 +158,7 @@ services: volumes: dawarich_db_data: + dawarich_redis_data: dawarich_shared: dawarich_public: dawarich_watched: