React, Django. Gunicorn, nginx, docker setup for production ready and not ablet to server static files for both frontend and backend

Это текущий директор моего проекта на данный момент

Project/
│── .env 
├── docker-compose.yml               # Docker Compose configuration file
│
├── Frontend/                   # React Frontend (Client-side)
│   ├── Dockerfile                   # Dockerfile for React app build
│   ├── package.json                 # React package file                     
│   ├── public/                      # Public assets for React
│   ├── src/                         # React source code
│   ├── build/                       # React build output (this is where `npm run build`                
│   ├── nginx.conf 
└── Backend/                    # Django Backend (Server-side)
    ├── Dockerfile                   # Dockerfile for Django app build
    ├── manage.py                    # Django manage.py file
    ├── Backend/                 # Django application code (models, views, etc.)
    ├── requirements.txt            
    ├── static/                       # Static files (collected by `collectstatic`)
    ├── media/                        # Media files (user-uploaded files)
    └── .dockerignore                 # Docker ignore file

У меня есть такая структура каталогов, где у меня есть 2 папки для backend и front end, в каждой из которых собраны Django и react соответственно, и у меня есть файл nginx в директории frontend, чтобы скопировать первую сборку в контейнер frontend, но дело в том, что я также разделяю тот же том с django, но nginx не ablet для сервера sttic файлов в django, а также получить 404 не найдена ошибка с nginx, поскольку файлы не в контейнерах, но они смонтированы с томами папки backend.

Ниже приведен yml-файл, который я использую, чтобы использовать общий том с бэкендом и сборку react

version: "3.8"

services:
  st_mysql_db:
    image: mysql:8.0
    container_name: st_mysql_db
    env_file:
      - .env
    environment:
      MYSQL_ROOT_PASSWORD: '${MYSQL_DB_ROOT_PASSWORD}'
      MYSQL_DATABASE: '${MYSQL_DATABASE_NAME}'
    volumes:
      - st_mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - st_network
    restart: always
    healthcheck:
      test: [
        "CMD", 
        "mysqladmin", "ping", 
        "-h", "localhost", 
        "-u", "root", 
        "-p${MYSQL_DB_ROOT_PASSWORD}", 
        "--silent"
      ]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 5s
    command: ["docker-entrypoint.sh", "mysqld"]

  st_backend:
    build:
      context: ./Backend
      dockerfile: Dockerfile
    container_name: st_backend
    volumes:
      - ./Backend:/app
      - ./Backend/media:/app/media
      - ./Backend/static:/app/static 
    env_file:
      - .env
    #environment:
      #- DATABASE_URL=mysql://root:${MYSQL_DB_ROOT_PASSWORD}@steno_mysql_db:3306/st_db
    ports:
      - "8000:8000"
    depends_on:
      - st_mysql_db
    networks:
      - st_network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/admin/"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 5s
    command: >
       bash -c "
          /wait-for-it.sh st_mysql_db:3306 --timeout=60 -- \
          
          # Run makemigrations for the accounts app first
          python manage.py makemigrations accounts && \
          
      
          # Run migrations for any other apps
          python manage.py migrate --noinput && \

          # Run migrations for any other apps
          python manage.py collectstatic --noinput && \
          
          # Start the gunicorn server
          gunicorn --bind 0.0.0.0:8000 Backend.wsgi:application"

    restart: always

  stfrontend:
    build:
      context: ./Frontend
      dockerfile: Dockerfile
    container_name: st_frontend
    env_file:
      - .env
    depends_on:
      - st_backend
      
    networks:
      - st_network
    volumes:
      - ./Backend/static:/usr/share/nginx/html/static  # Map Django static files to NGINX
      - ./Backend/media:/usr/share/nginx/html/media  # Map Django media files to NGINX
    
    restart: always
    ports:
      - "80:80"  # NGINX will serve frontend on port 80
    command: ["nginx", "-g", "daemon off;"]  # Directly run NGINX in the container


networks:
  st_network:
    driver: bridge

volumes:
  st_mysql_data:
  st_backend_data:

Это файл докера для фронтэнда и бэкэнда

frontend

# Stage 1: Build the React app
FROM node:14-slim AS builder

WORKDIR /app

# Copy package.json and package-lock.json
COPY package.json package-lock.json ./ 

# Install dependencies
RUN npm install

# Copy all files to the working directory
COPY . .

# Build the React app for production
RUN npm run build

# Stage 2: Serve the React app with NGINX
FROM nginx:alpine



# Copy custom NGINX configuration file from the parent directory
COPY ./nginx.conf /etc/nginx/nginx.conf 

