-
Notifications
You must be signed in to change notification settings - Fork 12
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 all 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,32 @@ | ||
| __pycache__ | ||
| *.pyc | ||
| *.pyo | ||
| *.pyd | ||
| .Python | ||
| env/ | ||
| venv/ | ||
| .venv/ | ||
| pip-log.txt | ||
| pip-delete-this-directory.txt | ||
| .tox/ | ||
| .coverage | ||
| .coverage.* | ||
| .cache | ||
| nosetests.xml | ||
| coverage.xml | ||
| *.cover | ||
| *.log | ||
| .git | ||
| .mypy_cache | ||
| .pytest_cache | ||
| .hypothes | ||
| .DS_Store | ||
| .env | ||
| .env.* | ||
| !.env.example | ||
|
|
||
| # Web artifacts (not needed for backend build context, though we use specific COPY) | ||
| web/node_modules/ | ||
| web/dist/ | ||
| web/.next/ | ||
| web/coverage/ |
| 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,62 @@ | ||
| # Base image | ||
| FROM python:3.11.8-slim-bookworm | ||
|
|
||
| # Install system dependencies | ||
| RUN apt-get update && apt-get install -y \ | ||
| curl \ | ||
| unzip \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Create a non-root user | ||
| RUN groupadd -r appuser && useradd -r -g appuser appuser | ||
|
|
||
| # Install uv | ||
| COPY --from=ghcr.io/astral-sh/uv:0.5.29 /uv /bin/uv | ||
|
|
||
| # Install Deno | ||
| # We install Deno to a global location or user's home | ||
| ENV DENO_INSTALL="/usr/local" | ||
| ENV DENO_VERSION="v1.40.3" | ||
| # Install deno manually to /usr/local/bin so it's accessible to all users | ||
| RUN curl -fsSL https://deno.land/x/install/install.sh | sh -s ${DENO_VERSION} | ||
|
|
||
| # Set working directory | ||
| WORKDIR /app | ||
|
|
||
| # Copy dependency definition only to leverage cache | ||
| COPY pyproject.toml README.md ./ | ||
|
|
||
| # Compile and install dependencies | ||
| # We install to system python which is fine in docker, but we need to ensure permissions if we were to install more later. | ||
| # However, system install requires root. We do this BEFORE switching user. | ||
| RUN uv pip compile pyproject.toml -o requirements.txt && \ | ||
| uv pip install --system -r requirements.txt | ||
|
|
||
| # Copy source code | ||
| COPY cr/ ./cr/ | ||
| COPY cli/ ./cli/ | ||
|
|
||
| # Install the project itself | ||
| RUN uv pip install --system --no-deps . | ||
|
|
||
| # Cache Deno dependencies | ||
| # We need to run this as the user who will run the app, OR ensure the cache is accessible. | ||
| # If we run as appuser, Deno will cache to $HOME/.cache/deno | ||
| # So we should switch user first. | ||
|
|
||
| # Change ownership of the app directory | ||
| RUN chown -R appuser:appuser /app | ||
|
|
||
| # Switch to non-root user | ||
| USER appuser | ||
|
|
||
| # Cache Deno dependencies (will be stored in /home/appuser/.cache/deno or similar) | ||
| # We need to ensure appuser has a home directory or set DENO_DIR | ||
| ENV DENO_DIR="/app/.deno_cache" | ||
| 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"] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| services: | ||
| backend: | ||
| # Run as root in development to avoid permission issues with bind mounts | ||
| user: root | ||
| 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: | ||
| # Run as root in development to ensure node_modules write access and hot reloading | ||
| user: root | ||
| 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:8080" | ||
| 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,13 @@ | ||
| node_modules | ||
| dist | ||
| .env | ||
| .env.* | ||
| !.env.example | ||
| .git | ||
| .DS_Store | ||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* | ||
| .idea | ||
| .vscode | ||
| coverage |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # 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 build artifacts | ||
| COPY --from=build /app/dist /usr/share/nginx/html | ||
|
|
||
| # Copy custom nginx config | ||
| COPY nginx.conf /etc/nginx/conf.d/default.conf | ||
|
|
||
| # Configure permissions for non-root user | ||
| # Nginx alpine image uses 'nginx' user (uid 101) | ||
| # We need to ensure it can write to cache/pid directories if they are used, | ||
| # though with standard config it might write to /var/run which is root owned. | ||
| # More commonly we just need to ensure it can read the static files (which it can) | ||
| # and bind to the port (which is now 8080). | ||
|
|
||
| # Update nginx.conf to use /tmp for pid/cache if strictly necessary, | ||
| # but usually just changing the port is enough for the main process | ||
| # if we don't need to write to system paths. | ||
| # However, standard nginx image tries to write to /var/cache/nginx and /var/run/nginx.pid | ||
| RUN chown -R nginx:nginx /var/cache/nginx && \ | ||
| chown -R nginx:nginx /var/log/nginx && \ | ||
| chown -R nginx:nginx /etc/nginx/conf.d && \ | ||
| touch /var/run/nginx.pid && \ | ||
| chown -R nginx:nginx /var/run/nginx.pid | ||
|
|
||
| # Switch to non-root user | ||
| USER nginx | ||
|
|
||
| EXPOSE 8080 | ||
| CMD ["nginx", "-g", "daemon off;"] |
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.
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
USERinstruction.