diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6347c08 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +.git +.gitignore +__pycache__/ +*.pyc +*.pyo +*.pyd +.build/ +dist/ +.wheels/ +.cache/ +.env +*.log +.mypy_cache/ +.pytest_cache/ +.vscode/ +.idea/ diff --git a/.env.example b/.env.example index f139386..9606e56 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,6 @@ # Docker Image Settings IMAGE_NAME=uigf-api CONTAINER_NAME=UIGF-API -IMAGE_TAG=2.0 -EXTERNAL_PORT=3052 # App Settings TOKEN=AppToken diff --git a/Dockerfile b/Dockerfile index dc71b68..1b9f8c1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,44 @@ -#!/bin/sh -# Build Stage +# syntax=docker/dockerfile:1.6 + +# Build stage FROM python:3.12 AS builder WORKDIR /code -ADD . /code -RUN pip install "fastapi[standard]" -RUN pip install redis -RUN pip install sqlalchemy -RUN pip install pymysql -RUN pip install "sentry-sdk[fastapi]" -RUN pip install cryptography -RUN pip install pyinstaller -RUN pyinstaller -F main.py - -# Runtime + +# Use --mount=type=cache to cache pip downloads between builds +COPY requirements.txt /code/requirements.txt +COPY requirements.build.txt /code/requirements.build.txt +RUN --mount=type=cache,target=/root/.cache/pip,id=pip-cache \ + python -m pip install --upgrade pip wheel \ + && pip wheel -r requirements.txt -w /wheels \ + && pip wheel -r requirements.build.txt -w /wheels + +# Copy source code +COPY . /code + +# Install dependencies from wheels cache (offline installation) +RUN --mount=type=cache,target=/root/.cache/pip,id=pip-cache \ + pip install --no-index --find-links=/wheels -r requirements.txt \ + && pip install --no-index --find-links=/wheels -r requirements.build.txt + +# Run PyInstaller to create a single executable +RUN --mount=type=cache,target=/root/.cache/pip,id=pip-cache \ + pyinstaller -F main.py + + +# Runtime stage FROM ubuntu:24.04 AS runtime WORKDIR /app -COPY --from=builder /code/dist/main . -EXPOSE 8000 -ENTRYPOINT ["./main"] + +# Install runner dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Copy the built executable from the builder stage +COPY --from=builder /code/dist/main /app/main + +# Health check +# HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ +# CMD curl -fsS http://localhost:8080/health || exit 1 + +ENTRYPOINT ["/app/main"] diff --git a/docker-compose.yml b/docker-compose.yml index a800c67..6e25100 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,14 +6,12 @@ services: context: . dockerfile: Dockerfile target: runtime - image: ${IMAGE_NAME}:${IMAGE_TAG} + image: ${IMAGE_NAME}:latest container_name: ${CONTAINER_NAME}-Server - ports: - - "${EXTERNAL_PORT}:8080" volumes: - ./cache:/app/cache - ./dict:/app/dict - - ./.env:/app/.env + - ./.env:/app/.env:ro restart: unless-stopped depends_on: - tunnel @@ -33,4 +31,4 @@ services: restart: unless-stopped command: tunnel --no-autoupdate run environment: - - TUNNEL_TOKEN=${TUNNEL_TOKEN} \ No newline at end of file + - TUNNEL_TOKEN=${TUNNEL_TOKEN} diff --git a/requirements.build.txt b/requirements.build.txt new file mode 100644 index 0000000..4be7835 --- /dev/null +++ b/requirements.build.txt @@ -0,0 +1,3 @@ +pyinstaller==6.10.0 +# setuptools is pinned below version 81 due to incompatibility with PyInstaller; see https://github.com/pyinstaller/pyinstaller/issues/7994 +setuptools<81