-
Notifications
You must be signed in to change notification settings - Fork 41
Docker support #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
63c5774
0d71ba1
45e225a
529cc78
33c29d8
c832928
46ed5c3
172e619
888488c
50fe29d
87854c1
a63f886
f848bbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # Docker Setup for AsyncReview | ||
|
|
||
| This guide explains how to run AsyncReview using Docker, both for production (immutable usage) and local development. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - **Docker** and **Docker Compose** installed on your machine. | ||
| - A `.env` file with your API keys (see [README.md](README.md) or copy `.env.example`). | ||
|
|
||
| **Note:** You *must* create a `.env` file before running any Docker commands. | ||
| ```bash | ||
| cp .env.example .env | ||
| # Edit .env and add your GEMINI_API_KEY | ||
| ``` | ||
|
|
||
| ## Quick Start (Production/User Mode) | ||
|
|
||
| To run the application in a stable, immutable container environment using the convenience Makefile command: | ||
|
|
||
| ```bash | ||
| make docker-up | ||
| ``` | ||
|
|
||
| Alternatively, using Docker Compose directly: | ||
| ```bash | ||
| docker compose up --build | ||
| ``` | ||
|
|
||
| - **Web UI:** http://localhost:3000 | ||
| - **API:** Proxied via the Web UI at http://localhost:3000/api | ||
| - Note: The backend service is not directly exposed to the host in production mode. | ||
|
|
||
| To stop the application: | ||
| ```bash | ||
| docker compose down | ||
| ``` | ||
|
|
||
| ## Local Development | ||
|
|
||
| To run the application in development mode with hot-reloading (changes to your code are immediately reflected): | ||
|
|
||
| ```bash | ||
| make docker-dev | ||
| ``` | ||
|
|
||
| Alternatively, using Docker Compose directly (requires both files): | ||
| ```bash | ||
| docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build | ||
| ``` | ||
|
|
||
| - **Web UI:** http://localhost:5173 (Vite dev server) | ||
| - **API:** http://localhost:8000 (Direct access for debugging) | ||
|
|
||
| *Note: In development mode, the `web/` directory and the root directory are mounted into the containers. Changes you make locally will trigger reloads.* | ||
|
|
||
| ## Running CLI Commands | ||
|
|
||
| You can run the `cr` CLI tool inside the backend container. | ||
|
|
||
| **In Production Mode:** | ||
| ```bash | ||
| docker compose run --rm backend cr --help | ||
| docker compose run --rm backend cr review --url https://github.com/org/repo/pull/123 | ||
| ``` | ||
|
|
||
| **In Development Mode:** | ||
| ```bash | ||
| docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm backend cr --help | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Port Conflicts | ||
| If port 3000, 8000, or 5173 are in use, you can modify the ports in `docker-compose.yml` or `docker-compose.dev.yml`. | ||
|
|
||
| ### Deno/Pyodide Issues | ||
| The backend container installs Deno and caches the Pyodide environment during the build. If you encounter issues, try rebuilding: | ||
| ```bash | ||
| docker compose build --no-cache backend | ||
| ``` | ||
|
|
||
| ### Dependencies | ||
| If you add new Python dependencies to `pyproject.toml`, you must rebuild the backend container: | ||
| ```bash | ||
| docker compose build backend | ||
| ``` | ||
| In development mode, since the source is mounted but dependencies are installed in the system python path, a rebuild is usually required to install new dependencies. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Base image | ||
| FROM python:3.11-slim | ||
|
|
||
| # Install system dependencies | ||
| RUN apt-get update && apt-get install -y \ | ||
| curl \ | ||
| unzip \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Install uv | ||
| # explicit path to ensure it's available | ||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv | ||
|
|
||
| # Install Deno | ||
| ENV DENO_INSTALL="/root/.deno" | ||
| RUN curl -fsSL https://deno.land/install.sh | sh | ||
|
ngoyal16 marked this conversation as resolved.
Outdated
|
||
| ENV PATH="$DENO_INSTALL/bin:$PATH" | ||
|
|
||
| # Set working directory | ||
| WORKDIR /app | ||
|
|
||
| # Copy project files | ||
| COPY pyproject.toml README.md ./ | ||
| COPY cr/ ./cr/ | ||
| COPY cli/ ./cli/ | ||
|
|
||
| # Install python dependencies | ||
| # We use --system to install into the container's system python environment | ||
| RUN uv pip install --system . | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To improve Docker build performance and leverage layer caching, it's recommended to copy dependency files and install dependencies in a separate layer before copying the application source code. The current setup copies all source code before installing dependencies, which invalidates the cache on any file change, forcing a re-installation of all dependencies. A better structure would be: # Copy dependency manifest
COPY pyproject.toml ./
# Install dependencies
RUN uv pip install ... # Command to install from pyproject.toml
# Copy source code
COPY . .The |
||
|
|
||
| # Cache Deno dependencies | ||
| RUN deno cache npm:pyodide/pyodide.js | ||
|
|
||
| # Expose port | ||
| EXPOSE 8000 | ||
|
|
||
| # Default command | ||
| CMD ["uvicorn", "cr.server:app", "--host", "0.0.0.0", "--port", "8000"] | ||
|
Comment on lines
+61
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The backend container runs as the root user by default. This violates the principle of least privilege and increases the security risk; if the application is compromised, the attacker would have full root access within the container. It is recommended to create a non-root user and switch to it using the |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| services: | ||
| backend: | ||
| volumes: | ||
| - ./:/app | ||
| # Use anonymous volumes to prevent host directories from overwriting container directories | ||
| - /app/.venv | ||
| - /app/.deno | ||
| command: uvicorn cr.server:app --reload --host 0.0.0.0 --port 8000 | ||
| ports: | ||
| - "8000:8000" | ||
| environment: | ||
| - WATCHFILES_FORCE_POLLING=true | ||
|
|
||
| frontend: | ||
| build: | ||
| target: dev | ||
| volumes: | ||
| - ./web:/app | ||
| - /app/node_modules | ||
| ports: | ||
| - "5173:5173" | ||
| environment: | ||
| - API_URL=http://backend:8000 | ||
| command: npm run dev -- --host |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| services: | ||
| backend: | ||
| build: | ||
| context: . | ||
| dockerfile: Dockerfile.backend | ||
| env_file: | ||
| - .env | ||
| environment: | ||
| - PYTHONUNBUFFERED=1 | ||
| restart: unless-stopped | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make your service orchestration more robust, consider adding a restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s |
||
|
|
||
| frontend: | ||
| build: | ||
| context: ./web | ||
| dockerfile: Dockerfile | ||
| target: prod | ||
| ports: | ||
| - "3000:80" | ||
|
ngoyal16 marked this conversation as resolved.
Outdated
|
||
| depends_on: | ||
| - backend | ||
|
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| restart: unless-stopped | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Base stage | ||
| FROM node:20-alpine AS base | ||
| WORKDIR /app | ||
| COPY package*.json ./ | ||
| RUN npm ci | ||
|
|
||
| # Development stage | ||
| FROM base AS dev | ||
| # Expose default Vite port | ||
| EXPOSE 5173 | ||
| # Command to run dev server, binding to all interfaces | ||
| CMD ["npm", "run", "dev", "--", "--host"] | ||
|
|
||
| # Build stage | ||
| FROM base AS build | ||
| COPY . . | ||
| RUN npm run build | ||
|
|
||
| # Production stage | ||
| FROM nginx:alpine AS prod | ||
| COPY --from=build /app/dist /usr/share/nginx/html | ||
| # We will copy a custom nginx config to handle SPA routing and API proxying | ||
| COPY nginx.conf /etc/nginx/conf.d/default.conf | ||
| EXPOSE 80 | ||
| CMD ["nginx", "-g", "daemon off;"] | ||
|
Comment on lines
+20
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| server { | ||
| listen 80; | ||
| server_name localhost; | ||
|
|
||
| location / { | ||
| root /usr/share/nginx/html; | ||
| index index.html index.htm; | ||
| # Support SPA routing (redirect to index.html for non-existent files) | ||
| try_files $uri $uri/ /index.html; | ||
| } | ||
|
|
||
| # Proxy API requests to the backend service | ||
| location /api/ { | ||
| proxy_pass http://backend:8000/api/; | ||
| 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; | ||
|
|
||
| # Support SSE (Server Sent Events) | ||
| proxy_buffering off; | ||
| proxy_cache off; | ||
| proxy_set_header Connection ''; | ||
| proxy_http_version 1.1; | ||
| chunked_transfer_encoding off; | ||
| } | ||
|
|
||
| # Health check | ||
| location /health { | ||
| proxy_pass http://backend:8000/health; | ||
| } | ||
|
|
||
| # Docs | ||
| location /docs { | ||
| proxy_pass http://backend:8000/docs; | ||
| } | ||
| location /openapi.json { | ||
| proxy_pass http://backend:8000/openapi.json; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reproducible builds, it's a best practice to pin dependencies to a specific version instead of using the
:latesttag. This prevents unexpected build failures if a breaking change is introduced in a new version of the tool.