Docker + Alpine3.5 + Apache2.4 + Python3.xで、mod_pythonをソースコードからインストールしてみた

以前、Docker + Alpine3.5 + Apache2.4 + Python2.7で、mod_pythonソースコードからインストールしてみました。
Docker + Alpine3.5 + Apache2.4 + Python2.7で、mod_pythonをソースコードからインストールしてみた - メモ的な思考的な

 
その時はPython2.x系で試したため、今回はPython3.x系でmod_pythonコンパイル&インストールし、Hello worldしてみます。

 
目次

 

環境

  • Mac OS X 10.11.6
  • Docker for Mac 17.03.1-ce-mac12
  • Alpine3.5 + Apache2.4.25
    • 前回同様、Apacheはprefork MPMで動作するようにDockerfileを修正
  • Python3系は以下の2種類を試す
    • Alpine3.5のパッケージにあるPython3.5
    • Alpine EdgeのパッケージにあるPython3.6
      • Alpine3.6ならPython3.6が入るが、今回はAlpine3.5で検証
  • mod_python
    • GitHub上のmasterの最新版
    • 今回利用したコミットは8acf1b7

 
なお、動作させるためのDockerfileやhttpd.conf、Hello worldスクリプトは、以前のPython2系で使ったものを流用・一部修正していきます。

 

まとめ

長いので最初にまとめます。

  • 最新のmaster(8acf1b7)ではPython3.x系は動作しない*1
  • ブランチ 3.5.xソースコードであれば、Python3.x系は動作する
  • 最新のmasterで動作させるには、ビルド用のファイルをブランチ3.5.xのコミットへと戻す
    • configure〜make installはあまり詳しくないので、3.5.xから最新までの間のどこでビルド用のファイルが壊れたかまでは追っていない

 

準備:prefork MPMで動作するApache2.4のDockerイメージを作成

今回の件とはあまり関係ないですが、後で再利用できるよう、Apache2.4 + prefork MPMのDockerイメージを作成しておきます。

(長いので省略しますが)Dockerfileは以下を使います。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/blob/master/alpine_apache_prefork/Dockerfile

 
thinkami:httpd24_preforkという名前でDockerイメージを作成します。

$ docker image build -t thinkami:httpd24_prefork .

 

masterをコンパイル&インストー

mod_pythonのmasterをPython3.5でコンパイル&インストールするには、以前のDockerfileを以下の内容で修正します。

  • mod_pythonで使用するpythonpython3へと変更
  • mod_pythonをビルドする時に使うpython-devpython3-devへと変更
  • configureする時のwith-pythonオプションを--with-python=/usr/bin/python3へと変更
RUN apk --update --no-cache add python3 && \
    python3 -m ensurepip && \
    rm -r /usr/lib/python*/ensurepip && \
    pip3 install --upgrade pip setuptools && \
    rm -r /root/.cache && \
    # mod_pythonで必要なパッケージを追加
    apk add --no-cache --virtual .mod_python_build_libs git && \
    apk --no-cache --virtual .mod_python_build_libs add python3-dev && \
    apk add --no-cache --virtual .mod_python_build_libs apache2-dev && \
    apk add --no-cache --virtual .mod_python_build_libs flex && \
    # ./configureで必要
    apk add --no-cache --virtual .mod_python_build_libs build-base && \
    # sudo make installで必要
    apk add --no-cache --virtual .mod_python_build_libs sudo && \
    # GitHubからソースコードを持ってきてインストール
    cd /tmp && \
    mkdir mod_python && \
    cd mod_python && \
    git clone https://github.com/grisha/mod_python.git . && \
    ./configure --with-apxs=/usr/local/apache2/bin/apxs --with-python=/usr/bin/python3 --with-flex=/usr/bin/flex && \
    make && \
    sudo make install && \
    # 不要なパッケージやソースコードを一括削除
    apk del .mod_python_build_libs && \
    rm -r /tmp/mod_python

 
docker image builddocker container runします。

# Dockerイメージのビルド
$ docker image build -t thinkami:python3_httpd24_mod_python_1 .
...
Successfully built e2669af0e6a4

