Gentoo Linuxにxmonadを導入する
動機
Gentoo Linuxではコンパイルに時間がかかるので、大規模なデスクトップ環境を構築しようとするとすごい時間がかかる。 当方はGNOME派だが、恐らくGNOMEやKDEを入れるのは骨が折れるだろう。コテコテのデスクトップ環境を構築するのもそれはそれで一興だが、今回は敢えて軽量な環境とするためにタイル型を導入してみたいと思う。
タイル型デスクトップ環境といえばawesomeも有名だが、ここではHaskellで設定ファイルが記述できるxmonadを導入することとした。
Emerge
# emerge xmonad xmonad-contrib xmobar
依存関係を確認すると、その場でコンパイルするのでghcが必要となり、これのコンパイルにものすごい時間がかかるので、先に入れておくとよい。xmonad-contrib
はxmonad
の設定ファイルを書く際に便利なアルゴリズムが同梱されているので導入しておきたい。また、ここではステータスバーとしてxmobar
を入れることとした。
この他にもHaskellのcabalを使って導入する方法もあるが、せっかくPortageツリーに入っているのでemerge
で入れることとした。
xmonadとxmobarの相性について
xmonad上でアプリケーションを開きながらその上にxmobarを重ねる場合、設定ファイルにどう記述してもなぜか下に潜ってしまう問題が起きた。 これは0.12を使っていたからということらしい。gentooのPortageツリーに入っていた安定版の0.11を使うと解決した。
Usage
modキーをAltに割り当てると他のキーバインドと重複して厄介なので、Windowsボタンに割り当てることとした。基本的な使い方は以下が詳しい。(但し以下ではGNOMEと共存させているが、今回はxmonad単体で実行している)
http://blog.drmn.jp/2013/04/haskell-xmonad.html
参考サイト
Gentoo Linuxでうどんワールドする
tl;dr
Gentoo LinuxでPortageを使う際、
# emerge --uDNva @world
をしたときに大量に循環依存やエラーメッセージが出た場合の対処策。
まずはメッセージを読む
$ man emerge
emergeコマンドの説明(できれば英語版のようがよい)を読みながら、出力の意味を理解する。
USEフラグを立てろと言われた場合は、メッセージの通りに設定してもよいですが、私はflaggie
を使って管理しています。
maskしろと言われた場合も同様。
例:app-emulation/dockerでaufsフラグを立てたい場合
$ sudo flaggie app-emulation/docker +aufs
それとnewsを読むと役に立つ情報が手にはいります。
$ eselect news read
循環参照じたいは、メッセージで表示されるパッケージに関わるUSEフラグを適当に-gtkとか-emacsとかしておいてからemergeして片方ずつ入れれば解決することが多いです。
ghcやperlのコンフリクトを解決する
ghcやperlといったプログラミング言語本体のパッケージの更新が関わってくると、バージョンの違いによって依存するライブラリがエラーを吐くことがあります。このときは関連するライブラリは入れずに、まずはghcやperlだけを先に更新し、それからライブラリをツールを使って一括で更新する、ということでエラーメッセージを回避することができます。
@worldからやると関連のライブラリを更新しようとするためにエラーメッセージが出ることがあり、@systemをまず対象とするとエラーメッセージが出ないかもしれません。そうでない場合は個別にghcやperlを選択し、更新をかけましょう。
その後しばしば@preserved-rebuildをしろというメッセージが出るので、実行しましょう。これによってパッケージの更新によって壊れた依存関係を解決してリビルドしてくれます。
emerge -1 @preserved-rebuild
ここで-1
というフラグをつけることで、--oneshot
つまり、ここで指定したパッケージは@world
に含まずに更新することができます。こうすることで、どうでもいいパッケージの更新を追尾せずにすむので、@worldの肥大化を防げます。
その後、perlであればperl-cleaner --all
, pythonであればpython-updator
といったコマンドが用意されているので、その言語固有のパッケージの更新をかけることで、バージョンアップに伴う依存関係の再構築を行うことが可能です。
dispatch-confする
/etc/以下のファイルを、emergeによって推奨する設定に書き換えるとき、それらの作業は手動で行われなければなりません。 古い文献ではetc-updateしろと書いてある場合がありますが、dispatch-confのほうが良さそうです。
dispatch-conf の使い方 - WebOS Goodies
あとは最後に、不要となったパッケージを整理するだけです。
$ emerge --depclean
参考ページ
Gentoo Linuxでtestingブランチを使わないことにする
tl;dr
AMD64環境のGentoo LinuxにXmonadを入れるときに、一部のdev-haskellパッケージのUSEフラグで~amd64を追加するように指示された。
/etc/package/make.conf
にACCEPT_KEYWORDS="~amd64"
と指定してうどんワールド *1 してしまったせいで、次の日から大量の更新パッケージが降ってきてうどんワールドすると大変なことになった。
ACCEPT_KEYWORDS
の指定を外すと、今度は大量のダウングレードとそれに伴う依存性破損が生じて大変なことになった。従って、現行のバージョンをできるだけ維持して、今後はstableブランチを使うようにしようとした。
~amd64とは
amd64環境ではstableでないパッケージをインストールする時に用いるフラグ。
これをつけないと、Firefoxは38が最新だし(現行は45)Dockerは1.7が入ってくるし、割と悲惨な目に遭うが、testing環境ではどんどん新しいパッケージが降ってくるのでコンパイルするだけでやたらと時間をとられる。
今回の問題はグローバルに~amd64
をつけてしまったことにあり、最新のパッケージを使うぶんには良いのだが、毎日emerge
に時間をとられるのが辛い場合は、stableなブランチに戻したくなる。
応急処置
暫定的に、ひたすらmaskをかけて「現行のバージョンより古いバージョンのパッケージをemerge」しないこととした。
<app-i18n/fcitx-anthy-0.2.2 <x11-misc/xfe-1.41 <sys-boot/os-prober-1.71 <media-fonts/jp-ipafonts-003.03 <x11-libs/libdrm-2.4.67 <app-portage/layman-2.3.0-r1 <x11-terms/rxvt-unicode-9.22 <x11-terms/xterm-324
このような形で、現行のバージョン未満の値のパッケージをmaskすれば、それらのパッケージがemerge
されることはなくなるので、とりあえず今のバージョンが保たれる。さすがに全てのパッケージに対してこれを記述するのは大変なので、主立ったツールやコンパイルに時間のかかるfirefoxやghcなどを中心に指定した。
謎のvirtual/パッケージのせいで様々な依存関係が生じる
うどんワールドしたときの依存性をツリーで表示させたときに、例えばvirtual/dev-manager
がsys-fs/static-dev
を要求しているが、sys-fs/static-dev
をemergeしようとすると怒られたとする。
このときは、virtual/dev-manager
をemergeすると何が起こるか見てみることにする。/usr/portage/virutal/dev-manager/dev-manager-0.ebuild
を開く。
# Copyright 1999-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Id$ EAPI="2" DESCRIPTION="Virtual for the device filesystem manager" HOMEPAGE="" SRC_URI="" LICENSE="" SLOT="0" KEYWORDS="alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 s390 sh sparc x86 ~sparc-fbsd ~x86-fbsd" IUSE="" DEPEND="" RDEPEND="|| ( virtual/udev sys-apps/busybox[mdev] sys-fs/devfsd sys-fs/static-dev sys-freebsd/freebsd-sbin )"
ここで大事なのはRDEPENDのところで、||はorのことであるから、列挙されているパッケージのうち、どれか1つをインストールすればよいということである。
Gentooとは選択である。
今回は上から順に、ということでvirtual/udev
をemergeしてみたところ、そのパッケージは既に入っているがstableブランチよりバージョンが新しいので、~amd64
のフラグが足りないと言われた。それを付けると、今度は依存性解決がうまく行ってemergeできた。
参考ページ
*1:sudo emerge -uDN @world
Gentoo Linuxをインストールする
パーティション設定
* sda2 128M part /boot ext2
* sda3 論理パーティション
* sda5 8G swap
* sda6 96.8G part / btrfs
メモリを2GBしか積んでいないので、コンパイル時にSwap領域を使うかと思って8GBぐらい確保しておいた。 btrfsが死なないことを祈る。
インストールの流れ
- 予め他のlivecdでgpartedなどを使ってパーティションを切っておく。
- Livecdで起動し、hddをマウントしてchrootする。(手元にあったArchbootを使ったが問題なし。)
- sshdを立てて、ssh接続でインストールした。wikiをみながら作業するとよいと思う。
- locale等の諸設定をして、カーネルの設定をしてカーネルを
make
する。何度やってもよい。 - grubの設定をして(重要)、再起動してhddから起動するようにBIOSを設定する。
- 起動したらインストール自体は成功。うまくいっていない場合はchrootからやり直し。
はまったこと
- ネットワークのドライバが入っていないために、有線LANにつながらない。
- startxすると怒られる。RADEONのドライバを認識してくれない。
- 何度もライブcdからchrootし直すはめになる。
- コンパイル中は暇。
対策
カーネルの設定時に忘れずにネットワークカードを選択する。
lspci -k | grep driver
をlivecdでした際の結果と、gentoo内でした結果を比較して、足りないドライバーをカーネルのコンパイルオプションで追加する。 カーネルビルトインではなくモジュールで追加するようにすると、動かすものを明示的に指定できるためうまくいくことがある。
RADEON系のグラボを使っている場合、xf86-video-ati
を使うことになるが、その際はカーネルでbinファイルを指定しなければならない。
startxしたときのエラーメッセージに、Device(s) detected, but none match those in the config file
とかいう文が入っていたら、ドライバが正しく動いていないことがある。
amdのドライバはプロプライエタリなもの(Fglrx)とオープンソースのものがあるが、上をみるとRADEONの古いバージョンだと新しいxorgを入れられないということがわかったので、オープンソースのドライバを選択することにした。
これを読んで、カーネルの設定で正しくradeon/<YOUR-MODEL>.binを指定しなければならない。ドライバが認識されると、コンソールの解像度が適切なものになる(はず)
何度でもchrootし直すはめになる
mkdir /mnt/gentoo mount /dev/sda6 /mnt/gentoo mount /dev/sda2 /mnt/gentoo/boot mount -t proc proc /mnt/gentoo/proc mount --rbind /dev /mnt/gentoo/dev mount --rbind /sys /mnt/gentoo/sys chroot /mnt/gentoo /bin/bash source /etc/profile
その都度livecdから入り直し、上のコマンドをコピペして対応した。
うどんワールドする
ソフトウェアの更新をする際に。
# emerge -uDN @world
これで依存関係と新しいUSEフラグを含めて、アプリケーションをすべて更新できる。俗に言う「うどんワールド」である。
参考ページ
syusui.tumblr.comなんだかんだarchwikiは頼りになる。
Dockerでサーバーを立てる(2)
それでは実際に、Docker-composeでRailsアプリを立てるところまでやってみたいと思う。
構成
今回のdocker-compose構成は以下である。
supervisordで1つのコンテナに全て立てるのはやはりdockerの原則に反していると思うので、原則として1プロセス1コンテナとした。 まずデータコンテナを置いて、そこにlogを取っておいて各コンテナをマウントするのはデータ永続化の手法としてしばしば用いられるらしい。 mysqldを立てていないのはsqlite3を使っているためである。sqlite3のファイル自体はデータコンテナに格納できていると思われる(?) やはりsqlは別コンテナに立てるべきだと思うので今後、改善したい。
unicornではなくpumaを使う
リバプロとしてnginxを立てる以上、スロークライアントとの通信はリバプロが引き受けるためにunicornの弱点であるプロセスの専有は防げるらしいので、pumaをアプリケーションサーバーとする必要はないらしい。だが敢えてnginx+pumaで立ててみる。
ちなみにこのエントリが、アプリケーションサーバーの機構についてまとめてあり参考になる。Unicornはマルチプロセス(prefork)型だが、Pumaはマルチスレッド型(スレッドプール)とマルチプロセス型のhybridだそうだ。但し、Rubinius or JRubyを使うことが推奨されている。今回はMRI上で動くアプリだが、TwitterAPIを叩くようなBlocking I/Oを呼ぶようなことはないので使っても大丈夫だろうという判断である。
実際のソケットの設定方法などはunicornを使ったパターンが多く、情報が少なく苦労したがこのあたりを調べた。
Arch linuxによるnginxサーバーを立てる時の注意点
既存のnginxイメージを使ってもよいのだが、せめてこれぐらいはArch linuxで立てたいと思ってDockerfileを記述した。
RUN \ pacman -Syu && \ pacman -S nginx --noconfirm ADD ./nginx.conf /etc/nginx/nginx.conf VOLUME ["/etc/nginx/sites-enabled", "/etc/nginx/certs", "/etc/nginx/conf.d", "/var/log/nginx", "/var/www/html"] WORKDIR /etc/nginx EXPOSE 80 ENTRYPOINT /usr/sbin/nginx -g 'daemon off;'
この中で、
ADD ./nginx.conf /etc/nginx/nginx.conf
の部分が厄介で、Arch linuxのnginxでは/etc/nginx/nginx.conf
にinclude /etc/nginx/conf.d/*.conf;
という記述がないので、そのままでは/etc/nginx/conf.d/nginx.conf
などに設定ファイルを記述したところで自動で読み込んではくれない。そこで、もとの/etc/nginx/nginx.conf
を手元のファイルで上書きする必要があるのだ。
結論:自分でDockerfileをフルスクラッチで書こうとするより、先駆者のものを参考にするのがよい。
実行
Dockerfile, docker-compose.ymlがアプリのルートディレクトリに置いてあって、Arch linuxによるnginxサーバーのイメージは予めbuildしてあることとする。
$ docker-compose up -d
これで、コンテナをcreateして実行してくれる。Dockeruiによる管理をしていれば、webui上で正常に動作しているかどうかを確認できる。
その後、dbのmigrationは実際に内部に入って行う必要がある。
$ docker exec -it app bash # bundle exec rake db:migrate
$ docker-compose down
これでコンテナを消せるので、失敗したものはどんどん消していくとよいと思う。
参考ページ
cross-originでiframeが埋め込めないとき
What I want to do
あるサービスをwww上で展開しているのだが、元のドメインのURLをそのまま晒すのがちょっと嫌なのでそれを隠すためにurl-forwardingをしたい。
tkドメインを試す
*.tkとかいうドメインはタダで手に入る。(但し有効期限がある) 登録画面は割と癖のある挙動。登録から割り当てまで時間がかかるので注意。メアドを登録せずに匿名でも登録できるのがウリか。信頼性は低そう。 無料版の範囲だとhttps対応していない。
これでURL-forwardingを試してみたが、やっていることはforward先のurlをiframeで埋め込むことだった。 但し、あるサービスはX-Frame-Options:SAMEORIGINであったので、このままではcross-originエラーが出て何も表示されない。
URL-forwardingといっても結局はforward先のurlをiframeで埋め込むのであれば、わざわざ独自ドメインをとらなくてもどこか信頼性の高そうなドメインにホスティングすればよいということになった。
動的にiframeを埋め込むようにする
人力検索はてなでも質問がされていた。
が、Stackoveflowが解決策としては一番わかり易かった。
cross-originを外すために、以下のサイトを媒介する。
An open source alternative to AnyOrigin
このサイトにパラメータとしてurlを渡すと、html部分を含んだ結果をJSON形式で取得できるので、コールバックでcontentsだけを取得して、divに注入するようにすればよい。ただしリンクは元のドメインのURLのままなので、このページからのリンクもそれぞれ静的なページで用意して、……としない限りはリンク先がおかしいぞ、となってばれてしまう。(もちろんソースコードを見れば一発だけれど) さすがに全ページを静的なページでプロキシするのは現実的でないので、トップページだけiframeの埋め込みでごまかすことで妥協しようと思う。
Dockerでサーバーを立てる(1)
はじめに
様々なところで語られていますが、Dockerはコンテナ型のサーバー仮想化のエコシステムとして知られている。ここでは、DockerでRailsアプリを立てることを目標とする。
大まかな概略をつかむには以下のページが参考になった。
Dockerについての調査まとめ、基本機能+主な特徴+Vagrantの連携 あたり · GitHub
細かなtips
具体的な構成は次に譲るとして、ここでは細かいtipsや周辺技術を書き留めておくこととしたい。
モニタリング
モニタリングツールは群雄割拠していてどれを選ぶかは難しいが、ここでは
これを利用して、コンピュータ上でどのコンテナが立っているかをモニタリングする。
docker run -d -p 9000:9000 --privileged -v /var/run/docker.sock:/var/run/docker.sock dockerui/dockerui
一度立てた後は
docker start dockerui
で起動可能。
コンテナ内に入る
docker exec -it nginx bash
supervisordを使う
本来のdocerは1コンテナ1プロセスが基本ですが、複数プロセスを立ち上げたいことがあるかもしれません。 そのときにこれを使います。
実際にそれを使ってRoR4のコンテナを立ち上げた例がこちら。
データボリュームについて
しばしばbusyboxなどでデータボリュームコンテナを立てて、その上にマウントした設定ファイルやログ用のフォルダをsqlやnginxなどのコンテナで共有するパターンがあります。こうすることで、ログ等を永続化できます。
そのとき、dockerコマンドのオプションをどう設定するかのtipsが、以下にまとまっています。
sshdを立てる
dockerでsshdを立てることはどうなのよ、という意見もありますが、立てている例があります。
gentoo/stage3-amd64でemergeする
docker run -v /home/#{name}/gentoo:/usr/portage/ -it gentoo/stage3-amd64 bash
みたいにすれば、emergeコマンドによるrsyncを永続化できます。これでDocker上で手軽にGentoo LinuxのPortageシステムを体験することができます。
DockerでMattermostサーバーを立てる
自前のサーバーでSlack, Hipchat系のチャットサービスを使いたいと思った時に。Golang製。
立ててみる
Local Machine Setup and Upgrade — Mattermost 2.0 documentation
docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform
http://localhost:8065/にアクセス。それ以後は一回立てた後はこれでOK。
docker start mattermost-dev
他のチャットサービスとの比較
slack
みんな大好きSlack。日本のスタートアップ企業でも圧倒的シェアを誇っています*1。
Slackではできるけど現段階のバージョンでのMattermostでできないこと。
- slackbotみたいな存在がない。
- snippet, postを貼れない。
- htmlを入力してもogが表示されない。
- スラッシュコマンドが乏しい。
- Androidネイティブアプリがまだ正式リリースされていない。
Rocket.Chat
デモは以下。
こちらはjsフレームワークのMeteor製。Meteorには割と注目しているのだが、若干洗練されていないデザインであるという印象。
トラブルシューティング
このサーバーで実際に複数人が接続して試してみたときの備忘録です。
- 他のユーザーが登録できない!
- 最初のユーザーはteamを作るときに登録できますが、そうでないユーザーはチームの画面に行ってもsign upできずに何もできません。実は招待urlから入るしかないので、最初のユーザーはメニューからInviteを選択しましょう。
- 最新版にアップデートしたい!
- 公式ドキュメントによれば、これはPreview版にすぎないため一度dockerイメージを削除してからpullするしかないようです。もちろんデータは全部消えてしまいます。
- 日本語のUIがない
- Slackも同じなのでがんばりましょう。
- Admin Consoleでユーザーの権限を誤ってSystem_adminから格下げしてしまった!
- これを一度してしまうと、System_adminでないとユーザー権限を変更できないので、二度とAdmin Consoleにログインできなくなり、設定を戻せなくなって詰みます。
しかも、docker内にはplatformというバイナリがあって、それを用いて本来はユーザーの権限が変更できそうなのですが、docker exec
で中に入ってバイナリを実行しようとしても動かなくなります。というわけで、一度dockerイメージを削除して立ち上げ直しました。
インターンシップを終えて
IT系のインターンシップに1週間ほど行っていたので、感想を簡単に記す。
概観
求められる水準は高く、仕事中は常に頭脳をフル回転させていなければならなかった。そのためインターンシップの期間中は全くといっていいほど、それ以外のことに手がつけられなかった。寝まくったがいくら寝ても体力が回復せず、自らのバイタリティーの乏しさを感じた。
学んだこと
- Macの使い方
- gitの活用。プルリクとイシューの立て方
- GitHub Frow による開発
- Ruby on Railsの開発、きれいなコードの書き方
- Atomの使い方、Slackを使ってみた
- Rspecの書き方(web mocksによるスタブの活用)
- フィーチャーテストの書き方
- Hamlの書き方
- Coffee scriptの解読
- APIの叩き方。アクセストークンの設定方法
- Active recordのクエリの書き方
- 大規模サービスを影で支える人たちの存在
更に学んでいること
今後の展望
Devise, Rake, Redisへの理解を深める必要がある。 特にRakeコマンドは、単なるおまじないとしての取り扱いが大きかったように感じるので、使いこなせるようになりたい。 Coffee scriptぐらいは書けるようになりたい。 Atomは大きいデータを扱い出すと途端に重くなり、ハングアップすることがあるので、やはりvimに戻ろうかと思う。
インターン中に読んだ本
Unix哲学に触れた。1つのプロセスが1つだけのことをするのが良いというのはDockerの思想ともつながっており、とても興味深かった。
- 作者: Mike Gancarz,芳尾桂
- 出版社/メーカー: オーム社
- 発売日: 2001/02
- メディア: 単行本
- 購入: 40人 クリック: 498回
- この商品を含むブログ (142件) を見る
Python2を高速化するtips(続)
これの続き。
単純に高速なアルゴリズムを使う
例えば"ham"という文字列がある配列に含まれるか?という問いに対して、
some_list = ["spam", "ham", "eggs"] if "ham" in some_list
というリスト検索ではO(log(n))ですが、RubyにおけるHashと同様のものがPythonでも辞書(Dictionaly)として提供されており、
some_dict = {"spam":1, "ham":1, "eggs":1} if "apple" in some_dict
とすればO(1)になります。もちろんこれが使えるのには条件がありますが、これで数秒程度早くなりました。
並列計算する
pythonの律速となっているのはだいたいfor文であり、このfor文の実行回数をいかに減らせるか、ということがポイントとなります。 並列計算には、スレッド並列化(メモリを共有する)とプロセス並列化(メモリを共有しない)の2種類があります。しかしCPythonの実装ではGIL(Global Interpreter Lock)というものがあるので、プロセス並列化ぐらいしかできません。
GILとは、並列実行したときに安全でないコード(例えばグローバル変数を書き換えるような、スレッドセーフでないコード:しばしばCのモジュールに存在する)を実行しないようにするために、そのコードを他のスレッドで呼ばれないようにする排他ロックのことで、pythonやrubyといったインタプリタ言語では一般に1つのプロセスに対して1つのGILが存在する。
GILがない実装としてJPython(JAVAによる実装)やIronPython、PypyのSTM版があげられますが、ここでは措きます。
CPythonでプロセス並列化によって高速化するには、for文の区間を分割して部分和を並列で計算し、あとでその総和をとるという手段が用いられます。しかしCのopenMPのように動的にfor文の処理をスレッドに割り当てるといったことは標準では用意されていないので、自分で実装するなりする必要があります。
Boost.pythonを使う
結局pythonで計算させるには限界があるので、C++で書いたコードをコンパイルしたものを共有ライブラリとしてpython側から呼び出す実装にしてみましょう。
#define BOOST_PYTHON_STATIC_LIB #include <boost/python.hpp> static void image_putpixel(image &i, const boost::python::tuple &x, const boost::python::tuple &y){ double point[2] = {boost::python::extract<double>(x[0]), boost::python::extract<double>(x[1])}; uchar color[3] = {boost::python::extract<uchar>(y[0]), boost::python::extract<uchar>(y[1]),boost::python::extract<uchar>(y[2])}; i.putpixel(point, color); } BOOST_PYTHON_MODULE(brush) { using namespace boost::python; class_<image>("image") .def("show", &image::show) .def("brush", &image_brush) .def("putpixel", &image_putpixel) .def("load", &image::load) .def("get", &image::get); }
上記でわかるように、C++のクラスをpythonのクラスにみなせたり、pythonのtupleを引数としてとるような関数を定義することができます。
g++ -std=c++11 -O2 -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'` -DPIC -fPIC -shared -o brush.so src/brush.cpp -lboost_python
-Iにインクルードパスを指定したいのですが、そのパスが異なるコンピュータ上でも共通に実行できるように、``でpythonを実行するコードを囲うことでそれをシェル上で評価した結果が返ってきます。
python側からは、soファイルを同じディレクトリに置いてファイル名でimportすればOKです。さらに、openMPで実装したC++のコードをpython側から呼び出すこともでき、さらに速度が上がる可能性もあります。