# Copy the React build output to NGINX's HTML directory
COPY --from=builder /app/build /usr/share/nginx/html




# Set the correct permissions for NGINX to access files
RUN chown -R nginx:nginx /usr/share/nginx/html
RUN chmod -R 755 /usr/share/nginx/html


# Set the correct ownership for other NGINX critical files
RUN chown -R nginx:nginx /var/cache/nginx /var/log/nginx /etc/nginx/conf.d

# Ensure that NGINX serves the index.html file
# In the NGINX configuration file, the directory index needs to be set correctly.
# The default NGINX configuration should already include this, but we can enforce it.
RUN echo 'server { listen 80; location / { root /usr/share/nginx/html; index index.html index.htm; } }' > /etc/nginx/conf.d/default.conf

# Expose port 80
EXPOSE 80

это файл docker для backend

# Stage 1: Build stage using a full Python image
FROM python:3.9 as builder

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY requirements.txt ./ 

# Install dependencies and set up virtual environment
RUN apt-get update && apt-get install -y libmariadb-dev curl bash \
    && python -m venv /opt/venv \
    && /opt/venv/bin/pip install --no-cache-dir -r requirements.txt

# Stage 2: Final slim image
FROM python:3.9-slim

# Install dependencies needed for mysqlclient, bash, and curl
RUN apt-get update && apt-get install -y libmariadb-dev curl bash

# Set the working directory in the container
WORKDIR /app

# Copy the virtual environment from the builder stage
COPY --from=builder /opt/venv /opt/venv

# Copy the application code into the container
COPY . . 

# Download the wait-for-it.sh script directly from GitHub
RUN curl -sSL https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -o /wait-for-it.sh && chmod +x /wait-for-it.sh

# Ensure the PATH includes the virtual environment
ENV PATH="/opt/venv/bin:$PATH"


# Expose the application port (adjust as necessary)
EXPOSE 8000

# Command to run the server with wait-for-it.sh to ensure DB is ready
#CMD ["/wait-for-it.sh", "steno_mysql_db:3306", "--timeout=60", "--", "bash", "-c", "python manage.py makemigrations && python manage.py migrate && gunicorn --bind 0.0.0.0:8000 app.wsgi:application"]

и это конфигурация для nginx.conf

worker_processes 1;

events {
    worker_connections 1024;
}

# Main NGINX configuration block
http {
    # Include any additional configurations (if needed)
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # Log configuration
   access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;
    

    # Server block for handling HTTP requests
    server {
        listen 80;
        server_name localhost;  # This will match any domain, acting as a catch-all

        # These directives should be outside the location block
            root /usr/share/nginx/html;  # Define the root directory for all requests
            index index.html;  

        # Frontend
        location / {
        
            try_files $uri /index.html;   # Rewrites any missing route to index.html
        }


        location /static/ {
        alias /usr/share/nginx/html/static/;

       
        autoindex on;
        }

        # Serve media files for Django (if you use them)
        location /media/ {
            alias /usr/share/nginx/html/media/;  # Serve media files from shared volume
            autoindex on;
        }


        # Backend API
        location /api/ {
            proxy_pass http://steno_backend:8000/;  # Proxy to Django backend
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        # Serve static files for Django from the shared volume
    
    }
}

вот мой файл настроек для медиа и статики, когда отладка равна False

STATIC_URL = 'static/'
STATIC_ROOT=os.path.join(BASE_DIR,'static')

# Media files (uploads)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

При такой конфигурации я хочу сделать то, что когда я делаю сбор статического в контейнере backend, то файлы хранятся в каталоге, но так как объем общий, то nginx не может обслуживать эти файлы, а также не может обслуживать даже файлы react, которые находятся в папке html nginx. и еще одна вещь, когда я делаю миграцию и миграцию, я использую модель customuser и я добавил ссылку в файл настроек, но когда я напрямую использую

python manage.py make migrations

он показывает, что все в порядке, а затем мигрировать он показывает не в состоянии ссылаться на вещи, так что это идет не так, так что из-за этого я должен сделать отдельные миграции для учетных записей, а затем мигрировать, чтобы применить все другие миграции. как я могу решить эту проблему, когда я должен использовать R2 Service от Cloudflare и rds от aws так что, пожалуйста, помогите мне с этим .

Если вы обнаружите какую-либо проблему с yml или любой конфигурацией, пожалуйста, укажите на нее для лучшего использования, а также предложите готовую к производству установку для вышеуказанных конфигураций.

Вернуться на верх