Initial Troubleshooting Efforts
Root Cause Analysis
Resolution
Conclusion
NOTE
To utilize this builder, run the following command:
something regarding programming and installations...
Human knowledge belongs to the world!
While working on multi platform docker images for a FastAPI application with MySQL client libraries, ran into a scenario where the MySQL library files are stored in platform specific paths.
As part of multi-stage build, I wanted to do something like
FROM python:${PYTHON_VERSION}-slim
# if x64
COPY --from=builder /usr/lib/x86_64-linux-gnu/libmysql* /usr/lib/x86_64-linux-gnu
# if arm
COPY --from=builder /usr/lib/aarch64-linux-gnu/libmysql* /usr/lib/aarch64-linux-gnu
But there is no conditional platform support at the COPY command level. It is only at the FROM level.
The simple solution would be to have duplicate final image setup.
But this would mean duplicating rest of the steps too.
The solution is to create multiple platform specific intermediate images and use them to create the final image.
As per the FastAPI docs, the way to create and add custom middlewares is
Seems simple enough. Before the await, you can do something with the request. After the await, you can do something with the response.
But if you run benchmark, you will find something very surprising.
Recently I ran into a scenario where I needed to call a init function for a third party library in my FastAPI application. The problem was, the function was async.
One way of calling an async function from a sync flow is using asyncio event loop.
But this gave event loop is already running error.
The problem is, FastAPI application is run with uvicorn which starts a loop.
So I tried creating a new loop.
But this still didn't work as asyncio only supports one loop at a time.
The most suggested approach is to use nest-asyncio.
$ pip install fastapi_swagger2
from typing import Union from fastapi import FastAPI from fastapi_swagger2 import FastAPISwagger2 app = FastAPI() FastAPISwagger2(app) @app.get("/") def read_root(): return {"Hello": "World"} @app.get("/items/{item_id}") def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q}
Multipass is a nice docker like vm platform from Ubuntu. It can configure the vm with cloud-init so you can prototype your cloud launches locally for free.
E.g. Launch an instance (by default you get the current Ubuntu LTS)
$ multipass launch --name foo
You can read more about multipass in the docs.
Primarly it does seem like just another alternative to docker. But then I found one nice little difference, not a resource hog unlike docker and you don't run as root.
Currently to run a GUI application which you just want to try without having to clean up the system, most common approach is create a vm with VirtualBox, VMware Fusion or Parallels. But it can be a time consuming task as it installs everything from scratch.
Getting GUI applications to work on docker is possible configuration. But then, atleast on Mac, Docker is a resource hog.
With multipass I was able to get IntelliJ IDEA with following:
Prerequisites:
echo "XAuthLocation /opt/X11/bin/xauth" >> ~/.ssh/config
Launch a vm with current LTS ubuntu with 4 cores CPU and 4 GB memory
$ multipass launch -n idea -c 4 -m 4G
$ multipass shell idea
$ sudo apt update
$ sudo apt install -y libxrender-dev libxtst6 libxi6 fontconfig
$ cd /tmp
$ curl -L -O https://download.jetbrains.com/idea/ideaIC-2021.1.tar.gz
$ sudo tar -xzf ideaIC-2021.1.tar.gz -C /opt
$ echo 'PATH=/opt/idea-IC-211.6693.111/bin:$PATH' >> ~/.bashrc
$ sudo apt install -y openjdk-11-jdk
You could automate the above with cloud-init. (Currently as of this writing multipass only supports yaml configs)
Now time for the magic part (on the host):
multipass shell internally is just doing a SSH
$ sudo cp '/var/root/Library/Application Support/multipassd/ssh-keys/id_rsa' ~/.ssh/multipass_id_rsa
Save this script to your PATH
$ cat ~/bin/multipass_x_ssh
#!/bin/bash
IP=$(multipass info $1 | grep IPv4 | awk '{ print $2 }')
ssh -X -i ~/.ssh/multipass_id_rsa ubuntu@$IP
Now when I want to run idea, all I have to do is:
$ multipass_x_ssh idea
$ idea.sh
There seems to be some issue going on with pyenv and MacOS Big Sur.
./Modules/posixmodule.c:8320:15: error: implicit declaration of function 'sendfile' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
ret = sendfile(in, out, offset, &sbytes, &sf, flags);
After referring multiple posts, this is what worked for me.
brew install zlib bzip2
CFLAGS="-I$(brew --prefix openssl)/include -I$(brew --prefix bzip2)/include -I$(brew --prefix readline)/include -I$(xcrun --show-sdk-path)/usr/include" LDFLAGS="-L$(brew --prefix openssl)/lib -L$(brew --prefix readline)/lib -L$(brew --prefix zlib)/lib -L$(brew --prefix bzip2)/lib" pyenv install 3.5.3 --patch < <(curl -sSL https://github.com/python/cpython/commit/8ea6353.patch\?full_index\=1)