Emacs のために Docker-Toolbox for Windows を使う話


動機

GCEの操作のためにWindows上で上手いこと動くEmacsが欲しい!

とある理由でGCEを用いる必要があったのですが、ssh接続をするターミナル環境があったほうが便利なので、それならEmacsを使おう となりました。
しかし直接 Windows で動かすと色々不便なことが多いので下地にLinuxが欲しくなり、結果以下の選択肢が得られました。

  • Bash on Ubuntu や WSL を使う
  • Docker を使う

 しかし前者は既に別の目的(主にWindowsのファイル操作とOrg-modeを用いたレポート作成)でEmacsを使っているため、別の環境が欲しいなぁとなり後者を採用することになりました。

Docker-Toolbox for Windows のインストール

さて Docker を使うにあたって、私は仮想環境関連では Virtual Box をメインに使っているので Docker-Toolbox for Windows というツールを使って Docker そのものを整備しました。

基本的にインストールするだけなので難しいことはないと思いますが、参考文献として こちら を挙げさせて頂きます。

インストールが終わったらならば、念のためにこの確認を行いましょう。Docker Quickstart Terminal 或いは Powershell を開き、以下のコマンドを実行して下さい。

$ docker run hello-world
;; You may see the message like ``Hello from docker''.

Hello from docker みたいな出力が得られれば成功です。

Docker ファイルを書く

Emacs に欲しい機能を考える

環境を作る前に何が欲しいのかを考えます。今回は

  1. GCE上の計算機にアクセスし、ファイル操作等をしたい
    => Emacsに標準搭載の tramp-mode 等を使う
  2. Github上の自分の(プライベートを含む)レポジトリにアクセスしたい
    => ssh 鍵の共有をする
  3. かっこいいGUI環境
    => doom-emacs を使う
    => MobaXterm を使う
    VcXsrvではEmacsが上手く動きませんでした
  4. 軽いサイズ
    => OS に ArchLinux を使う

の4つが焦点となりました。

Dockerfileを書く

何が必要なのかはっきりしたところで Docker ファイルを書いていきます。恥ずかしながら初めて書きましたので、至らぬ点があるかもしれませんが以下の通りです。全体はこのレポジトリにあります。

Dockerfile
FROM archlinux/base

# basic settings for archlinux
RUN pacman --noconfirm -Sy pacman-contrib \
 && cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.backup \
 &&  rankmirrors -n 6 /etc/pacman.d/mirrorlist.backup > /etc/pacman.d/mirrorlist \
 && echo -e "[multilib]\nInclude = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf \
  && pacman -Syyu --noconfirm base base-devel git openssh wget which emacs gtk2 tmux python3 noto-fonts-cjk
###
### RUN   sed -i "s/PermitRootLogin prohibit-password/PermitRootLogin yes/" /etc/ssh/sshd_config
###
RUN echo -e "en_US.UTF-8 UTF-8\nja_JP.UTF-8 UTF-8" > /etc/locale.gen && locale-gen \
 &&  ln -fs /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
 && useradd -m -r -s /bin/bash emacs && passwd -d emacs \
 && echo "emacs ALL=(ALL) ALL" > /etc/sudoers.d/emacs \
 && mkdir /home/emacs/works \
 && chown -R emacs:emacs /home/emacs

# switch user
USER emacs

# installation for yay and mozc
WORKDIR "/home/emacs/works"
RUN git clone https://aur.archlinux.org/yay.git
RUN git clone https://aur.archlinux.org/mozc.git
WORKDIR "/home/emacs/works/yay"
RUN makepkg  --noconfirm -si \
  && yay --afterclean --removemake --save
WORKDIR "/home/emacs/works/mozc"
RUN sed -ie "s/#_emacs_mozc=\"yes\"/_emacs_mozc=\"yes\"/" PKGBUILD \
  && sed -ie "s/_ibus_mozc=\"yes\"/#_ibus_mozc=\"yes\"/" PKGBUILD \
  && sed -ie "s/'ibus>=1.4.1'\ //" PKGBUILD \
  && makepkg --noconfirm -si

