tiangolo / uvicorn-gunicorn-fastapi-docker

Docker image with Uvicorn managed by Gunicorn for high-performance FastAPI web applications in Python with performance auto-tuning.
MIT License
2.7k stars 333 forks source link

Providing an ARM build? #5

Closed ModischFabrications closed 4 years ago

ModischFabrications commented 5 years ago

I am trying to host my FastAPI project on a Raspberry Pi and get the following error every time I hit a RUN: standard_init_linux.go:190: exec user process caused "exec format error"

A little bit of research led me to believe that I need an ARM-image to base my project on, is there anything planned?


My Dockerfile:

# use FastAPI quick-deploy
FROM tiangolo/uvicorn-gunicorn:python3.7-alpine3.8

# copy whole installation (minus dockerignore)
COPY ./app /app

# install additional dependencies
COPY ./requirements.txt requirements.txt
RUN pip install -r requirements.txt

# entrypoints are managed by FastAPI
ModischFabrications commented 5 years ago

Ideally the base image could be multi-architecture (https://blog.docker.com/2017/09/docker-official-images-now-multi-platform/) to maximize compatibility.

tiangolo commented 5 years ago

Yes, I would like to, that's one of the reasons why I always base these images on official ones (official Python) and use parts from official images, because these base images are multi-architecture.

The issue is that not Docker Hub automated builds nor Travis CI can compile to ARMs.

If you clone this repository, you should be able to compile the images in the Raspberry Pi itself. Although this is not ideal.

"Solution", new docs

For this specific use case, I added documentation to create your application's Dockerfile with minimal requirements, in a way compatible with Raspberry Pi.

Using only Uvicorn (without Gunicorn), to reduce resource usage.

Here's the new documentation: https://fastapi.tiangolo.com/deployment/#raspberry-pi-and-other-architectures

Future plans

One of the side-projects in my backlog is finding a way to build in ARM (Raspberry Pi) and publish in the same Docker Hub images without affecting the other architectures. And then find a way to automatize it. But I haven't been able to test it, although I actually have a small Raspberry Pi cluster/farm (8 Pis I think). But for now, I think the solution above should work.

ModischFabrications commented 5 years ago

Thank you for your extensive answer and quick reaction, I'm even more impressed with this project. I am looking forward to your automated builds, for now I will stick to your "Solution".

I had a small problem but managed to get it working on PC using a slight modification of your newest addition to the documentation. In my case I needed to add a WORKDIR to keep my application in scope.

My new Dockerfile:

FROM python:3.7
EXPOSE 80

# manual installation
RUN pip install fastapi uvicorn

# copy whole installation (minus dockerignore)
COPY ./app /app

# install additional dependencies (might have duplicates?)
# (was pipenv previously but had problems with alpine)
COPY ./requirements.txt requirements.txt
RUN pip install -r requirements.txt

# set workdir to have subscripts in scope
WORKDIR ./app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

I unsuccessfully tried "improving" the Dockerfile by using FROM python:3.7-alpine. This is not possible as httpstools and uvloops are unable to build wheels. It might be sensible to empathize that as using alpine seems to be the default nowadays.

I was unable to get it running on my Raspberry Pi Zero W using the above Dockerfile. I have not found a solution in the last 2 hours, did I overlook something?

pi@modischpi-zero:~/CutSolver $ bash docker build -t cutsolver:latest .
Sending build context to Docker daemon  45.57kB
Step 1/8 : FROM python:3.7
 ---> fb676539ecfe
Step 2/8 : EXPOSE 80
 ---> Using cache
 ---> b2607ba96d8b
Step 3/8 : RUN pip install fastapi uvicorn
 ---> Running in 26bb1cd0822a
The command '/bin/sh -c pip install fastapi uvicorn' returned a non-zero code: 139

A few measurements I made while experimenting (on PC):

uvicorn-gunicorn:python3.7-alpine3.8 size: 114 554 660 init mem: 65MiB

Idle: 0.4% Run: 7.5%

python:3.7 ("manual" build) size: 974 971 759 init mem: 17MiB

Idle: 0.1% Run: 7.3%

ModischFabrications commented 5 years ago

I was experimenting a bit and it seems like a manual build is possible on Raspberry Pi 3B, but not on Zero W. Building the image on the 3B took around 15min, but at least it's working.

The main difference was that the 3B is using ARMv7 while the Zero W has ARMv6.

tiangolo commented 5 years ago

I'm sorry for the delay. Thanks for the report. That's an interesting finding. I don't own a Zero myself, so I wouldn't know. But it seems like the issue could be right there in the ARM version difference.

github-actions[bot] commented 4 years ago

Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues.

uburuntu commented 4 years ago

@tiangolo hello! Now it is possible to build arm based containers on any computer. Can you support it in your scripts? If you dont have enough free time I can try to make PR.

https://medium.com/@artur.klauser/building-multi-architecture-docker-images-with-buildx-27d80f7e2408 https://collabnix.com/building-arm-based-docker-images-on-docker-desktop-made-possible-using-buildx/

alexcombessie commented 3 years ago

Interested as well!

mayteio commented 3 years ago

+1 for multiarch!

assman commented 3 years ago

+1 for multiarch!

Soneji commented 3 years ago

@tiangolo can this be reopened please?

flyingjoe commented 3 years ago

Since the amd64 version of this container was way too slow on my m1 mac I forked this repo and changed the deploy action to build the arm64 version aswell: https://github.com/flyingjoe/uvicorn-gunicorn-fastapi-docker/tree/ARM_Images (same for the underlying uvicorn-gunicorn image of course)

Maybe this helps someone: https://hub.docker.com/r/flyingjoe/uvicorn-gunicorn-fastapi

Note: I had no time yet to adapt the tests to multi platform, that's why there is no pull request yet. I wouldn't recommend using this image for production.

tedivm commented 3 years ago

I've made an upstream PR to make the uvicorn-gunicorn containers multiarch. Those images are on docker hub as well (since I was testing push functionality).

Assuming that gets merged I can make another PR here to do the same.

Matthieu-Tinycoaching commented 3 years ago

Hi @tedivm is it viable to use the arm64 docker image from your docker hub repository on production on AWS graviton? Or is it better to way for the merge?

tedivm commented 3 years ago

I only put them up for testing (since docker buildx handles both building and pushing together, a registry is needed). I'm not automatically updating them or maintaining them, and after the PR is merged I plan on erasing the repo.

If you need to use these on graviton before they're merged in I'd suggest building them yourself directly, hosting on ECR, and then building off of your own images.

Matthieu-Tinycoaching commented 3 years ago

Hi @tedivm thanks but where could I find the most updated dockerfile to build these arm64 docker images?

I tried to rebuild arm64 uvicorn-gunicorn images based on https://github.com/tiangolo/uvicorn-gunicorn-docker/tree/master/docker-images and buildx, but this gave me inconsistent results unfortunately.

tedivm commented 3 years ago

If you want to use images from this PR you should clone my version of the upstream repository, check out this branch, update the repository username to the one for your container repository, and then run the build and push script from that repo.

Then do the same for this repository, pointing the dockerfiles at your newly created images.

Matthieu-Tinycoaching commented 3 years ago

@flyingjoe thanks for your arm64 image on docker hub, it works well on AWS EC2 graviton.

However, I have a strange behaviour when docker is running: rapidly the docker container takes more than 2 GB of disk space. I don't understand how and why it takes so much. Do you have an idea?

Thanks!