Search This Blog

Thursday, May 22, 2025

Segmentation fault when running pip inside docker buildx on host=arm platform=amd64

Following Docker's transition to a paid licensing model for Docker Desktop, I migrated our development environment to Rancher Desktop, which offers integrated support for both Docker and Kubernetes functionalities. During a recent initiative to convert legacy Docker images to multi-platform images, I encountered an unusual issue.

During the buildx build, the `pip install` command was failing with a segmentation fault error, despite the same installation steps executing flawlessly in an interactive container environment.

Initial Troubleshooting Efforts

Further investigation revealed:
1. The ARM64 architecture builds completed successfully, while AMD64 builds consistently failed
2. The failures were isolated to two specific Python packages: pycrypto and uWSGI
3. Standard remediation approaches suggested on various posts were ineffective, including:
   - Modifying Python versions
   - Updating pip
   - Testing alternative package versions
   - Installing supplementary system libraries
   - Switching between base images (python:3.8-slim (Debian bookworm), Debian bullseye, Ubuntu)
   - Using root installation instead of virtual environments

Root Cause Analysis

After extensive troubleshooting, I identified that the failures stemmed from cross-architecture compilation requirements. Both uWSGI and pycrypto lack pre-built wheels, necessitating compilation during installation. This compilation process was failing specifically when building AMD64 binaries on ARM64 host architecture.

Shifting my focus to the underlying virtualization platform, I searched for issues related to QEMU emulation and segmentation faults on AMD64 platforms. A comment on a relevant post suggested trying the build process on Docker Desktop. 

Resolution

After reinstalling Docker Desktop, I was able to successfully build the image.

To verify the findings, I retested all previous versions of the Dockerfile, and they worked as expected.

Conclusion

The root cause of this issue lies in the QEMU virtualization framework's emulation of AMD64 architectures on ARM-based systems. 

While ARM support has matured considerably across the board, such cases represent areas requiring further development attention from the community. 

NOTE

To facilitate easy reuse and streamline the build process, I recommend creating a builder

docker buildx create \
--name multi-platform-docker \
--driver docker-container \
--platform linux/amd64,linux/arm64


To utilize this builder, run the following command:

docker buildx --builder multi-platform-docker build .

Monday, May 19, 2025

Multi-platform multi-stage build docker images with platform specific files

 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.

/usr/lib/x86_64-linux-gnu

/usr/lib/aarch64-linux-gnu

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.

FROM --platform=amd64 python:${PYTHON_VERSION}-slim

COPY --from=builder /usr/lib/x86_64-linux-gnu/libmysql* /usr/lib/x86_64-linux-gnu
...

FROM --platform=arm64 python:${PYTHON_VERSION}-slim

COPY --from=builder /usr/lib/aarch64-linux-gnu/libmysql* /usr/lib/aarch64-linux-gnu
...

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.

FROM --platform=amd64 python:${PYTHON_VERSION}-slim as final-intermediate-amd64

COPY --from=builder /usr/lib/x86_64-linux-gnu/libmysql* /usr/lib/x86_64-linux-gnu
COPY --from=builder /usr/lib/x86_64-linux-gnu/libmaria* /usr/lib/x86_64-linux-gnu
COPY --from=builder /usr/lib/x86_64-linux-gnu/*xslt* /usr/lib/x86_64-linux-gnu
COPY --from=builder /usr/lib/x86_64-linux-gnu/*xml* /usr/lib/x86_64-linux-gnu

FROM --platform=arm64 python:${PYTHON_VERSION}-slim as final-intermediate-arm64

COPY --from=builder /usr/lib/aarch64-linux-gnu/libmysql* /usr/lib/aarch64-linux-gnu
COPY --from=builder /usr/lib/aarch64-linux-gnu/libmaria* /usr/lib/aarch64-linux-gnu
COPY --from=builder /usr/lib/aarch64-linux-gnu/*xslt* /usr/lib/aarch64-linux-gnu
COPY --from=builder /usr/lib/aarch64-linux-gnu/*xml* /usr/lib/aarch64-linux-gnu

FROM final-intermediate-${TARGETARCH}

COPY . /code/
COPY requirements.txt /code/requirements.txt
COPY --from=builder /code/.venv /code/.venv
COPY --from=builder /usr/bin/mysql_config /usr/bin

WORKDIR /code

EXPOSE 8000

CMD ["/code/.venv/bin/uvicorn", "--app-dir", "/code/myapp", "server:app", "--proxy-headers"]