Deploying a FastAPI + React Application with Docker

Deploying a web application using FastAPI (backend) and React (frontend) with Docker is an effective way to ensure consistency across different environments. Below, you'll find a detailed guide outlining the best practices and step-by-step instructions to help you deploy your application to a server using Docker.

Table of Contents

  1. Prerequisites
  2. Project Structure
  3. Setting Up the FastAPI Backend
  4. Setting Up the React Frontend
  5. Creating Dockerfiles
  6. Docker Compose Configuration
  7. Environment Variables and Configuration
  8. Building and Running with Docker Compose
  9. Deploying to a Server
  10. Additional Best Practices
  11. Conclusion

Prerequisites

Before proceeding, ensure you have the following installed on your local machine:

  • Docker: Install Docker
  • Docker Compose: Comes bundled with Docker Desktop for Windows and macOS. For Linux, install Docker Compose.
  • Git: For version control. Install Git
  • Basic Knowledge: Familiarity with Python, JavaScript, FastAPI, React, and command-line interfaces.

Project Structure

Organizing your project systematically will simplify development and deployment. Here's a recommended structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
my-web-app/
├── backend/
│ ├── app/
│ │ ├── main.py
│ │ └── ... (other FastAPI modules)
│ ├── requirements.txt
│ └── Dockerfile
├── frontend/
│ ├── public/
│ ├── src/
│ │ └── ... (React components)
│ ├── package.json
│ └── Dockerfile
├── docker-compose.yml
└── README.md

Setting Up the FastAPI Backend

  1. Initialize FastAPI Project

    Navigate to the backend directory and create a virtual environment:

    1
    2
    3
    cd my-web-app/backend
    python -m venv venv
    source venv/bin/activate # On Windows: venv\Scripts\activate
  2. Install Dependencies

    Install FastAPI and Uvicorn:

    1
    pip install fastapi uvicorn
  3. Create main.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # backend/app/main.py

    from fastapi import FastAPI

    app = FastAPI()

    @app.get("/")
    def read_root():
    return {"message": "Hello from FastAPI"}
  4. Freeze Requirements

    1
    pip freeze > requirements.txt

Setting Up the React Frontend

  1. Initialize React Project

    Navigate to the frontend directory and create a new React app using create-react-app:

    1
    2
    cd ../frontend
    npx create-react-app .
  2. Modify App.js

    Update the default App.js to fetch data from FastAPI:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // frontend/src/App.js

    import React, { useEffect, useState } from 'react';

    function App() {
    const [message, setMessage] = useState('');

    useEffect(() => {
    fetch('http://localhost:8000/')
    .then(response => response.json())
    .then(data => setMessage(data.message));
    }, []);

    return (
    <div className="App">
    <h1>{message}</h1>
    </div>
    );
    }

    export default App;
  3. Install Dependencies

    If you plan to use additional libraries, install them using npm or yarn.


Creating Dockerfiles

Backend Dockerfile

Create a Dockerfile in the backend directory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# backend/Dockerfile

# Use an official Python runtime as a parent image
FROM python:3.11-slim

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Set work directory
WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --upgrade pip
RUN pip install -r requirements.txt

# Copy project
COPY . .

# Expose port
EXPOSE 8000

# Run the application
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Frontend Dockerfile

Create a Dockerfile in the frontend directory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# frontend/Dockerfile

# Stage 1: Build the React app
FROM node:18-alpine as build

# Set working directory
WORKDIR /app

# Install dependencies
COPY package.json package-lock.json ./
RUN npm install

# Copy source code
COPY . .

# Build the app
RUN npm run build

# Stage 2: Serve the React app with Nginx
FROM nginx:stable-alpine

# Copy the build output to Nginx's html directory
COPY --from=build /app/build /usr/share/nginx/html

# Expose port
EXPOSE 80

# Start Nginx
CMD ["nginx", "-g", "daemon off;"]

Docker Compose Configuration

To manage both frontend and backend containers, use Docker Compose.

Create a docker-compose.yml in the root of your project:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# docker-compose.yml

version: '3.8'

services:
backend:
build:
context: ./backend
container_name: fastapi-backend
ports:
- "8000:8000"
volumes:
- ./backend/app:/app/app
environment:
- PYTHONUNBUFFERED=1

frontend:
build:
context: ./frontend
container_name: react-frontend
ports:
- "3000:80"
depends_on:
- backend

Environment Variables and Configuration

Managing environment variables is crucial for different environments (development, production).

  1. Backend Environment Variables

    Create a .env file in the backend directory:

    1
    2
    3
    4
    # backend/.env

    DATABASE_URL=sqlite:///./test.db
    SECRET_KEY=your-secret-key

    Update the backend Dockerfile to copy the .env file:

    1
    2
    3
    # backend/Dockerfile (add the following line before CMD)

    COPY .env .
  2. Frontend Configuration

    React uses environment variables prefixed with REACT_APP_.

    Create a .env file in the frontend directory:

    1
    2
    3
    # frontend/.env

    REACT_APP_API_URL=http://localhost:8000/

    Update API calls in React to use this variable:

    1
    2
    3
    4
    5
    6
    7
    // frontend/src/App.js

    useEffect(() => {
    fetch(process.env.REACT_APP_API_URL)
    .then(response => response.json())
    .then(data => setMessage(data.message));
    }, []);

