From 25edcd8ac4633ecd3cc5a956a44883a424e61500 Mon Sep 17 00:00:00 2001 From: T31M Date: Sun, 6 Aug 2023 21:02:23 +0200 Subject: [PATCH] feat: Add FastAPI s6 sidecar PoC - Sidecar DragonflyDB as Redis replacement - Run pytheus in multiprocessing mode with Redis backend --- .gitignore | 3 +++ Dockerfile | 38 ++++++++++++++++++++++++++++++++++++++ README.md | 13 +++++++++++++ app/__init__.py | 0 app/main.py | 20 ++++++++++++++++++++ requirements.txt | 30 ++++++++++++++++++++++++++++++ s6/run_dragonfly | 3 +++ s6/run_fastapi | 3 +++ 8 files changed, 110 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 app/__init__.py create mode 100644 app/main.py create mode 100644 requirements.txt create mode 100644 s6/run_dragonfly create mode 100644 s6/run_fastapi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7095cd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.venv +.python-version +*__pycache__ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1d876b4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +FROM public.ecr.aws/docker/library/python:3.11-slim-bookworm +ARG S6_OVERLAY_VERSION=3.1.5.0 + +RUN apt-get update && apt-get upgrade -y && apt-get install -y xz-utils libssl-dev libxml2-dev && rm -rf /var/cache/apt/archives /var/lib/apt/lists + +# Add s6-overlay +ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp +RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz +ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp +RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz + +# Add FastAPI s6 config +RUN mkdir -p /etc/s6-overlay/s6-rc.d/fastapi/dependencies.d/ +RUN echo "longrun" >> /etc/s6-overlay/s6-rc.d/fastapi/type +COPY s6/run_fastapi /etc/s6-overlay/s6-rc.d/fastapi/run +RUN touch /etc/s6-overlay/s6-rc.d/user/contents.d/fastapi && touch /etc/s6-overlay/s6-rc.d/fastapi/dependencies.d/base && touch /etc/s6-overlay/s6-rc.d/fastapi/dependencies.d/dragonfly + +# Install DragonflyDB +ADD https://github.com/dragonflydb/dragonfly/releases/download/v1.7.1/dragonfly_amd64.deb /tmp +RUN dpkg -i /tmp/dragonfly_amd64.deb + +# Cleanup /tmp +RUN rm -rf /tmp/* + +# Add DragonflyDB s6 config +RUN mkdir -p /etc/s6-overlay/s6-rc.d/dragonfly/dependencies.d/ +RUN echo "longrun" >> /etc/s6-overlay/s6-rc.d/dragonfly/type +COPY s6/run_dragonfly /etc/s6-overlay/s6-rc.d/dragonfly/run +RUN touch /etc/s6-overlay/s6-rc.d/user/contents.d/dragonfly && touch /etc/s6-overlay/s6-rc.d/dragonfly/dependencies.d/base + +# Add FastAPI code + dependencies +WORKDIR /code +COPY ./requirements.txt /code/requirements.txt +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt +COPY ./app /code/app + +# Execute s6 overlay entrypoint +ENTRYPOINT ["/init"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8188b2b --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# FastAPI - s6-overlay - sidecar PoC + +### How-To: + + docker build -t fastapi-s6-sidecar-poc + docker run --rm -p 8080:80 fastapi-s6-sidecar-poc + curl http://localhost:8080/metrics + +### Sources: +- [s6-overlay for docker](https://github.com/just-containers/s6-overlay) +- [FastAPI](https://fastapi.tiangolo.com) +- [Pytheus FastAPI Prometheus Middleware](https://github.com/Llandy3d/pytheus) +- [DragonflyDB - Redis drop-in replacement](https://github.com/dragonflydb/dragonfly) \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..d23472c --- /dev/null +++ b/app/main.py @@ -0,0 +1,20 @@ +from fastapi import FastAPI +from fastapi.responses import PlainTextResponse +from pytheus.exposition import generate_metrics +from pytheus.middleware import PytheusMiddlewareASGI + +from pytheus.backends import load_backend +from pytheus.backends.redis import MultiProcessRedisBackend + +load_backend( + backend_class=MultiProcessRedisBackend, + backend_config={"host": "127.0.0.1", "port": 6379}, +) + +app = FastAPI() +app.add_middleware(PytheusMiddlewareASGI) + + +@app.get("/metrics", response_class=PlainTextResponse) +async def pytheus_metrics(): + return generate_metrics() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..db4d9f2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,30 @@ +annotated-types==0.5.0 +anyio==3.7.1 +black==23.7.0 +click==8.1.6 +fastapi==0.101.0 +flake8==6.1.0 +gunicorn==21.2.0 +h11==0.14.0 +httptools==0.6.0 +idna==3.4 +mccabe==0.7.0 +mypy-extensions==1.0.0 +packaging==23.1 +pathspec==0.11.2 +platformdirs==3.10.0 +pycodestyle==2.11.0 +pydantic==2.1.1 +pydantic_core==2.4.0 +pyflakes==3.1.0 +pytheus==0.2.0 +python-dotenv==1.0.0 +PyYAML==6.0.1 +redis==4.6.0 +sniffio==1.3.0 +starlette==0.27.0 +typing_extensions==4.7.1 +uvicorn==0.23.2 +uvloop==0.17.0 +watchfiles==0.19.0 +websockets==11.0.3 diff --git a/s6/run_dragonfly b/s6/run_dragonfly new file mode 100644 index 0000000..e78d06b --- /dev/null +++ b/s6/run_dragonfly @@ -0,0 +1,3 @@ +#!/command/execlineb -P +dragonfly --logtostderr --bind localhost --port 6379 + diff --git a/s6/run_fastapi b/s6/run_fastapi new file mode 100644 index 0000000..81e72e9 --- /dev/null +++ b/s6/run_fastapi @@ -0,0 +1,3 @@ +#!/command/execlineb -P + /bin/sh -c "cd /code && gunicorn app.main:app --workers 2 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80" +