# Dockerコンテナの起動 => エラーで起動せず
$ docker container run -p 8081:80 --name mod_python_1 -v `pwd`/htdocs/:/usr/local/apache2/htdocs thinkami:python3_httpd24_mod_python_1
httpd: Syntax error on line 19 of /usr/local/apache2/conf/httpd.conf: Cannot load modules/mod_python.so into server: Error relocating /usr/local/apache2/modules/mod_python.so: PyErr_BadArgument: symbol not found

 
エラーPyErr_BadArgument: symbol not foundが表示され、Dockerコンテナが起動しません。

ブランチ3.5.xをコンパイル&インストー

最新のmasterでは動作しなかったため、動作するブランチを探したところ、以下のIssueにコメントがありました。
mod_python 3.5.0 (with support for Python 3!) available for pre-release testing. · Issue #9 · grisha/mod_python

3.5.xブランチを使えばいいようです。

 
そのため、Dockerfileの中でgit cloneしている部分をmasterから3.5.xブランチへと修正します。

# git clone https://github.com/grisha/mod_python.git . && \
git clone -b 3.5.x https://github.com/grisha/mod_python.git . && \

 
docker image build & docker container runします。

$ docker image build -t thinkami:python3_httpd24_mod_python_2 .

$ docker container run -p 8081:80 --name mod_python_2 -v `pwd`/htdocs/:/usr/local/apache2/htdocs thinkami:python3_httpd24_mod_python_2
[Fri Jun 09 03:51:43.408568 2017] [:notice] [pid 1] mod_python: Creating 8 session mutexes based on 256 max processes and 0 max threads.
[Fri Jun 09 03:51:43.408632 2017] [:notice] [pid 1] mod_python: using mutex_directory /tmp 
[Fri Jun 09 03:51:43.445271 2017] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.25 (Unix) mod_python/3.5.0-9d223c3 Python/3.5.2 configured -- resuming normal operations
[Fri Jun 09 03:51:43.445310 2017] [core:notice] [pid 1] AH00094: Command line: 'httpd -D FOREGROUND'
[Fri Jun 09 03:52:06.023976 2017] [:notice] [pid 6] mod_python: (Re)importing module 'mptest'
172.17.0.1 - - [09/Jun/2017:03:52:05 +0000] "GET /test/mptest.py HTTP/1.1" 200 12

mod_pythonが起動したようです。

 
curlで動作確認をします。

