Docker: Installing python cryptography on alpine linux distribution

Marko Zadravec picture Marko Zadravec · May 31, 2018 · Viewed 9.9k times · Source

I am a little bit new to Docker and deployment cycle.

I have Django application that we would like to deploy with uWSGI to docker container. Actually the deploy worked perfectly for a few weeks, but now it soundly report error...

Error seam to be with cryptography package:

build/temp.linux-x86_64-3.6/_openssl.c:52862:10: warning: conversion to 'long unsigned int' from 'long int' may change the sign of the result [-Wsign-conversion]
build/temp.linux-x86_64-3.6/_openssl.c: In function '_cffi_f_SSL_set_options':
build/temp.linux-x86_64-3.6/_openssl.c:52895:14: warning: conversion to 'long int' from 'long unsigned int' may change the sign of the result [-Wsign-conversion]
   { result = SSL_set_options(x0, x1); }
              ^~~~~~~~~~~~~~~
build/temp.linux-x86_64-3.6/_openssl.c:52895:14: warning: conversion to 'long unsigned int' from 'long int' may change the sign of the result [-Wsign-conversion]
error: command 'gcc' failed with exit status 1
----------------------------------------
Command "/usr/local/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-install-dg_tg9pa/cryptography/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-record-my98rwq4/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-install-dg_tg9pa/cryptography/ 
The command '/bin/sh -c pip install --no-cache-dir -r requirements.txt' returned a non-zero code: 1
ERROR: Job failed: exit code 1

Our docker file looks like

FROM python:3-alpine

ENV PYTHONUNBUFFERED 1

WORKDIR /usr/src/app

RUN apk add --no-cache gcc mailcap python3-dev build-base linux-headers pcre-dev postgresql-dev libffi-dev libressl-dev

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

As I mention the docker file and requirement.txt hasn't change between success build and failed one. (What is the most strange to me...)

The only think I could think is that command

FROM python:3-alpine

is taking the different version of alpine...

Is this possible? What could be wrong? How to fix it?

Answer

Akram picture Akram · Sep 20, 2019

Alpine is a headache distro for most Python packages that ship C/C++ extensions (code written in C/C++ that is compiled to a shared object and loaded in Python via a foreign function library). The reason for that is that is PEP 513 which portability definition between Linux distros, manylinux1, is based on glibc/glibcxx. Since Alpine uses musl libc, no manylinux1 compatible wheel can be installed on Alpine. So when you issue pip install cryptography, the wheel with the compiled extensions is filtered and pip tries to build the package with all the C extensions from source.

installing with the system package manager

This is the preferred way and was mentioned by @GracefulRestart in the comments; use it if you don't need the bleeding edge version of the package. Install it with apk:

$ apk add py-cryptography

installing with pip

Should you need the bleeding edge version, you can try building it from source by installing with pip.

Preparing the build environment

You will need the compiler and libraries with header files: musl, OpenSSL, libffi and Python itself:

$ apk add gcc musl-dev libffi-dev openssl-dev python3-dev


Building

$ pip install pkgname

hides the build log by default. To see the complete build log, add -vvv to increase verbosity. (Optional) Also, you can explicitly prohibit installing manylinux1 wheels by adding -

-no-binary=pkgname

so the build from source will be enforced.

$ pip install cryptography -vvv --no-binary=cryptography