Building and Running with Docker Compose

  1. Build the Containers

    From the root directory (my-web-app/), run:

    1
    docker-compose build
  2. Run the Containers

    1
    docker-compose up
  3. Access the Application

  4. Stopping the Application

    Press CTRL+C in the terminal where Docker Compose is running, then:

    1
    docker-compose down

Deploying to a Server

Once your application works locally with Docker, you can deploy it to a production server. Here's how:

Choosing a Hosting Provider

Popular options include:

  • AWS EC2
  • DigitalOcean Droplets
  • Google Cloud Compute Engine
  • Azure Virtual Machines
  • Heroku (supports Docker deployments)

For this guide, we'll use DigitalOcean Droplets as an example.

Setting Up the Server

  1. Create a Droplet

    • Sign up or log in to DigitalOcean.
    • Create a new Droplet with your preferred OS (e.g., Ubuntu 22.04).
    • Ensure you select Docker when choosing the image or install it manually later.
  2. Access the Server

    Use SSH to connect:

    1
    ssh root@your_server_ip
  3. Install Docker and Docker Compose (if not pre-installed)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # Update packages
    sudo apt-get update

    # Install Docker
    sudo apt-get install -y docker.io

    # Start and enable Docker
    sudo systemctl start docker
    sudo systemctl enable docker

    # Install Docker Compose
    sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose

    # Verify installation
    docker-compose --version

Transferring Your Application

  1. Clone Your Repository

    On the server, install Git and clone your project:

    1
    2
    3
    sudo apt-get install -y git
    git clone https://github.com/yourusername/my-web-app.git
    cd my-web-app

    Replace the URL with your repository's URL.

  2. Set Up Environment Variables

    Ensure .env files are set up correctly on the server. You might need to create them manually or use secrets management.

  3. Build and Run with Docker Compose

    1
    2
    sudo docker-compose build
    sudo docker-compose up -d
  4. Configure Firewall

    Allow necessary ports (e.g., 80, 443):

    1
    2
    3
    4
    sudo ufw allow OpenSSH
    sudo ufw allow 80
    sudo ufw allow 443
    sudo ufw enable
  5. Set Up a Reverse Proxy (Optional but Recommended)

    Using Nginx as a reverse proxy can help manage traffic and SSL.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    sudo apt-get install -y nginx

    # Create Nginx configuration
    sudo nano /etc/nginx/sites-available/my-web-app

    # Add the following configuration
    server {
    listen 80;
    server_name your_domain.com;

    location /api/ {
    proxy_pass http://localhost:8000/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
    proxy_pass http://localhost:3000/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    }
    }

    # Enable the configuration
    sudo ln -s /etc/nginx/sites-available/my-web-app /etc/nginx/sites-enabled/

    # Test and reload Nginx
    sudo nginx -t
    sudo systemctl reload nginx
  6. Secure Your Application with SSL

    Use Let's Encrypt for free SSL certificates.

    1
    2
    sudo apt-get install -y certbot python3-certbot-nginx
    sudo certbot --nginx -d your_domain.com

    Follow the prompts to complete SSL setup.


Additional Best Practices

Security Considerations

  • Keep Dependencies Updated: Regularly update your dependencies to patch vulnerabilities.

  • Use Environment Variables: Never hardcode sensitive information. Use environment variables or secret managers.

  • Limit Access: Use firewalls to restrict access to essential ports only.

  • Use Non-Root Users in Containers: Modify Dockerfiles to run applications with non-root users.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Example addition to Dockerfile

    # Add a user
    RUN addgroup --system appgroup && adduser --system appuser --ingroup appgroup

    # Set ownership
    RUN chown -R appuser:appgroup /app

    # Switch to the user
    USER appuser

Optimizing Docker Images

  • Use Multi-Stage Builds: As shown in the frontend Dockerfile, use multi-stage builds to reduce image size.
  • Leverage Caching: Order Dockerfile instructions to maximize cache efficiency.
  • Minimize Layers: Combine commands where possible to reduce the number of layers.

Logging and Monitoring

  • Centralized Logging: Use tools like ELK Stack (Elasticsearch, Logstash, Kibana) or cloud services.
  • Monitoring Tools: Implement monitoring with Prometheus, Grafana, or similar tools to track application performance and uptime.

Conclusion

Deploying a FastAPI and React application using Docker ensures a scalable and maintainable setup across different environments. By following the best practices outlined above—such as proper project structuring, using Docker Compose, managing environment variables securely, and implementing security measures—you can efficiently deploy and manage your web application on a server.

Remember to continuously monitor your application's performance and security, and keep your Docker images and dependencies up to date. Happy coding!


Deploying a FastAPI + React Application with Docker
https://asdfffy.top/posts/5d85a866/
作者
asdfffy
发布于
2024年11月1日
许可协议