Nextremer Advent Calendar 2017 14日目の記事です
Lispという言語に皆さんは触れたことがあるでしょうか?
「神の言語」とも言われるLisp、プログラマーであれば一度は気になったことがあるんじゃないでしょうか
NextremerにはLisperのメンバーが若干名おり、そのお陰で最近はたまにNextremerのオフィスでLispの勉強会であるShibuya.lispが開催されたりしています
私自身は今まで一度もLisp系の言語をちゃんと勉強したことがなかったんですが、会社のslackでうっかりCommon Lispやってみたいてきなことを呟いたらLisperの方々が反応してくれました
このやり取りをきっかけに、最近じわじわと社内でCommon Lisp熱が高まりつつあります
Common Lisp を使おう!
Common Lisp環境のセットアップ、Hello world的な解説や基本的な構文などを@t-sinさんが記事にまとめられています
とてもわかりやすく参考にさせていただきました!
いまから始めるCommon Lisp
Dockerイメージを作ろう!
Nextremer内の自称Dockerエバンジェリストとしては、何か新しいアプリケーションを開発するときに何でもDockerにしてしまいたい欲望があります
RoswellとSBCLをインストール済みのDockerイメージを作ってDocker Hubにアップしました
・Docker Hub
https://hub.docker.com/r/chanmoro/docker-roswell/
・githubリポジトリ
https://github.com/KazukiMorozumi/docker-roswell
WebAPIを作ってみよう!
先ほども紹介した@t-sinさんの記事で紹介されているWebAPIと同じものを実装して、Dockerコンテナ内で動かしてみます
ソースコード一式は以下に置きました
https://github.com/Chanmoro/commom-lisp-webapp-example
このリポジトリをクローンして $ docker-compose up
を実行するとWebサーバーが起動します
初回の実行は各種ダウンロードで少し時間がかかります
起動した後は localhost:5000 で以下のようにアクセスできます
$ curl localhost:5000
Hello CL with Docker!
$ curl localhost:5000/post/list
[{"ID":1,"TITLE":"記事1","DATE":"2017-01-01","TAGS":["tag1","tag2","tag3"]},{"ID":2,"TITLE":"記事2","DATE":"2017-01-02","TAGS":["tag2","tag3"]},{"ID":3,"TITLE":"記事3","DATE":"2017-01-03","TAGS":["tag1","tag3"]}]
$ curl localhost:5000/post/id/1
{"ID":1,"TITLE":"記事1","DATE":"2017-01-01","TAGS":["tag1","tag2","tag3"],"BODY":"本文1本文1本文1本文1"}
コード自体は特に困ったところはなかったんですが、Dockerイメージを作るのにちょこちょこ細かいところでハマったので以下にまとめます
Dockerコンテナ化する際にハマった点
WARNINGが出る
ビルド時や ros
コマンドの実行時に以下のようなWarningが出ます
WARNING:
Couldn't re-execute SBCL with proper personality flags (/proc isn't mounted? setuid?)
以下のwikiにこれについての対応方法が書かれていました
https://github.com/dimitri/pgloader/wiki/Running-in-Docker-(SBCL-warning)
どうやらなんらかのシステムコールを実行する必要があり、Dockerのセキュリティ機構の seccomp
を無効にするか、システムコールを実行する許可の設定をすることで該当のWarningが消えます
https://github.com/daewok/slime-docker/blob/master/resources/docker-sbcl-seccomp.json
seccompを設定する際は以下のように --security-opt
オプションで指定します
docker run -it --security-opt seccomp=./docker-sbcl-seccomp.json chanmoro/docker-roswell bash
seccompの設定をしなくてもビルドは成功しますし、その後の処理も動くので無視したままでも動作はするようでした
※そもそものWarningの内容をよく理解していないので、今後問題になるようだったら詳細調べてみるかもです・・・
Common Lispのソース内に日本語があるとエラーになる
無事Dockerイメージがビルドできたと思ったら、今度はAPIサーバーの実行時に以下のようなエラーが出ました
:ASCII stream decoding error on
#<SB-SYS:FD-STREAM for "file /app/app.lisp" {1003857E83}>:
the octet sequence #(232) cannot be decoded.
何らか文字コードが関係していそうで、いろいろとググるとどうやらlocaleが関係していそうでした
今回ベースに利用しているubuntu 16.04のイメージは、デフォルトの状態だとlocaleはこのように POSIX
が設定されています
# locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="
この状態だとエラーとなるので、aptでlocales
をインストールしDockerfile内で以下のようにlocaleにen_US.UTF-8
をセットすることで日本語のエラーが解決しました
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
Common Lispの各種パッケージをどのタイミングでインストールしたらいいかわからない
コンテナを気にせず普通に実行する場合はapp.lisp
内の以下のようにquickload
を利用するとライブラリのダウンロードが自動で行われます
(ql:quickload '(:ningle) :silent t)
(ql:quickload '(:jonathan) :silent t)
しかし、Dockerイメージ化する上では各種ライブラリがダウンロード済みの状態のイメージを作りたいです
結果として以下のようにDockerfile内でライブラリを読み込んでダウンロードするようにしました
RUN echo 'install libs' \
&& ros -s ningle \
&& ros -s jonathan
この悩みを弊社のLisperである@gos_kさんに聞いてみたところ、以下のリポジトリを教えてくれました
https://github.com/Rudolph-Miller/dockerfile-clack/blob/master/Dockerfile
さらにros -e "(ql:quickload :hoge)"
のようにコードを実行する方法ではなくros -s hoge
としてquickloadだけ実行するのがナウいと教えてくれたのでこの方法を使いました
みんなでCommon Lispしよう!
さて、今回はCommon Lispで実装したWebアプリケーションをDockerで動かそう、というのにトライしました
これでポータビリティーも最強になったので、Common Lispで実装したソフトウェアを思う存分投入できますね!
まだまだCommon Lispを触り始めたばかりなので分からないことだらけですが、今後も引き続き勉強させていただきます!
あまりLisp系言語やCommon Lispについてゆるふわなことばかり言っていると、どこかからマサカリが飛んで首を持っていかれそうな気がするので、初心者はこのあたりで黙っておきます