ripe-battery-94204
12/14/2023, 4:06 PMcli/
├─ run.py
├─ evaluate.py
├─ BUILD
data/
main_library/
web/
├─ server.py
├─ BUILD
app.yaml
pants.toml
requirements.txt
BUILD
Currently:
• Our flask app is run by gunicorn (invoked through the CLI) on Google App Engine (without docker)
What We Want:
• The flask app should be run by gunicorn
(invoked through the CLI)
• It should be packaged as Docker image and uploaded to the Google Artefact Registry
• Deployment then would merely mean to pull a new image version into GAE (no pants involved)
What We Tried:
We have tried various ways of achieving the above and are currently stuck with building a pex
target of the web/server.py.
We build it cross-platform so it works both on our local machines (OSX) and the Docker image (linux)
We ran into some issues with loading resources included in the pex
file. Unzipping the pex
after copying it onto the Docker image solved the issue, but feels like it might be a hacky solution. The image runs fine locally but not on app engine.
We thought running flask via gunicorn and Docker should be trivial, but for some reason we can’t seem to get it to work. Has anyone here experience with this specific deployment scenario?broad-processor-92400
12/14/2023, 4:57 PMwide-midnight-78598
12/14/2023, 5:22 PMwide-midnight-78598
12/14/2023, 5:59 PMscie
but AppService couldn't just run a random executable (which is stupid).
I'm using Azure's docker app services - but I think with what I'm doing here, you can narrow down some of the stuff on your side as well.
# BUILD.pants
pex_binary(
name="myapi",
dependencies=[
":libmyapi",
"//:reqs#uvicorn",
"//:reqs#gunicorn",
],
include_tools=True,
platforms=[
"linux-x86_64-cp-311-cp311",
"macosx-13.3-arm64-cp-311-cp311",
"macosx-13.3-x86_64-cp-311-cp311",
],
)
docker_image(
name="dockerized_myapi",
image_tags=["mytag1"],
registries=["myregistry"],
repository="myrepo",
skip_push=True,
)
# Dockerfile
# 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.myapi/myapi.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.myapi/myapi.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
EXPOSE 8000
ENTRYPOINT ["/bin/app/bin/gunicorn", "myapi.main:app", "--bind=0.0.0.0", "--timeout", "600", "--forwarded-allow-ips=*", "-k", "uvicorn.workers.UvicornWorker", "-w", "1"]
Then I use something like pants package backend/myapi::
to build the docker image, and then in my case, I just deploy using podman
- but you might be able to use Pants for that too, if you setup the registries and loginsripe-battery-94204
12/20/2023, 3:36 PMWARNING: Deployment of service [default] will ignore the skip_files field in the configuration file, because the image has already been built.
Updating service [default] (this may take several minutes)...failed.
ERROR: (gcloud.app.deploy) Error Response: [9] An internal error occurred while processing task /app-engine-flex/flex_await_healthy/flex_await_healthy>2023-12-20T15:31:53.445Z3500.lclhrb.1: exec /bin/app/bin/gunicorn: exec format error
Apparently the exec format error
usually indicates a mismatch in platforms. We cross-compile from osx
onto linux_arm64
and the docker image works perfectly when deployed locally. It just doesn't work once deployed to GAE. Any ideas where this could come from?wide-midnight-78598
12/20/2023, 3:38 PMripe-battery-94204
12/20/2023, 3:41 PMdocker_environment
platform to linux_x86_64
but I then get this following error:
16:39:34.25 [ERROR] 1 Exception encountered:
Engine traceback:
in `package` goal
IntrinsicError: Failed to create Docker container: DockerResponseServerError { status_code: 404, message: "image with reference sha256:09485c9.....2f49afbba62cd5bd387 was found but does not match the specified platform: wanted linux/amd64, actual: linux/arm64/v8" }
So maybe the actual issue lies here?ripe-battery-94204
12/20/2023, 3:43 PMdocker_environment(
name="python_linux",
platform="linux_arm64", # Seems like the correct platform?
image="python:3.10.13-bookworm",
python_bootstrap_search_path=["<PATH>"],
)
pex_binary(
name="server",
dependencies=[
"main_libarary:main_libarary",
"//:reqs#gunicorn",
"web/server.py",
"systems:systems",
],
environment="linux", # This maps to the docker_environment python_linux above
include_tools=True,
layout="packed",
execution_mode="venv"
)
docker_image(
name="server_image",
)
wide-midnight-78598
12/20/2023, 3:44 PMplatforms=[
"linux-x86_64-cp-311-cp311",
"macosx-13.3-arm64-cp-311-cp311",
"macosx-13.3-x86_64-cp-311-cp311",
],
wide-midnight-78598
12/20/2023, 3:45 PMcomplete_platforms
https://www.pantsbuild.org/docs/reference-pex_binary#codecomplete_platformscoderipe-battery-94204
12/20/2023, 4:19 PMplatforms
parameter through the pex_binary I get some issues with pyyaml
No interpreter compatible with the requested constraints was found:
A distribution for pyyaml could not be resolved for /usr/local/bin/python3.10.
Found 2 distributions for pyyaml that do not apply:
1.) The wheel tags for PyYAML 6.0.1 are cp310-cp310-macosx_11_0_arm64 which do not match the supported tags of /usr/local/bin/python3.10:
cp310-cp310-manylinux_2_36_aarch64
... 517 more ...
2.) The wheel tags for PyYAML 6.0.1 are cp310-cp310-manylinux_2_17_x86_64, cp310-cp310-manylinux2014_x86_64 which do not match the supported tags of /usr/local/bin/python3.10:
cp310-cp310-manylinux_2_36_aarch64
... 517 more ...
Using the docker_environment solved those issues since you're directly building on what seemed like the correct platform.
Looking into complete platforms now, maybe that will do the trickripe-battery-94204
12/21/2023, 4:16 PMplatforms=[
"linux_2_17_x86_64-3.10.10-cp310"
"macosx_14_0_arm64-cp-3.10.10-cp310"
]
I get the following error:
stderr:
No pre-built wheel was available for PyYAML 6.0.1.
Successfully built the wheel PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl from the sdist PyYAML-6.0.1.tar.gz but it is not compatible with the requested foreign target abbreviated platform cp310-cp310-linux_2_17_x86_64_3_10_10_cp310macosx_14_0_arm64.
You'll need to build a wheel from PyYAML-6.0.1.tar.gz on the foreign target platform and make it available to Pex via a `--find-links` repo or a custom `--index`.
Seems like it pants builds the wheel for PyYAML automatically, but does it for MacOS but not for linux. Given that I am on a Mac machine that makes sense, but I'm confused how to get around this. I used the docker_environment to solve this issue, but is there any other way?broad-processor-92400
12/21/2023, 9:58 PM```2.) The wheel tags for PyYAML 6.0.1 are cp310-cp310-manylinux_2_17_x86_64, cp310-cp310-manylinux2014_x86_64 which do not match the supported tags of /usr/local/bin/python3.10:
cp310-cp310-manylinux_2_36_aarch64```It looks like the dependency is packaged for x86-64 architecture, but is running on aarch64 (aka arm) architecture. How are you running it?
broad-processor-92400
12/21/2023, 10:01 PMplatforms
is a dead-end that's soon to be deprecated in Pants, because they're a very lossy estimate of the target platform: complete platforms is the way to go, as that has far more accurate info.
https://github.com/pantsbuild/pants/discussions/18756 has some info about how we do it.