Docker上のEmacsのビルドでハマった話

Docker上でEmacsをビルドしようとしてハマったので対処方法と、ついでに簡単に調査したメモです。

現象

環境は次のような感じでした。

  • ホスト: CentOS 7.2 (Conoha VPSのデフォルトイメージ利用)
  • Docker 1.10.3

まず、確認用に次のDockerfileを用意します。なお、centos:7としても現象は同じでした(ただし、yumのインストール対象にmakeを追加する必要があります)。

FROM centos:6

ARG emacs=emacs-24.5
RUN yum install -y gcc lcurses-devel wget ncurses-devel

ARG work_dir=/tmp/setup
RUN mkdir ${work_dir}

RUN cd ${work_dir} && \
    wget http://mirror.jre655.com/GNU/emacs/${emacs}.tar.gz && \
    tar zxf ${emacs}.tar.gz && \
    cd ${emacs} && \
    ./configure --without-x && \
    make

これをビルドしてみると・・・

$ docker build --no-cache -t test-emacs-build .
~略~
Finding pointers to doc strings...
Finding pointers to doc strings...done
Dumping under the name emacs
**************************************************
Warning: Your system has a gap between BSS and the
heap (22442648 bytes).  This usually means that exec-shield
or something similar is in effect.  The dump may
fail because of this.  See the section about
exec-shield in etc/PROBLEMS for more information.
**************************************************
/bin/sh: line 7:  5952 Segmentation fault      (core dumped) ./temacs --batch --load loadup bootstrap
make[1]: *** [bootstrap-emacs] Error 1
make[1]: Leaving directory `/tmp/setup/emacs-24.5/src'
make: *** [src] Error 2

makeで死にます。

対処方法その1

とりあえず、メッセージに従ってetc/PROBLEMS(テキストファイル)でexec-shieldを検索してみます。見てみると、Linuxのセキュリティ機構であるExec-shield(プロセスのメモリ配置のランダム化?)が問題のようです。

解決方法だけ抜粋すると、下記の通りです。

    echo 0 > /proc/sys/kernel/exec-shield
    echo 0 > /proc/sys/kernel/randomize_va_space

ということで以下のようにして、「ホスト側で」一時的にrandomize_va_spaceを無効化してからdocker buildすればOKです(exec-shieldの方は無関係でした)。

$ cat /proc/sys/kernel/randomize_va_space
2
$ sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"
$ docker build --no-cache -t test-emacs-build .

emacsのビルド部分が通った後はrandomize_va_spaceを元に戻して問題ありませんでした。といっても、Emacsのビルド部分を通るたびにこれが必要なのは何かと不便そうです。

少し調査

randomize_va_spaceというキーワードが手に入ったのでGoogle先生に聞いてみると、次のissueが引っ掛かりました。

Ubuntu 16.04: Dockerfile cannot build emacs · Issue #22801 · docker/docker · GitHub

これはDocker側のissueですが、ここからEmacs側のスレッド(同じ人?)にもリンクが張られています。

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=23529

で、斜め読みしかしていないのですが、Emacsのスレッドで示されている下記コードのpersonalityというsyscallが問題になっているようです。これで、一時的にrandomize_va_spaceに0をセットするのに相当する操作をしているようですが、これがDockerのゲスト上ではうまく働かない(ホスト側を変更する必要があるのにそれができない)ということだと思います。

https://github.com/emacs-mirror/emacs/blob/master/src/emacs.c#L802-819

結局のところ、Docker側がpersonalityが動作するようなオプションを入れるかEmacs側がこの動作を修正するかですが、前者はDockerのポリシー的におそらく難しく、後者は望ましいが技術的に難しいという話になっているようです(斜め読みなので違ったらすみません)。

対処方法その2

最新版の利用や細かいバージョンの指定ができないのは残念ですが、この辺りの融通が効くのであれば大人しくRPM使っとけというのが多くの場合正しいでしょう。

個人的には24系が入ればそれで良かったので、CentOS6系であれば、「centos6.5にemacs24.5をrpmからインストールする | joppot」を参考に以下のようにすればOKでした。なお、CentOS7系であれば単にyum installするだけで24系のEmacsが入るはずです。

FROM centos:6

RUN yum install -y gcc lcurses-devel wget ncurses-devel gpm-libs alsa-lib perl gnutls-devel

RUN cd /etc/yum.repos.d && \
    wget https://gist.githubusercontent.com/AaronTheApe/5540012/raw/5782a8d6a95f76daeed6073dc0c90612fefe2fb3/emacs.repo && \
    yum --disablerepo="*" --enablerepo="emacs" --nogpgcheck -y install emacs-nox

追記(2016/08/11)

今現在は/proc/sys/kernel/randomize_va_spaceが2でも、上記の問題は起きず問題なくビルドできています。

Emacsの描画崩れの問題でDocker側を1.11にアップデートしたのですが(参考:「Dockerを1.10から1.11へアップデート on CentOS7 - eshamster’s diary」)、その影響でしょうか?ただ、上記のissueの時点では1.11.1や当時のmaster(1.12)でも再現しているようですが…。続報もないので(また、改めて1.10に戻して試す気もないので)結局良く分からないです。

一応バージョンはissueの時点よりも少し進んで、1.11.2だという差はあります。

$ docker --version
Docker version 1.11.2-cs3, build c81a77d