LoginSignup
19
21

More than 3 years have passed since last update.

Dockerで簡単構築!Common Lisp学習環境

Last updated at Posted at 2018-12-11

この記事では、Dockerを用いてCommon Lispの学開環境を構築する方法について書きます。

次の①〜④の流れで進めます。

 ① Dockerについて

 ② 利用するDockerfileについて

 ③ イメージの取得とコンテナの起動

 ④ Common Lisp製アプリケーションの実行

① Dockerについて

Dockerについては、以下の記事が参考になります。

・Dockerについてなるべくわかりやすく説明する / kasanaxnさん

・今更Docker入門 - コンテナ化することで何が嬉しいか / zgmf_mbfp03さん

この記事でのDockerの使い方を要約すると、docker pullでイメージのダウンロード後、docker runでコンテナの作成と起動をして、Common Lispの学習環境を構築する流れです。コンテナを起動すると、Caveman2やLem等のCommon Lisp製アプリケーションを実行することができます。

では、Dockerをインストールして次に進んでください。OSはmacOSかUbuntuを想定しています。Windowsのユーザの方は、Virtual BoxにUbuntuを入れて進めてください。

Docker for Mac のインストール手順
Docker CE for Ubuntu のインストール手順

② 利用するDockerfileについて

今回は、Alpine Linuxをベースに、Common Lispの環境構築のためにRoswell、エディタとしてLem、notebook形式の開発環境としてDarkmatter、WebアプリケーションフレームワークとしてCaveman2がインストールされたイメージを作成するDockerfileを作成します。Dockerfileはeshamsterさんのcl-baseを元に作成しました。

FROM frolvlad/alpine-glibc:alpine-3.6

ARG work_dir=/tmp/setup
RUN mkdir ${work_dir} && \
    chmod 777 ${work_dir}

# --- Roswellのインストール --- #
RUN apk add --no-cache git automake autoconf make gcc build-base curl-dev curl glib-dev libressl-dev ncurses-dev sqlite libev-dev su-exec libpq postgresql-client postgresql-dev postgresql-contrib && \
    mkdir /docker-entrypoint-initdb.d && \
    chmod +x docker-entrypoint.sh && \
    cd ${work_dir} && \
    git clone --depth=1 -b release https://github.com/roswell/roswell.git && \
    cd roswell && \
    sh bootstrap && \
    ./configure --disable-manual-install && \
    make && \
    make install && \
    cd .. && \
    rm -rf roswell && \
    ros run -q

# --- .roswell/binにPATHを通す --- #
ENV PATH /root/.roswell/bin:${PATH}

# --- Caveman, Lem, Darkmatter をインストールする--- #
RUN ln -s ${HOME}/.roswell/local-projects work && \
    ros install fukamachi/clack && \
    ros install fukamachi/caveman && \
    ros install cxxxr/lem && \
    ros install tamamu/darkmatter && \
    ros install Shinmera/dissect && \
    ros install fukamachi/qlot && \
    ros install fukamachi/utopian && \
    mv ${HOME}/.roswell/bin/lem ${HOME}/.roswell/bin/lem2 && \
    mv ${HOME}/.roswell/bin/lem-ncurses ${HOME}/.roswell/bin/lem

# --- Webアプリケーションにアクセスできるようにポートを開ける --- #
EXPOSE 8888

③ イメージの取得とコンテナの起動

では、このDockerfileでビルドしたイメージを用いて実践に移ります。

まず、Dockerを起動してください。Dockerの起動後、docker pullでイメージをダウンロードします。

$ docker pull tcool/cl-alpine

次に、コンテナの作成と起動を行います。イメージを元にcl-alpineという名前でコンテナを作成後、ホストOSのポート8888番へのリクエストをコンテナのポート8888番につなぎます。-itオプションを使うことで、シェルを対話的に実行することができます。

docker run -it -p 8888:8888 --name cl-alpine tcool/cl-alpine

④ Common Lisp製アプリケーションの実行

Roswellについて

Roswellを使うと、ros install <Githubアカウント名/レポジトリ名>でLispアプリケーションをインストールできます。試しに、JSONのエンコードとデコードを行うライブラリ Jonathanをインストールしてみましょう。

#\ ros install Rudolph-Miller/jonathan
Installing from github Rudolph-Miller/jonathan
To load "jonathan":
  Load 1 ASDF system:
    jonathan
; Loading "jonathan"
..To load "proc-parse":
  Load 2 ASDF systems:
    alexandria babel
(中略)
up to date. stop
$ 

ros runとすると、REPLを起動することができます。

#\ ros run
* 

先ほどインストールしたJonathanをREPLから利用するには、ql:quickloadでJonathanを読み込み、Jonathanの後に:コロンをつけて関数を実行します。試しに、リストをjsonにエンコードするto-json関数を使ってみます。

* (ql:quickload :jonathan)
To load "jonathan":
  Load 1 ASDF system:
    jonathan
