Why Backend Deployment is Different
Frontend
- Static files (HTML/CSS/JS)
- Just upload to a CDN
- No server process needed
Backend
- Requires a running server process
- Executes code for each request
- State management, DB connections
By packaging the backend into a container, it can run identically on any server.
Docker Basics
Writing a Dockerfile
# Use Python image
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Install dependencies first (leverage caching)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy source code
COPY . .
# Expose port
EXPOSE 8080
# Run the app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]Test Locally
# Build image
docker build -t my-api .
# Run container
docker run -p 8080:8080 my-api
# Check at http://localhost:8080Multi-stage Build (Optional)
Use multi-stage builds to reduce image size.
# Build stage
FROM python:3.11-slim as builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Runtime stage
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8080
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]Cloud Run Deployment
1 Install gcloud CLI
# macOS
brew install google-cloud-sdk
# Login
gcloud auth login
# Set project
gcloud config set project YOUR_PROJECT_ID2 Build and Push Image
# Build with Cloud Build + push to Artifact Registry
gcloud builds submit --tag gcr.io/YOUR_PROJECT_ID/my-api3 Deploy to Cloud Run
gcloud run deploy my-api \
--image gcr.io/YOUR_PROJECT_ID/my-api \
--platform managed \
--region asia-northeast3 \
--allow-unauthenticated --allow-unauthenticated: Allow access without authentication (for public APIs)
4 Set Environment Variables
gcloud run deploy my-api \
--image gcr.io/YOUR_PROJECT_ID/my-api \
--set-env-vars="DATABASE_URL=postgresql://...,API_KEY=secret"Secret Management
For sensitive information, use Secret Manager instead of environment variables.
Operations Basics
Health Check Endpoint
Cloud Run performs health checks on the / path.
It is best practice to create a dedicated health check endpoint.
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health_check():
return {"status": "healthy"}
@app.get("/")
def root():
return {"message": "Hello, World!"}Checking Logs
# View Cloud Run logs
gcloud run services logs read my-api --region asia-northeast3
# Stream logs in real-time
gcloud run services logs tail my-api --region asia-northeast3CORS Configuration
If your frontend and backend are on different domains, you need to configure CORS.
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["https://myapp.com", "http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)Next Steps
If backend deployment is complete, let's connect a database next. In Cycle 4: Database, you will learn how to connect PostgreSQL.