# settings for doom-emacs
WORKDIR "/home/emacs"
RUN git clone https://github.com/hlissner/doom-emacs /home/emacs/.emacs.d
COPY doom /home/emacs/.config/doom
RUN sudo chown -R emacs /home/emacs/.config/doom
WORKDIR "/home/emacs/.emacs.d"
RUN git checkout develop \
  && bin/doom -y -p ~/.config/doom quickstart \
RUN rm -r /home/emacs/works/*

COPY docker-entrypoint.sh /home/emacs/works
RUN sudo chmod +x /home/emacs/works/docker-entrypoint.sh \
  && mkdir /home/emacs/mnt
ENTRYPOINT ["/home/emacs/works/docker-entrypoint.sh"]

basic settings for archlinux のブロックは archlinux のインストールの基本的な部分です。RUN sed -i "s/PermitRootLogin prohibit-password/PermitRootLogin yes/" /etc/ssh/sshd_config は、ホストからこのインスタンスへssh接続したい際に必要になりますが、今回は必要なさそうなのでコメントアウトしています。
switch user ではユーザ emacs を作成しています。

installation for yay and mozc では archlinux のパッケージ管理ツール yay と 日本語入力のための mozc をインストールします。mozcに関しては少し面倒で、PKGBUILDというビルドファイルを調節しています。

settings for doom-emacs は doom-emacs をインストールしており、公式の指示に従っています。しかし、bin/doom quickstart bin/doom refresh に関しては org-mode 関連のインストールを行う部分が事故を起こすせいで docker build 中に止まってしまうことが稀にあるのでこの記事を書いた時点で上手くいくようにこねくり回しています。また doom-emacs の設定に関しては自由にできた方が良いだろうということで、外部の doom フォルダに置きました。この設定はインスタンス作成毎に調整しようと考えています。

最後に docker-entrypoint.sh というファイルを持ってきてこれを ENTRYPOINT にしていますが、これがGUI環境を作る要になっています。

docker-entrypoint.sh
#!/bin/sh
set -e

cp -R /tmp/.ssh /home/emacs/.ssh
chmod 700 /home/emacs/.ssh
chmod 644 /home/emacs/.ssh/id_rsa.pub
chmod 600 /home/emacs/.ssh/id_rsa
exec /bin/bash

外部からマウントしてきたフォルダ /tmp/.ssh にはホストの ~/.ssh が該当します。これを /home/emacs/.ssh に移すことによってホストとssh 鍵を共有することができます。
標準でこの .ssh フォルダは所有者が root となっているので、その下の chmod で所有権の変更を行っています。

Docker instance を建てる

以下のファイルを実行することで instance を立ち上げます。

run_emacs.sh
#!/bin/bash
if [ $# -ne 2 ]; then
    echo -e "Please input \nyour ip-addr:port for display (see. your MobaXterm)\nyour ssh folder (ex. /c/Users/<yourname>/.ssh)" 1>&2
    exit 1
fi

docker run -e DISPLAY=$1 -v $2:/tmp/.ssh -v /:/home/emacs/mnt -it --rm arch-doom-emacs

これで .ssh フォルダと ホスト全体がマウントされます。
MobaXterm を走らせた後、Docker Quickstart Terminal からコードを実行してみましょう。

/...$ git clone https://github.com/MokkeMeguru/arch-doom-emacs
/...$ cd arch-doom-emacs
/.../arch-doom-emacs$ docker build -t arch-doom-emacs .
/.../arch-doom-emacs$ sh run_emacs.sh [ip-addr]:[port] [path-to-your-ssh-folder]
[emacs@--- ~]$ emacs

emacs が立ち上がりましたが、all-the-icons が機能していないので、M-x all-the-icons-install-fonts で icon をインストールします。一旦 SPC q R で再起動します。

これでうまくいきました。
念の為 scratch buffer で日本語を入力してみます。

こんな感じです。

追記

ところでこの doom-emacs キーバインドの説明などの情報が spacemacs に比べてかなり少ない気がするんですがどうなんでしょう。

=> なので、Spacemacs版も作成しました