rough-noon-85911
07/28/2023, 1:25 PMbetter-van-82973
07/28/2023, 1:26 PMA repo that deploys a Flask or FastAPI app with docker and gunicorn/uvicorn. I’ve seen some basic docker examples but nothing deploying using those.
A repo that uses Helm. We currently deploy all of our services with Helm, and if Pants is a good solution for that as well, then I’d be interested. I’ve seen it in the docs but no examples.
better-van-82973
07/28/2023, 1:27 PMrough-noon-85911
07/28/2023, 1:37 PM[
"gunicorn",
"-b",
"0.0.0.0:80",
"--max-requests",
"0",
"--threads",
"10",
"-k",
"uvicorn.workers.UvicornWorker",
"--preload",
"<my.app.path>:main()",
]
I'm curious if you could share what the entry point looks like for your service. Do you use Pex for these?
Additionally, what does your folder structure look like (if that's not asking too much)? After looking through some examples I was considering the following:
3rdparty/
| -- python/
src/
| -- docker/
| -- service_a/
| -- service_b/
| -- python/
| -- services/
| -- service_a/
| -- service_b/
| -- libs/
| -- lib_a/
| -- javascript/
tests/
wide-midnight-78598
07/28/2023, 2:15 PMadhoc_tool
to run my SvelteKit stuff:
https://gist.github.com/sureshjoshi/98fb09f2a340f7c1dad270c4887865a0
For FastAPI, I'm using scies
rather than Docker, but it's not particularly hard to deploy to Docker instead (just put a pex
into the docker container and that's already most of the work).
There are already docs on some what you've asked for (e.g. package your Flask/FastAPI app into a pex, then deploy it into Docker):
https://pex.readthedocs.io/en/v2.1.140/recipes.html
Here's a bit of a throwaway example that needs some updates involving the main steps in using FastAPI:
https://github.com/sureshjoshi/pants-plugins/tree/main/examples/python/hellofastapi
And here's another example I use to make `scie`s for one of my projects (private, unfortunately):
pex_binary(
name="apigateway-pex",
dependencies=[
":libapigateway",
"//:reqs#uvicorn",
"//:reqs#gunicorn",
],
include_tools=True,
platforms=["linux-x86_64-cp-311-cp311", "macosx-13.3-arm64-cp-311-cp311",]
)
scie_binary(
name="apigateway",
dependencies=[":apigateway-pex"],
platforms=["linux-x86_64", "macos-aarch64"],
lift="lift.toml",
)
And then the lift.toml
is similar to the hellofastapi.toml
in the project above.
Finally, one of my projects it's sitting in an Azure App Service (because of reasons outside of my control), so in that case, I'm manually unwrapping my pex on deployment and running it with these commands (e.g. using the packaged gunicorn + uvicorn):
PEX_TOOLS=1 python ./apigateway.pex venv --bin-path prepend --compile --rm all venv
venv/bin/gunicorn apigateway.main:app --bind=0.0.0.0 --timeout 600 --forwarded-allow-ips="*" -k uvicorn.workers.UvicornWorker -w $((($NUM_CORES*2)+1))
better-van-82973
07/28/2023, 2:19 PMpython_sources(
name="lib",
dependencies=[
"//:poetry#grpcio",
"//:poetry#openai",
"//:poetry#anthropic",
"//:poetry#weaviate-client",
],
)
pex_binary(
name="binary-deps",
environment="linux_docker",
layout="packed",
execution_mode="venv",
include_sources=False,
include_tools=True,
)
pex_binary(
name="binary-srcs",
entry_point="main.py",
dependencies=[
":lib",
"api/src/py/api/scripts:lib",
"api/src/py/api/weaviate:schema",
"graph/src/py/graph:lib",
],
environment="linux_docker",
layout="packed",
execution_mode="venv",
include_requirements=False,
include_tools=True,
)
And in main.py
I have this at the bottom:
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=80)
happy-kitchen-89482
07/28/2023, 6:22 PMhappy-kitchen-89482
07/28/2023, 6:22 PMrough-noon-85911
07/31/2023, 2:11 AMwide-journalist-72152
02/07/2024, 8:47 PMwide-midnight-78598
02/07/2024, 9:12 PMwide-midnight-78598
02/07/2024, 9:13 PM# Following instructions here for reduced startup time and smaller footprint
# <https://pex.readthedocs.io/en/latest/recipes.html?ref=blog.pantsbuild.org#pex-app-in-a-container>
# There are still some more optimizations that could be done, see below:
# <https://blog.pantsbuild.org/optimizing-python-docker-deploys-using-pants/>
FROM python:3.11-slim as deps
COPY backend.admin/adminapi-pex.pex /api.pex
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /api.pex venv --scope=deps --compile /bin/app
FROM python:3.11-slim as srcs
COPY backend.admin/adminapi-pex.pex /api.pex
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /api.pex venv --scope=srcs --compile /bin/app
FROM python:3.11-slim
COPY --from=deps /bin/app /bin/app
COPY --from=srcs /bin/app /bin/app
# Using the same entrypoint as the Azure App Service variant
# Look into the number of cores
EXPOSE 8000
ENTRYPOINT ["/bin/app/bin/gunicorn", "admin.main:app", "--bind=0.0.0.0", "--timeout", "600", "--forwarded-allow-ips=*", "-k", "uvicorn.workers.UvicornWorker", "-w", "1"]
better-van-82973
02/07/2024, 9:40 PMFROM python:3.11-slim
ENTRYPOINT ["/bin/app/pex"]
EXPOSE 80
# Install package dependencies
RUN \
--mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
--mount=target=/var/cache/apt,type=cache,sharing=locked \
apt-get update && apt-get install -y procps build-essential python3-dev libpq-dev
# Copy deps and compile
COPY dist/api.src.py.api/binary-deps.pex /binary-deps.pex
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /binary-deps.pex venv --scope=deps --compile /bin/app
# Copy sources and compile
COPY dist/api.src.py.api/binary-srcs.pex /binary-srcs.pex
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /binary-srcs.pex venv --scope=srcs --compile /bin/app
wide-journalist-72152
02/07/2024, 11:55 PMFROM python:3.11-slim-bookworm as deps
COPY src.python/api-binary-deps.pex /
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /api-binary-deps.pex venv --scope=deps --compile /api-binary-deps
FROM python:3.11-slim-bookworm as srcs
COPY src.python/api-binary-srcs.pex /
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /api-binary-srcs.pex venv --scope=srcs --compile /api-binary-srcs
ENTRYPOINT ["/app/pex"]
EXPOSE 80
The error on line 7:
ERROR: failed to solve: process "/bin/sh -c PEX_TOOLS=1 /usr/local/bin/python3.11 /api-binary-srcs.pex venv --scope=srcs --compile /api-binary-srcs" did not complete successfully: exit code: 2
Honestly, I'm not even clear what "compile" means in this context, still less how to debug this failure.better-van-82973
02/08/2024, 12:08 AMExit status 2 appears when there’s a permissions problem or a missing keyword in a command or script. A missing keyword example is forgetting to add aSo if you can run that command manually inside a Docker container, you might find your answerin a script’sdone
loop. The best method for script debugging with this exit status is to issue your command in an interactive shell to see the errors you receive.do
wide-journalist-72152
02/08/2024, 2:17 AMpython: can't open file '/api-binary-srcs.pex': [Errno 2] No such file or directory
It's strange. From the error message the script seems to want to treat api-binary-srcs.pex
as a file it can open when it's actually a directory (with a file-like name). Stranger still, the same command worked fine for the command on api-binary-deps.pex
. I'm definitely confused.
I can't seem to find anything in the docs for Pex that explain the usage of the --compile flag, only example code, which I've tried to follow without a lot of understanding. There's this from the source code explaining the --compile flag and the trade-off of using it:
"Compiling means that the built pex will include .pyc files, which will result in "
"slightly faster startup performance. However, compiling means that the generated pex "
"likely will not be reproducible, meaning that if you were to run `./pex -o` with the "
"same inputs then the new pex would not be byte-for-byte identical to the original."
I rather appreciate that Pex (without compilation) affords a deterministic build artifact and wonder if it's worth the "slightly faster" startup performance to give that up. But I'd like to at least be able to try the compiled version.happy-kitchen-89482
02/08/2024, 2:25 AMhappy-kitchen-89482
02/08/2024, 2:26 AMhappy-kitchen-89482
02/08/2024, 2:30 AM/api-binary-srcs.pex
is a directory?happy-kitchen-89482
02/08/2024, 2:31 AM/api-binary-deps.pex
is not?wide-journalist-72152
02/08/2024, 3:00 AMwide-journalist-72152
02/08/2024, 3:03 AMhappy-kitchen-89482
02/08/2024, 3:05 AM--compile
to be a red herring herewide-journalist-72152
02/08/2024, 3:16 AMFROM python:3.11-slim-bookworm
ENTRYPOINT ["/bin/aerial-api.pex"]
COPY src.python/aerial-api.pex /bin
In this case I build the pex without layout="packed"
and execution_mode="venv"
to preserve the single file pex archive.
Running that image in a container does in fact start up the server exactly as happens when executing the pex file directly, but the server isn't accessible from the browser. Some missing network config perhaps. I'm not the greatest Docker expert and haven't worked that out after a bunch of fiddling with ENTRYPOINT and CMD directives.wide-midnight-78598
02/08/2024, 4:05 AMwide-journalist-72152
02/08/2024, 12:54 PM# 3rd party deps
pex_binary(
name="api-binary-deps",
environment="docker_linux",
layout="packed",
execution_mode="venv",
include_sources=False,
include_tools=True,
)
# 1st party srcs
pex_binary(
name="api-binary-srcs",
entry_point="api.main",
environment="docker_linux",
layout="packed",
execution_mode="venv",
include_requirements=False,
include_tools=True,
)