; Loading "jonathan"
....
(:JONATHAN)
* (jonathan:to-json '(:name "Common Lisp" :born 1984 :impls (SBCL KCL)))
"{\"NAME\":\"Common Lisp\",\"BORN\":1984,\"IMPLS\":[\"SBCL\",\"KCL\"]}"

REPLで(quit)と打つと、REPLから抜けることができます。

* (quit)

また、ros use <処理系/バージョン>とすると、Common Lispの処理系、バージョンを切り替えることができます。例えば、ros install sbcl/1.2.3の後ros use sbcl/1.2.3とすると、デフォルトでSBCLのversion 1.2.3を用いるように指定できます。

以上のように、RoswellはCommon Lispの環境構築を行うために便利なユーティリティーです。

1. Lem

Lemを起動します。

#\ lem

起動後、M-x slimeでSlimeを起動します。M-xは、「escキーかOptionキーを押しながらXを押す」という意味です。次のような画面になります。
スクリーンショット 2018-12-07 21.40.31.png

Lemのキーバインドは、Emacsライクなものとvi-modeがあります。

vi-modeを利用される場合は、 ~/.lem/init.lispに次のように設定を書いてください。

(lem-vi-mode:vi-mode)

デフィルトのキーバインドはM-x describe-bindingsで確認できます。Emacsのキーバインドに慣れている方は、ほぼそのまま利用できます。C-xは、Controlを押しながらxM-xは、Esc(またはAlt)を押しながらxC-x oC-xのあとキーボードから指を離して、oを打ちます。

基本操作は、以下の通りです。

コマンド 機能
M-x lisp-mode Lisp編集モードに変更
M-x start-lisp-repl 同じプロセスでslimeを開始
M-x slime 別のプロセスでslimeを開始
C-x C-f 新規ファイルの作成、diredの起動
C-x o または M-o バッファの移動
C-x k バッファの削除
C-@ 選択開始
C-w カット
M-w コピー
C-y ペースト

Lemの使用法についてはこちらをご参照ください。

IMAGE ALT TEXT HERE

2. Darkmatter

Darkmatterを読み込み、サーバを起動します。

#\ ros run
* (ql:quickload :darkmatter)
* (darkmatter:start :server :hunchentoot :port 8888)

サーバの起動後、http://localhost:8888にアクセスすると、Darkmatterを利用できます。

as.png

Darkmatterに関する詳しい情報は、darkmatterのレポジトリをご参照ください。

3. Caveman2

最後に、Common Lisp製のWebフレームワーク「Caveman2」を使ってみます。プロジェクト雛形の生成機能を用いて、myappという名前でプロジェクトを生成します。

#\ ros run
* (ql:quickload :caveman2)
* (caveman2:make-project #P"/path/to/myapp/"
                         :author "<Your full name>")
;-> writing /path/to/myapp/.gitignore
;   writing /path/to/myapp/README.markdown
;   writing /path/to/myapp/app.lisp
;   writing /path/to/myapp/db/schema.sql
;   writing /path/to/myapp/shlyfile.lisp
;   writing /path/to/myapp/myapp-test.asd
;   writing /path/to/myapp/myapp.asd
;   writing /path/to/myapp/src/config.lisp
;   writing /path/to/myapp/src/db.lisp
;   writing /path/to/myapp/src/main.lisp
;   writing /path/to/myapp/src/view.lisp
;   writing /path/to/myapp/src/web.lisp
;   writing /path/to/myapp/static/css/main.css
;   writing /path/to/myapp/t/myapp.lisp
;   writing /path/to/myapp/templates/_errors/404.html
;   writing /path/to/myapp/templates/index.tmpl
;   writing /path/to/myapp/templates/layout/default.tmpl

サーバを起動するには、(プロジェクト名:start :port ポート番号)とします。例えば、myappというプロジェクトで8888番ポートでサーバを起動するには、次のようにします。

* (myapp:start :port 8888)

ブラウザでhttp://localhost:8888にアクセスをすると、"Hello, Caveman2!"と表示されます。

デプロイ

ここまでは、ローカルマシン上のDockerで作業を行ってきましたが、次はVPS上にDockerをインストールして環境構築してみます。ここではAWSのLightsailを用います。AWSにアカウントを作成後、次の初期化スクリプトを用いて、Ubuntuのインスタンスを作成、dockerとイメージをインストールしてください。

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates
sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt-get update
sudo apt-get install -y linux-image-extra-virtual
sudo apt-get install -y docker-engine
sudo service docker start

完了後、WebコンソールからSSH接続をして、次のコマンドを打てば、コンテナの中に入れます。

$ sudo docker pull tcool/cl-alpine
$ docker run -it -p 8888:8888 --name cl-alpine tcool/cl-alpine

ローカルのTerminalからSSHでサーバに接続するには、インスタンスの設定ページからpemファイルをダウンロードして、次のように接続します。

ssh -i <pemファイルのパス> ubuntu@http://<固定のグローバルIPアドレス>

コンテナの再起動

コンテナを停止した場合、再度ashにログインするには、コンテナを再起動する必要があります。起動中のコンテナを確認するには、docker psを実行します。

docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES

このようにコンテナが起動していないときには、docker ps -aでコンテナのIDを確認します。

$ docker ps -a
CONTAINER ID     IMAGE            COMMAND          CREATED          STATUS           PORTS                  NAMES
1d5659fdb4f3     tcool/cl-alphine   "/bin/bash"      31 minutes ago   Up 31 minutes    0.0.0.0:8888->8888/tcp cl-alpine

その後、docker start <コンテナID>でコンテナを起動します。

$ docker start 1d5659fdb4f3 

docker exec -it <コンテナ名> /bin/ashでコンテナのashにログインできます。ashを起動すると、作業の続きに戻ることができます。

docker exec -it 1d5659fdb4f3 /bin/ash 

まとめ

以上の方法を使うと、簡単にCommon Lispの開発環境を試すことができます。本番環境に適したDBやSSLの対応をしていないので本番運用では使えませんが、手軽にCommon Lispの学習環境を構築するには良いかと思います。

次回は、Docker Composeを用いてDBのコンテナと連携させながらLispアプリを運用したり、AWS Lambdaのカスタムランタイムを使ってCommon Lispの関数を呼び出したりしてみたいと思います。

19
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
21