$ curl localhost:8081/test/mptest.py -D - -v
*   Trying ::1...
* Connected to localhost (::1) port 8081 (#0)
> GET /test/mptest.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Fri, 09 Jun 2017 03:52:05 GMT
Date: Fri, 09 Jun 2017 03:52:05 GMT
< Server: Apache/2.4.25 (Unix) mod_python/3.5.0-9d223c3 Python/3.5.2
Server: Apache/2.4.25 (Unix) mod_python/3.5.0-9d223c3 Python/3.5.2
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
< Content-Type: text/plain
Content-Type: text/plain

< 
* Connection #0 to host localhost left intact
Hello World!

Hello worldが表示されたため、正常に動作しているようです。

 

masterにブランチ3.5.xをマージして、コンパイル&インストー

上記ではブランチ3.5.xで動かしましたが、3.5.xブランチの最新コミットは2013年10月であるため、それ以降に修正された不具合は反映されていません。

試しにブランチ3.5.xとmasterの差分を見ると、以下の4コミットでした。 Comparing master…3.5.x · grisha/mod_python

4コミットには以下の8ファイルが含まれていました。

 
そこで、masterにブランチ3.5.xを単純にマージし、動作するか試してみます。

 
Dockerfileでは

  • git cloneするのをmasterから3.5.xブランチへ
  • git mergeするために、ユーザの設定を任意の値へ

を修正します。

cd mod_python && \
# gitを使うためにユーザ設定を実施
git config --global user.email "you@example.com" && \
git config --global user.name "Your Name" && \
# 現在のmasterを取得
git clone https://github.com/grisha/mod_python.git . && \
# 3.5.xブランチを取得
git branch 3.5.x origin/3.5.x && \
# 3.5.xブランチをmasterにマージ
git merge 3.5.x && \
./configure --with-apxs=/usr/local/apache2/bin/apxs --with-python=/usr/bin/python3 --with-flex=/usr/bin/flex && \

 
docker image build & docker container runします。

$ docker image build -t thinkami:python3_httpd24_mod_python_3 .

$ docker container run -p 8081:80 --name mod_python_3 -v `pwd`/htdocs/:/usr/local/apache2/htdocs thinkami:python3_httpd24_mod_python_3
[Fri Jun 09 03:54:21.257839 2017] [:notice] [pid 1] mod_python: Creating 8 session mutexes based on 256 max processes and 0 max threads.
[Fri Jun 09 03:54:21.257983 2017] [:notice] [pid 1] mod_python: using mutex_directory /tmp 
[Fri Jun 09 03:54:21.391315 2017] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.25 (Unix) mod_python/3.5.0-7e4861f Python/3.5.2 configured -- resuming normal operations
[Fri Jun 09 03:54:21.393658 2017] [core:notice] [pid 1] AH00094: Command line: 'httpd -D FOREGROUND'

mod_pythonが起動したようです。

 
curlで動作確認をします。

$ curl localhost:8081/test/mptest.py -D - -v
*   Trying ::1...
* Connected to localhost (::1) port 8081 (#0)
> GET /test/mptest.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 500 Internal Server Error
HTTP/1.1 500 Internal Server Error
< Date: Fri, 09 Jun 2017 03:54:36 GMT
Date: Fri, 09 Jun 2017 03:54:36 GMT
< Server: Apache/2.4.25 (Unix) mod_python/3.5.0-7e4861f Python/3.5.2
Server: Apache/2.4.25 (Unix) mod_python/3.5.0-7e4861f Python/3.5.2
< Content-Length: 528
Content-Length: 528
< Connection: close
Connection: close
< Content-Type: text/html; charset=iso-8859-1
Content-Type: text/html; charset=iso-8859-1

< 
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>500 Internal Server Error</title>
</head><body>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete
your request.</p>
<p>Please contact the server administrator at 
 you@example.com to inform them of the time this error occurred,
 and the actions you performed just before this error.</p>
<p>More information about this error may be available
in the server error log.</p>
</body></html>
* Closing connection 0

Internal Server Errorになりました。

 
Docker containerのコンソールを見ると

[Fri Jun 09 03:54:36.714955 2017] [:error] [pid 6] make_obcallback: could not import mod_python.apache.\n
[Fri Jun 09 03:54:36.716445 2017] [:error] [pid 6] make_obcallback: Python path being used "['/usr/lib/python35.zip', '/usr/lib/python3.5/', '/usr/lib/python3.5/plat-linux', '/usr/lib/python3.5/lib-dynload']".
[Fri Jun 09 03:54:36.716560 2017] [:error] [pid 6] get_interpreter: no interpreter callback found.
[Fri Jun 09 03:54:36.716596 2017] [:error] [pid 6] [client 172.17.0.1:36616] python_handler: Can't get/create interpreter.
172.17.0.1 - - [09/Jun/2017:03:54:36 +0000] "GET /test/mptest.py HTTP/1.1" 500 528

と、interpreterのcallbackが見当たらないようです。

よって、単純なマージではダメなようです。

 

masterのビルド用ファイルをブランチ3.5.xの時点に戻して、コンパイル&インストー

差分のあった8ファイルのうちビルド用ファイル

を、ブランチ3.5.x時の状態に戻した上でコンパイル&インストールします。

また、コンパイルにはAPKのEdgeにあるPython3の最新版を利用してみます。

Dockerfileの変更は

# Python3まわり
RUN apk --update --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/main/ add python3 && \
    python3 -m ensurepip && \
    rm -r /usr/lib/python*/ensurepip && \
    pip3 install --upgrade pip setuptools && \
    rm -r /root/.cache && \
    # python3-devもEdgeから持ってくる
    # そうでないと、Python3のバージョンが合わずに、Downgrading python3が発生する
    apk --no-cache --virtual .mod_python_build_libs --repository http://dl-cdn.alpinelinux.org/alpine/edge/main/ add python3-dev && \
...

# mod_pythonまわり
    cd mod_python && \
    # gitを使うためにユーザ設定を実施
    git config --global user.email "you@example.com" && \
    git config --global user.name "Your Name" && \
    # 現在のmasterを取得
    git clone https://github.com/grisha/mod_python.git . && \
    # 3.5.xブランチを取得
    git branch 3.5.x origin/3.5.x && \
    # 3.5.xブランチをmasterにマージ
    git merge 3.5.x && \
    # python3用に、masterブランチのうちの一部ファイルを3.5.xブランチの状態へ戻す => OK
    git checkout 2d013b353631feb7ffe29fe9946327a08fe55381 scripts/mod_python.in && \
    git checkout 54d42b1810d5abfffe5b407d8e763402a0d4b2f0 configure.in && \
    git checkout 9d223c39a8f27345d8c046d026468fc0c1ad5d53 configure && \
    git checkout 51f7b0366d66b58b5b82874fe8a2db346f77d7fc src/include/mod_python.h && \
    git checkout 51f7b0366d66b58b5b82874fe8a2db346f77d7fc src/include/mod_python.h.in && \
    git checkout affc26bd69b3f5e67e8233166ff0d40c43fb7302 src/mod_python.c && \
    # ビルド
    ./configure --with-apxs=/usr/local/apache2/bin/apxs --with-python=/usr/bin/python3 --with-flex=/usr/bin/flex && \
...

です。

 
docker image build & docker container runします。

$ docker image build -t thinkami:python3_httpd24_mod_python_4 .

$ docker container run -p 8081:80 --name mod_python_4 -v `pwd`/htdocs/:/usr/local/apache2/htdocs thinkami:python3_httpd24_mod_python_4
[Fri Jun 09 03:56:17.740963 2017] [:notice] [pid 1] mod_python: Creating 8 session mutexes based on 256 max processes and 0 max threads.
[Fri Jun 09 03:56:17.741173 2017] [:notice] [pid 1] mod_python: using mutex_directory /tmp 
[Fri Jun 09 03:56:17.959878 2017] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.25 (Unix) mod_python/3.5.0-2b3da9d Python/3.6.1 configured -- resuming normal operations
[Fri Jun 09 03:56:17.960025 2017] [core:notice] [pid 1] AH00094: Command line: 'httpd -D FOREGROUND'

 
curlで動作確認をします。

$ curl localhost:8081/test/mptest.py -D - -v
*   Trying ::1...
* Connected to localhost (::1) port 8081 (#0)
> GET /test/mptest.py HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.43.0
> Accept: */*
> 
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Fri, 09 Jun 2017 03:56:34 GMT
Date: Fri, 09 Jun 2017 03:56:34 GMT
< Server: Apache/2.4.25 (Unix) mod_python/3.5.0-2b3da9d Python/3.6.1
Server: Apache/2.4.25 (Unix) mod_python/3.5.0-2b3da9d Python/3.6.1
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
< Content-Type: text/plain
Content-Type: text/plain

< 
* Connection #0 to host localhost left intact
Hello World!

Hello Worldが表示されました。

念のため、Dockerのコンソールを見ると

[Fri Jun 09 03:56:35.416889 2017] [:notice] [pid 6] mod_python: (Re)importing module 'mptest'
172.17.0.1 - - [09/Jun/2017:03:56:34 +0000] "GET /test/mptest.py HTTP/1.1" 200 12

と、無事に動いているようです。

 

ソースコード

GitHubに上げました。
thinkAmi-sandbox/Docker_Apache-sample

関係するディレクトリは以下の通りです。

  • alpine_apache_python3x_mod_python
    • 今回試したソースコード一式
    • executable_py36_all_in_oneは、Alpine3.5のDockerイメージから、Apache2.4(prefork) + EgeのPython3.x + mod_python が動作する環境を作るDockerfile
  • alpine_apache_prefork
    • Apache2.4をprefork MPMでビルドするDockerfile

*1:前回の記事にある通りこのコミットは自分のプルリクのものですが、動作しない原因は自分のコミットではありません、たぶん