在Docker中安装uWSGI

简介

uWSGI是一个由unbit提供的Web应用服务器,实现了WSGI规范。

由于主题是C语言,所以在利用pip install uWSGI来安装时,需要配置编译环境。

在Alpine中尝试安装

由于直接写Dockerfile时失败了,并且错误提示不足。 于是,孤跑了一个python:2.7.13-alpine的Docker容器,然后尝试安装uWSGI

$ docker run --rm -it python:2.7.13-alpine sh

以下开始试错。

gcc

直接执行pip install uWSGI,得到近百行的错误提示。 其中有用的部分如下:

  File "uwsgiconfig.py", line 742, in __init__
    raise Exception("you need a C compiler to build uWSGI")
Exception: you need a C compiler to build uWSGI

这表明,需要安装一个C编译器。 由于是首次安装软件,需要先更新源。

apk update
apk add gcc

这步是比较耗时的,约10分钟,具体取决于网速。

这也是为什么,孤选择不直接通过build一个Dockerfile来试错。

libc-dev

安装gcc后,再执行pip install uWSGI,关键错误如下:

    In file included from core/socket.c:1:0:
    ./uwsgi.h:165:19: fatal error: stdio.h: No such file or directory
    compilation terminated.
    In file included from core/logging.c:2:0:
    ./uwsgi.h:165:19: fatal error: stdio.h: No such file or directory
    compilation terminated.
    In file included from core/utils.c:1:0:
    ./uwsgi.h:165:19: fatal error: stdio.h: No such file or directory
    compilation terminated.
    In file included from core/protocol.c:1:0:
    ./uwsgi.h:165:19: fatal error: stdio.h: No such file or directory
    compilation terminated.

stdio.h都没有,这当然是缺乏C语言的标准库所致。

apk add libc-dev

linux-headers

再来,关键错误如下:

    In file included from core/logging.c:2:0:
    ./uwsgi.h:238:26: fatal error: linux/limits.h: No such file or directory
    compilation terminated.
    In file included from core/utils.c:1:0:
    ./uwsgi.h:238:26: fatal error: linux/limits.h: No such file or directory
    compilation terminated.
    In file included from core/protocol.c:1:0:
    ./uwsgi.h:238:26: fatal error: linux/limits.h: No such file or directory
    compilation terminated.
    In file included from core/socket.c:1:0:
    ./uwsgi.h:238:26: fatal error: linux/limits.h: No such file or directory
    compilation terminated.

虽然有了C的标准库,但是缺乏Linux相关的头文件。

apk add linux-headers

这也是最后一个必要的编译依赖了。 此后,pip install uWSGI顺利完成。

运行问题

编译有依赖,运行也有依赖。 二者通常是不同的,而后者通常是前者的子集。

由于三个模块都是编译用的,所以编译完成后可以删除。

而如果删除了编译依赖,运行时会出现问题。

Error loading shared library libuuid.so.1: No such file or directory (needed by /usr/local/bin/uwsgi) Error relocating /usr/local/bin/uwsgi: uuid_unparse: symbol not found Error relocating /usr/local/bin/uwsgi: uuid_generate: symbol not found

所幸,加上libuuid就没问题了。

其它问题

由于uWSGI功能众多,所以,使用的参数不同,需要的功能也会有差异。

在使用--static-map等参数时,可能会有额外的编译依赖,否则会有运行时报错。

pcre-dev

!!! no internal routing support, rebuild with pcre support !!!

PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正则表达式库。

编译依赖为pcre-dev,运行依赖为pcre。

mailcap

!!! no /etc/mime.types file found !!!

运行时,某些功能需要访问/etc/mime.types文件。

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。 是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。

这个东西对应的Alpine库是mailcap。

Dockerfile(部分)

FROM python:2.7.15-alpine

RUN apk update && apk add \
        libuuid \
        pcre \
        mailcap \
        gcc \
        libc-dev \
        linux-headers \
        pcre-dev \
    && pip install --no-cache-dir uWSGI>=2.0.15 \
    && apk del \
        gcc \
        libc-dev \
        linux-headers \
    && rm -rf /tmp/*

总结

对一个纯净的Alpine来说,uWSGI有gcc、libc、linux-headers三个编译依赖。

编译完成后如果删除依赖,则还需要一个运行时依赖libuuid。

通过上述方法,可以更快的确定这一点,做出更好的Docker镜像。

如果使用Debian作为基础镜像,过程会简单一些,因为镜像自带的库比较全。 但是,镜像文件就大多了。

另附

由于有部分Python库,无法在Alpine上使用,比如opencv-python。 原因是,Alpine的libc不是GNU的,而是musl libc。 详见:Cannot install opencv-contrib-python from Alpine Linux · Issue #75 · skvark/opencv-python

I completely forgot that Alpine Linux is based on musl libc and not on GNU libc and thus it's not a GNU/Linux distribution. Manylinux supports only GNU/Linux.

因此,基于Debian的镜像,有时也是必须的。 好在slim版的镜像也不大。 以下就是一个基于python:3.5.6-slim-stretch,安装uWSGI的示例。

FROM python:3.5.6-slim-stretch

# Install uWSGI
RUN apt-get update && apt-get install -y \
        libc6-dev \
        gcc \
        mime-support \
    && pip install --no-cache-dir uWSGI>=2.0.15 \
    && apt-get remove -y \
        gcc \
        libc6-dev \
    && rm -rf /var/lib/apt/lists/*

相关笔记