読者です 読者をやめる 読者になる 読者になる

Common Lisp開発環境 on Docker

Docker上でCommon Lisp開発環境(by Emacs+SLIME)を起こしてみました。何が入っているか分からない開発環境だとどうしてもアップデートが億劫になるので、その辺をきっちりコード化したかったというのが動機です。

どちらかと言うとAnsibleやChefのように直接サーバを設定するタイプの方がこの用途ではスタンダードな気がします(単なる印象)が、Dockerの方が試行錯誤で出るゴミ*1が残らないので好みでした。

注意点

執筆時点(2016/08/11)では、CentOS 7のyumではDocker 1.10が入りますが、事実上1.11以上が必須です。1.10ではEmacsの描画が激しく崩れるという問題があるためです(参考の前回記事:Dockerを1.10から1.11へアップデート on CentOS7 - eshamster’s diary)。

また、Dockerfileからビルドする場合にも必要な可能性があります。Emacsのビルド部分で詰まる可能性があるためです(参考の前々回記事:Docker上のEmacsのビルドでハマった話 - eshamster’s diary)。どういう訳か1.11.2では参考記事の問題は起きていないので、1.11にしておくとスムーズ…かもしれません*2

概説

まずは作ったものへの諸リンク*3

元々は以前書いた記事「Common Lisp開発環境を新規に作ったのでメモ - eshamster’s diary」をそのまま再現してCentOS 6ベースで作った(1.0~1.3)のですが、Clozure CLの最新版が入らないなど問題しかないので、CentOS 7をベースに作り直しました(2.0~)。やっていることは変わらないので気になった部分だけメモ。

  • CentOS 7化周りの話
    • 一番困った点はw3mのインストール(emacsからのHyperSpec閲覧用)です。標準リポジトリからなくなったので、ソースからビルドが必要ですが、単純にはできません。「[CentOS7] emacs24にemacs-w3mインストール - Qiita」にあるように細工が必要です
      • もうサポートしないということかと思うので、移行先を探すのが正道ですかね…
    • roswellのビルドには標準リポジトリのautoconfで十分でした
      • roswellのバージョンを固定した方がいいか迷いどころですが、適宜最新化しながら使う予定なので都度対応で良いかなと
    • Emacsは24系であればいいので、CentOS 7ならyumでいいはず…と思っていたら、yumで入る24.3では動かないEmacs拡張(どれかは忘れました)がありました。そのため、結局ソースから24.5を入れました
      • 探した範囲ではCentOS 7用の24.5のrpmは見つからなかったので、ソースからのビルドという手段を塞がれた場合CentOS 6より厄介かもしれません…
  • その他の話
    • ビルド時点でsbcl, sbcl-bin, ccl-binを入れていますが、コンテナの容量が膨らむので微妙かもしれません…
    • 同じく容量が膨らむのでEmacs拡張をインストールするためのRUN emacs --batch --load .emacs.d/init.elも…

実際に使うとき

実際に開発に利用する上ではeshamster/cl-develだけでは不足です。GitHubにpushするためのSSH鍵の設定や、コンテナ終了後もデータを残すためのボリュームの設定等が必要です。とはいえ、こうしたパーソナルな設定を公開Dockerfileに書くのも違う気がします。

そのため、下記の3ファイル(Dockerfile, 設定ファイルのsetenv, 起動用のrun.sh)とSSH*4を用意し、run.shを叩いてコンテナを起こしています。なお、ホストのマウント先に指定した${HOME}/work/lispは事前にchown -R 1000:1000 ${HOME}/work/lisp*5と所有者設定をしておかないとゲスト側から触れません。

run.shでコンテナを起動した後は、emacsを立ち上げ*6M-x slimeですぐにslimeが使えます。保存の必要なものは~/work/lisp以下に保存します。また、コンテナをdetach*7した後は、docker attach clで再接続できます(プロセス名clsetenvで設定)。

  • Dockerfile
FROM eshamster/cl-devel:2.0

# --- git settings --- #
RUN git config --global user.name "<ユーザ名>" && \
    git config --global user.email "<メールアドレス>"

# --- ssh settings --- #
ARG user=dev

ARG SSH_HOME=/home/${user}/.ssh
RUN mkdir ${SSH_HOME} && \
    chmod 700 ${SSH_HOME}

USER root
COPY id_rsa ${SSH_HOME}
COPY id_rsa.pub ${SSH_HOME}
RUN chown ${user}:${user} ${SSH_HOME}/* && \
    chmod 600 ${SSH_HOME}/*

# --- other settings --- #
USER ${user}
RUN ros install prove
RUN echo "export PATH=${HOME}/.roswell/bin:${PATH}" >> ${HOME}/.bashrc
RUN echo "export LANG=ja_JP.UTF-8" >> ${HOME}/.bashrc
  • 設定ファイル(setenv)*8
export HOST_PORT=17380
export GUEST_PORT=18616
export RUN_NAME=cl
  • 起動用シェル(run.sh)
#!/bin/bash

set -eu

. "${1:-$(dirname ${0})/setenv}"

docker rmi $(docker images | awk '/^<none>/ { print $3 }') || echo "ignore rmi error"
docker rm `docker ps -a -q` || echo "ignore rm error"

docker build -t cl .
docker run --name=${RUN_NAME} -p ${HOST_PORT}:${GUEST_PORT} -e "OPEN_PORT=${GUEST_PORT}" -e "HOST_PORT=${HOST_PORT}" -v ${HOME}/work/lisp:/home/dev/work/lisp -it cl /bin/bash

感想

上記の環境が整ってしまえば、後はrun.shをたたくだけで簡単にフレッシュな環境が得られるので良い感じです(気づいたら環境が壊れて色々動かなくなった…となってもすぐ戻せますし)。しばらく使ってみましたが、Dockerを1.11にアップデートしてEmacsの描画問題が解決してからは快適に利用できています。


*1:実はそのゴミ(だと思っていたもの)のおかげで動いていたとか、設定に書いていない元々入っていたもののおかげで動いていたとか、心配性なのでその辺りがどうしても気になります…

*2:曖昧な言い方になっているのは、きちんと調査できていないためです。本当に1.11にアップデートしたことで解消されたのか半信半疑です…

*3:DocekrHubとGitHubの連係機能を後から知ったので連係できていないという…。後からできるのでしょうか

*4:.pubの方は必須ではないですが、一緒に持っておかないと対応が分からなくなりそうなので…

*5:設定すべきID(ここでは1000番)はゲスト側で/etc/passswdを見れば確認できます

*6:最初からrun.shで/usr/bin/emacsを立ち上げても良い気がします。Emacsの走る環境も触れた方が良いかと思い、/bin/bashで立ち上げています

*7:なお、Dockerの初期設定ではdetachがCtrl-P Ctrl-Qという正気とは思えないキーバインドになっているので、「docker-1.10.0からデタッチキーが変更できるようになった - Qiita」あたりを参考に変更しましょう。Ctrl-Pはないよなあ…

*8:portの設定は必須ではないですが、Webアプリケーションを開発するような想定でつけています。ゲスト側ではGUEST_PORTで接続を待ち受け、つなぐ側はホストのHOST_PORTに繋ぎます