diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5874dee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +FROM node:18-bullseye-slim as frontend + +WORKDIR /frontend/ +COPY frontend/package.json frontend/package-lock.json /frontend/ +RUN npm install + +COPY frontend /frontend/ +RUN npm run build + +FROM python:3.10.1-slim-bullseye +RUN apt-get update && apt install dumb-init +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +EXPOSE 8080 +RUN mkdir -p /app +WORKDIR /app + +COPY hypercorn.toml /app/ +CMD ["pdm", "run", "hypercorn", "--config", "hypercorn.toml", "backend.run:app"] + +RUN python -m venv /ve +ENV PATH=/ve/bin:${PATH} +RUN pip install --no-cache-dir pdm + +COPY backend/pdm.lock backend/pyproject.toml /app/ +RUN pdm install --prod --no-lock --no-editable + +COPY --from=frontend /frontend/build/*.js* /app/backend/static/ +COPY --from=frontend /frontend/build/*.png /frontend/build/*.svg /app/backend/static/ +COPY --from=frontend /frontend/build/index.html \ + /app/backend/templates/ +COPY --from=frontend /frontend/build/static/. /app/backend/static/ + +COPY backend/src/ /app/ + +USER nobody diff --git a/README.md b/README.md index b529c36..dc0bb82 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Todo API +## To run + +`docker-compose up -d` + ## Frontend ### Development Workflow diff --git a/backend/src/backend/blueprints/serving.py b/backend/src/backend/blueprints/serving.py new file mode 100644 index 0000000..bc805f1 --- /dev/null +++ b/backend/src/backend/blueprints/serving.py @@ -0,0 +1,12 @@ +from quart import Blueprint, render_template, ResponseReturnValue +from quart_rate_limiter import rate_exempt + + +blueprint = Blueprint("serving", __name__) + + +@blueprint.get("/") +@blueprint.get("/") +@rate_exempt +async def index(path: str | None = None) -> ResponseReturnValue: + return await render_template("index.html") diff --git a/backend/src/backend/run.py b/backend/src/backend/run.py index 7b8fd22..493449b 100644 --- a/backend/src/backend/run.py +++ b/backend/src/backend/run.py @@ -23,6 +23,7 @@ from backend.blueprints.control import blueprint as control_blueprint from backend.blueprints.members import blueprint as members_blueprint from backend.blueprints.sessions import blueprint as sessions_blueprint from backend.blueprints.todos import blueprint as todos_blueprint +from backend.blueprints.serving import blueprint as serving_blueprint # For making sure error responses are in JSON format from backend.lib.api_error import APIError @@ -48,6 +49,7 @@ app.register_blueprint(control_blueprint) app.register_blueprint(sessions_blueprint) app.register_blueprint(members_blueprint) app.register_blueprint(todos_blueprint) +app.register_blueprint(serving_blueprint) # Rate limiting diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..e040496 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,38 @@ +version: "3" +services: + web-service: + build: + context: . + dockerfile: ./Dockerfile + ports: + - "8080:8080" + depends_on: + postgres: + condition: service_healthy + networks: + - my_network + environment: + TODO_SECRET_KEY: "secret key" + TODO_QUART_DB_DATABASE_URL: postgres://postgres:postgres_password@postgres:5432/todo + TODO_QUART_DB_DATA_PATH: migrations/data.py + + postgres: + image: postgres:16-alpine + environment: + POSTGRES_PASSWORD: postgres_password + POSTGRES_DB: todo + POSTGRES_USER: postgres + networks: + - my_network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 30s + timeout: 10s + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: + +networks: + my_network: diff --git a/hypercorn.toml b/hypercorn.toml new file mode 100644 index 0000000..7e45fbc --- /dev/null +++ b/hypercorn.toml @@ -0,0 +1,4 @@ +accesslog = "-" +access_log_format = "%(t)s %(h)s %(f)s - %(S)s '%(r)s' %(s)s %(b)s %(D)s" +bind = "0.0.0.0:8080" +errorlog = "-"