去年, Immutable Infrastructure という言葉を知った.
この概念を Emacs の管理に利用できないかなとという話.
これをやろうと考えたのは, 去年の 6 月だった. この記事の延長が本記事.
なかなか時間がとれなくて, 結局半年後の冬休みにようやくできた.
問題の分析
問題
Emacs を家でも会社でも利用している.以下が簡単な環境.
家
- ArchLinux
- Widows 8 (GUI 版)
会社
- Widows 7 (GUI 版)
- Windows 7 (Cygwin 版)
設定を github にあげて, 設定を共有している. 会社で設定ファイルを更新するのは社内規程的に NG なので, いつもは以下のような運用.
- 自宅で設定ファイルを git push
- 会社で設定ファイルを git pull
しかし, 自宅で設定したものが会社で動かなかったりすることがよくある.
会社で Emacs の設定ファイルを更新した後は, 朝の 30 分は毎回 Emacs と戯れているのはここだけのないしょだ.
しかし, 設定の同期作業も, 面倒なのでなんとか時間を短縮できないもの か. というのが今回の解決したい問題.
また, 1 年に 1 回 くらいの頻度で Emacs 環境を一から再構築することがある. このとき, Emacs の パッケージ管理は el-get を利用して管理しているので, 自動ですべてのパッケージを ネットから落としてきて動作するはず.
しかし, 必ず el-get のダウンロードで失敗するパッケージがたくさんでる.
会社だと, proxy という厄介なものがある. また, 設定の問題とは思うが, MELPA へアクセスできなく github からしか elisp を取得できない.
まとめると,
- 会社で Emacs の設定ファイルを更新したときに 起動時のエラーを発生させなくするためには?
- Emacs 環境を一から再構築するときに エラーを発生させなくするためには?
課題
よくあるあたふたケースは,
- 自宅の Linux 環境で push したものを 会社の windows 環境で pull して動かなくなる.
- 会社で pull をするのが怖いのでしばらく放置した後, 久しぶりに pull すると 大量のエラーが発生する.
エラーがあっても放置してしまうのは, 頻繁に エラーの確認をしないから. それは面倒だからしない. エラーの確認作業を自動化できたらうれしい.
ということで, 課題は以下.
- Linux 環境で push したら Windows 環境で pull してエラーチェックを する作業を自動化する.
- 定期的に一から Emacs の設定を再構築する作業を自動化する.
解決策
この 自動でエラーをチェックするところを Immutable Infrastracture の概念と 組み合わせたらおもしろそうだと思った. 無駄な勉強にもなるし.
Immutable Infrastructure とは
簡単に調べてみた.
一度サーバーを構築したらその後はサーバーのソフトウェアに変更を加えないこと.
以下の説明がとてもわかりやすい.
Windows って調子が悪くなると再インストールしてすっきりさせるじゃないで すか. OS にいろんなソフトウェアをインストールしたりカスタマイズしたり すると調子が悪くなりますが, 再インストールすれば戻ります.
だったら, そもそも毎回作り直せばシステムはすっきりするよね, というのが 簡単な Immutable Infrastructure の説明です.
Action Plan
以下のようなアクションプランを考えた.
- AWS 上のサーバで Emacs 環境を構築する.
- AWS 上のサーバで エラチェックーを走らせる.
- チェックがおわったらサーバを破棄して終了.
さらにこの手順の自動化ができたらいいけど, これは大変そうなので今度.
- git push したら AWS 上で動く サーバで エラチェックーを走らせる.
- 毎週深夜に, Emacs 環境を自動で構築する.
解決へのとりくみ
Windows 環境はなにかと難しいとおもったので, まずは, Linux 環境を構築することにした.
というわけで, この記事のゴールは,
AWS 上に Emacs と自分の Emacs の設定を自動でインストールすること
名づけて,
Immutable Emacs! 大作戦.
響きがとても気に入った!
AWS を借りる
別記事に独立.
ここでは, Ubuntu Server 14.04 LTS (HVM), SSD Volume Type をつかう.
ansible で Amazon AWS に SSH 接続
なれている, ansible を利用する.
mkdir -p ~/.emacs.d/playbook cd ~/.emacs.d/playbook echo ‘54.65.121.127’ » hosts
以下の作業はすべて,~/.emacs.d/playbook で実施.
ansible.cfg ファイルを作成.
[defaults] hostfile = ./hosts remote_user = ubuntu private_key_file = ~/.ssh/archlinux.pem host_key_checking = False
ping する.
ansible all -m ping -i hosts
54.64.58.11 | success » { “changed”: false, “ping”: “pong” }
ansible playbook
org-mode で書いたものは, 以下のスクリプトで yaml に変換する.
2021.11.30追記 記事壊れました.
#!/bin/sh #
-*- mode: shell-script -*- # # tangle files with org-mode # see: https://orgmode.org/manual/Batch-execution.html # DIR=`pwd` FILE=""
</p>
<p>
for i in $@; do # tangle org to yaml emacs -Q -batch -eval "(progn (add-to-list 'load-path \"/usr/share/emacs/site-lisp/org\") (require 'org) (require 'ob) (require 'ob-tangle) (setq org-src-preserve-indentation t) (find-file (expand-file-name \"$i\" \"$DIR\")) (org-babel-tangle) (kill-buffer))" 2>&1 | grep tangled
</p>
<p>
# execute ansible command to yml file string_filename=${i##*/} string_filename_without_extension=${string_filename%.*} string_path=${i%/*}
</p>
<p>
if test $string_filename = $i ; then ansible-playbook ${string_filename_without_extension}.yaml -i hosts else ansible-playbook ${string_path}/${string_filename_without_extension}.yaml -i hosts fi done [/sourcecode]
</p>
<p>
ここからは実際の ansible playbook を書く.
</p>
<ul class="org-ul">
<li>
<a href="https://github.com/tsu-nera/dotfiles/blob/master/.emacs.d/playbook/amazon-aws-ubuntu.org">https://github.com/tsu-nera/dotfiles/blob/master/.emacs.d/playbook/amazon-aws-ubuntu.org</a>
</li>
</ul>
</div>
<div id="outline-container-unnumbered-12" class="outline-3">
<h3 id="unnumbered-12">
ansible settig
</h3>
<div class="outline-text-3" id="text-unnumbered-12">
[sourcecode language="text" title=""] - - hosts: defaults sudo: yes vars: home_dir: /home/ubuntu emacs_dir: emacs dotfiles_dir: dotfiles tasks: [/sourcecode]
</div>
</div>
<div id="outline-container-unnumbered-13" class="outline-3">
<h3 id="unnumbered-13">
initial tools
</h3>
<div class="outline-text-3" id="text-unnumbered-13">
<ul class="org-ul">
<li>
libncurses5-dev は tputs error 対策
</li>
<li>
gnutls-bin for el-get
</li>
<li>
texinfo for makeinfo
</li>
</ul>
<p>
[sourcecode language="text" title=""] - name: apt-get update command: apt-get update - name: apt-get install git apt: pkg=git - name: apt-get install build tools apt: pkg=build-essential,autoconf,automake,libncurses5-dev,gnutls-bin,texinfo [/sourcecode]
</p>
</div>
<div id="outline-container-unnumbered-14" class="outline-4">
<h4 id="unnumbered-14">
bookmarks
</h4>
<div class="outline-text-4" id="text-unnumbered-14">
<ul class="org-ul">
<li>
<a href="https://gihyo.jp/admin/serial/01/ubuntu-recipe/0235">第 235 回 Ubuntu 12.04 で Emacs 24.1 を使う:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社</a>
</li>
<li>
<a href="https://emacs.tsutomuonoda.com/emacs24-1-ubuntu-install/">Emacs24.1 を Ubuntu にインストールする | Emacs の elisp インストール・設定・使い方</a>
</li>
</ul>
</div>
</div>
</div>
<div id="outline-container-unnumbered-15" class="outline-3">
<h3 id="unnumbered-15">
install emacs
</h3>
<div class="outline-text-3" id="text-unnumbered-15">
<ul class="org-ul">
<li>
<p>
<a href="https://qiita.com/seizans/items/f5f052aec1592c47767f">Ansible で git clone させる - Qiita</a>
</p>
<p>
make -j オブションをつけたら, メモリ枯渇で make が停止した.
</p>
</li>
</ul>
<p>
[sourcecode language="text" title=""] - name: get emacs from git repository git: repo=git://git.savannah.gnu.org/emacs.git dest={{home_dir}}/{{emacs_dir}} accept_hostkey=yes - name: make emacs configure file command: ./autogen.sh chdir={{home_dir}}/{{emacs_dir}} - name: make emacs Makefile command: ./configure -prefix=/usr/local -without-makeinfo -with-x-toolkit=no -without-all chdir={{home_dir}}/{{emacs_dir}} - name: make emacs command: make chdir={{home_dir}}/{{emacs_dir}} - name: install emacs command: make install chdir={{home_dir}}/{{emacs_dir}} [/sourcecode]
</p>
</div>
</div>
<div id="outline-container-unnumbered-16" class="outline-3">
<h3 id="unnumbered-16">
install dotfiles
</h3>
<div class="outline-text-3" id="text-unnumbered-16">
[sourcecode language="text" title=""] - name: clone dotfiles git: repo=https://github.com/tsu-nera/dotfiles.git dest={{home_dir}}/{{dotfiles_dir}} - name: make lnlinks command: ./make_lnlink chdir={{home_dir}}/{{dotfiles_dir}} sudo: yes sudo_user: ubuntu [/sourcecode]
</div>
</div>
<div id="outline-container-unnumbered-17" class="outline-3">
<h3 id="unnumbered-17">
install additinal tools for emacs
</h3>
<div class="outline-text-3" id="text-unnumbered-17">
[sourcecode language="text" title=""] - name: install additinal tools for pdf-tools apt: pkg=libpng-dev,libz-dev,libpoppler-glib-dev,libpoppler-private-dev - name: install additinal tools for magit apt: pkg=texinfo - name: install additinal tools for org2blog apt: pkg=bzr - name: install additinal tools for exectable-find apt: pkg=mercurial - name: install additinal tools for cmigemo apt: pkg=cmigemo - name: install additinal tools for ag apt: pkg=silversearcher-ag [/sourcecode]
</div>
</div>
<div id="outline-container-unnumbered-18" class="outline-3">
<h3 id="unnumbered-18">
boot emacs
</h3>
<div class="outline-text-3" id="text-unnumbered-18">
<p>
Emacs の boot に, el-get を利用してパッケージを次々にダウンロードする.
</p>
<ul class="org-ul">
<li>
<a href="https://github.com/tsu-nera/dotfiles/blob/master/.emacs.d/inits/00_el-get.org">https://github.com/tsu-nera/dotfiles/blob/master/.emacs.d/inits/00_el-get.org</a>
</li>
</ul>
<p>
[sourcecode language="text" title=""] - name: boot emacs first command: emacs -daemon sudo: yes sudo_user: ubuntu # - name: reboot emacs # command: emacsclient -e '(progn (defun yes-or-no-p (p) t) (kill-emacs))' && emacs -daemon # command: emacs -daemon # sudo: yes [/sourcecode]
</p>
おわりに
これで AWS 上で動く Ubuntu サーバに Emacs をインストールすることができた.
まだまだ, 改良の余地は大ありだ.まだ, スタート地点.
dotfiles を育てるように, ansible のコードも育てていきたい.