sshrcで環境を汚さずにサーバの .bashrc .tmux.conf .vimrc 等をカスタマイズする

複数人で管理している本番サーバの環境をオレオレカスタマイズしてる人はいないと思うが、デフォルトのままだと使いにくいので、ぎりぎり許せる最大公約数的な設定をしているという管理者は多いのではないだろうか。
それでも、tmux や screen のプリフィックスは人によって通常使っているキーが違ったりして、これが異なるだけで非常に使いにくかったりする。自分はログインする度に以下のようなコマンドを打ちこんでいた。実に面倒くさい。

$ tmux set-option -g prefix C-t

この件についてtwitterで聞いてみたところ、皆さんサーバ上に個人用の設定ファイルを用意して、ログイン時にそれを読み込んだりしているようだった。

複数人で管理してるサーバの tmux.conf / .screenrc を個人用にカスタマイズすべきじゃないと思うんだけど、デフォルトのままだと使いにくい。みんなどうしてるんだろう?

で、これを何とかしようと思って少し調べてみた結果、以下の sshrc を使うのが便利という結論に至った。

https://github.com/Russell91/sshrc

特徴としては、

  • sshログイン時に毎回流し込むので環境を汚さない
  • いちいちサーバに設定ファイルをコピーする必要がないので、管理するサーバの台数が多くても安心
  • ローカルの設定ファイルだけメンテナンスしておけば、常に同じ環境で作業ができる
  • サーバ上の .bashrc も今まで通り読み込まれる

 

Macの場合は、Homebrewからインストールできる。

$ brew install sshrc

次に設定ファイルを用意する。

~/.sshrc
tmux() {
  local TMUXDIR=/tmp/.yamashita-tmux
  if ! [ -d $TMUXDIR ]; then
    rm -rf $TMUXDIR
    mkdir -p $TMUXDIR
  fi
  rm -rf $TMUXDIR/.sshrc.d
  cp -r $SSHHOME/.sshrc $SSHHOME/bashsshrc $SSHHOME/sshrc $SSHHOME/.sshrc.d $TMUXDIR
  SSHHOME=$TMUXDIR SHELL=$TMUXDIR/bashsshrc `which tmux` -f $SSHHOME/.sshrc.d/.tmux.conf -S $TMUXDIR/tmuxserver $@
}

export VIMINIT="let \$MYVIMRC='$SSHHOME/.sshrc.d/.vimrc' | source \$MYVIMRC"
export SHELL=`which bash`

# alias etc... as you like
alias ll='ls -l'
alias la='ls -A'

tmux関数は re-attach するためのおまじないで、これを利用することで他の人とセッションを共有しなくなる。

次に ~/.sshrc.d/ というディレクトリを作って、.tmux.conf や .vimrc を置けば設定は完了。また、ローカルでzshを使っている人は「compdef sshrc=ssh」を追加しておくと補完が効いて幸せになれる。

.sshrc
.sshrc.d/
 ├── .tmux.conf
 └── .vimrc

それでは、早速サーバに接続してみよう。普段使っている ssh コマンドの代わりに sshrc コマンドを使う。中身はシェルスクリプトで書かれたsshのラッパーなので、オプション等はそのまま利用できる。

$ sshrc username@servername
$ la
.bash_history  .bash_logout  .bash_profile  .bashrc  .ssh
$ tmux

自分の .tmux.conf が反映され、使い慣れた環境が再現されているはず。うん便利。

次に通常のsshでログインしてみると、

$ ssh username@servername
$ la
-bash: la: コマンドが見つかりません
$ ls -A
.bash_history  .bash_logout  .bash_profile  .bashrc  .ssh

当然 alias は設定されておらず、余計なファイルも全く作られていない。

ひとつ注意点としては、バリバリにカスタマイズせずに最低限にしておいたほうがよいということ。特にtmux-powerlineなどで魔改造しているような人は、サーバ管理用の専用設定を用意したほうがよい。ログイン時にファイルを転送する必要があるので、作者の方も64KB以下を推奨している。

AWS NATインスタンス構築とSerfによる冗長化

2015.12.17追記:マネージドNATゲートウェイというサービスがリリースされました。

AWS VPCでプライベートサブネット内に起動したインスタンスは、インターネットと通信することができません。外部リポジトリやAmazon S3等の各種サービスも利用するためには、NATインスタンスを用意して外部との通信を中継する必要があります。

このためにAWSではNATインスタンス用のオフィシャルなAMIが提供されているのですが、わざわざ専用のインスタンスを稼働させるのは勿体ないので、ヴェッテルでは管理用サーバにNATインスタンス機能を持たせて併用しています。またNATインスタンスがSPOFにならないように障害が発生したら、自動的にフェイルオーバーするような冗長化も行っています。

ここでは、オフィシャルなAMIを利用せずに独自でNATインスタンスを構築する方法と Serf による冗長化の方法を紹介したいと思います。

NATインスタンスの構築

まずはAMIを使わない独自NATインスタンスの構築ですが、これは configure-pat.sh がポイントなだけでそれほど難しくありません。当然ですが、NATインスタンスはパブリックサブネット上にあり、Public IPもしくはElastic IPアドレスが割り当てられている必要があります。

1. configure-pat.sh を /usr/local/sbin/ に設置
$ sudo mv configure-pat.sh /usr/local/sbin/
$ sudo chmod 755 /usr/local/sbin/configure-pat.sh
2. /etc/rc.local に最後の2行を追加
$ sudo vi /etc/rc.local

#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

# Configure PAT
/usr/local/sbin/configure-pat.sh
3. 再起動もしくは configure-pat.sh を実行して設定を反映
$ sudo /usr/local/sbin/configure-pat.sh
4. Route Tablesの設定を追加

VPCコンソールにて、 [Route Tables]を開きます。[Routes] タブで [Edit] をクリックし、[Destination] ボックスに [0.0.0.0/0] と指定します。次に、[Target] リストから NAT インスタンスのインスタンス ID を選択して、[Save] をクリックします。

5. 「Source/Dest. Check」の無効化

Amazon EC2コンソールからNATインスタンスを選択して、[Actions]-[Networking]-[Change Source/Dest. Check] をクリックします。以下の画面が表示されるので [Yes, Disable] をクリックして無効にします。


6. SecurityGroupの設定

必要に応じて適切なSecurityGroupを設定します。公式ドキュメントを参考にしてください。

これで無事にNATインスタンスを構築することができました。
しかし、NATインスタンスが1台だけだとこの部分がSPOFになってしまうので、もう一台NATインスタンスを用意して監視を行い、何かしらの原因で通信ができなくなった場合に2代目のNATインスタンスに切り替えるように設定します。

Serfによる冗長化

Serfはサービスディスカバリーやオーケストレーション、障害検出のためのツールでVagrantの開発者であるMitchell Hashimoto氏により開発が進められています。Goで書かれており、軽量で設置も簡単です。
ここでは、2台のNATインスタンスをそれぞれ nat1(10.0.0.1), nat2(10.0.0.2) として設定します。

1. インストール (nat1, nat2)
$ wget https://dl.bintray.com/mitchellh/serf/0.6.3_linux_amd64.zip
$ unzip 0.6.3_linux_amd64.zip
$ sudo cp serf /usr/local/bin/
2. TCP/UDPの7946番ポートを開放 (nat1, nat2)
3. 設定ファイルの設置 (nat1)
$ vi /etc/serf.conf

{
  "node_name": "nat1",  ← ノード名
  "tags": {
    "role": "nat",
    "routetable": "rtb-123456789"  ← Route Table IDを指定
  },
  "start_join": [
    "10.0.0.2"  ← 相手のIPアドレスを指定
  ],
  "event_handlers" : [
    "member-failed,member-leave=/home/ec2-user/bin/replace-nat.sh >> /var/log/serf-event.log 2>&1"
  ]
}

EC2ではマルチキャストDNSによるオートディスカバリはできないようなので、少々ダサいですが相手ノードのIPアドレスを指定しています。

4. 設定ファイルの設置 (nat2)
$ vi /etc/serf.conf

{
  "node_name": "nat2",  ← ノード名
  "tags": {
    "role": "nat",
    "routetable": "rtb-123456789"  ← Route Table IDを指定
  },
  "start_join": [
    "10.0.0.1"  ← 相手のIPアドレスを指定
  ],
  "event_handlers" : [
    "member-failed,member-leave=/home/ec2-user/bin/replace-nat.sh >> /var/log/serf-event.log 2>&1"
  ]
}
5. 切り替えスクリプトの設置 (nat1, nat2)
$ vi /home/ec2-user/bin/replace-nat.sh

#!/bin/sh
export AWS_CONFIG_FILE=/home/ec2-user/.aws/config

echo `date` "-- Other NAT heartbeat failed, taking over $SERF_TAG_ROUTETABLE default route to $SERF_SELF_NAME"

# Get this instance's ID
Instance_ID=`/usr/bin/curl --silent http://169.254.169.254/latest/meta-data/instance-id`

if [ -n $SERF_TAG_ROUTETABLE ]; then
  aws ec2 replace-route --route-table-id $SERF_TAG_ROUTETABLE --destination-cidr-block 0.0.0.0/0 --instance-id $Instance_ID
fi
6. Serfの自動起動設定 (nat1, nat2)
$ vi /etc/init/serf.conf

description "Serf agent"

start on started elastic-network-interfaces
stop on stopping elastic-network-interfaces

respawn
exec /usr/local/bin/serf agent \
    -config-file=/etc/serf.conf >> /var/log/serf.log 2>&1

ネットワークが利用可能になってから起動しないといけないので、start on started elastic-network-interfaces を設定しています。EC2のネットワークが有効になるタイミングなんですが、問題なく動いているのでおそらくこれで大丈夫だと思います。

以上で設定は完了です。Serfを起動して実際に動作確認をしてみましょう。

[nat1]$ sudo initctl start serf
[nat2]$ sudo initctl start serf

何も問題がなければ、お互いを認識しログに以下のように表示されるはずです。

[nat2]$ tailf /var/log/serf.log
==> Starting Serf agent...
==> Starting Serf agent RPC...
==> Serf agent running!
         Node name: 'special'
         Bind addr: '0.0.0.0:7946'
          RPC addr: '127.0.0.1:7373'
         Encrypted: false
          Snapshot: false
           Profile: lan
==> Joining cluster...(replay: false)
    Join completed. Synced with 1 initial agents

==> Log data will now stream in as it occurs:

    2014/12/29 08:34:28 [INFO] agent: Serf agent starting
    2014/12/29 08:34:28 [INFO] serf: EventMemberJoin: nat2 10.0.0.2
    2014/12/29 08:34:28 [INFO] agent: joining: [10.0.0.1] replay: false
    2014/12/29 08:34:28 [INFO] serf: EventMemberJoin: nat1 10.0.0.1
    2014/12/29 08:34:28 [INFO] agent: joined: 1 nodes
    2014/12/29 08:34:29 [INFO] agent: Received event: member-join

membersコマンドで確認してみます。

$ serf members
nat2  10.0.0.2:7946  alive  routetable=rtb-123456789,role=nat
nat1  10.0.0.1:7946   alive  role=nat,routetable=rtb-123456789

nat1とnat2が表示され、問題なく認識されていることが分かります。

それではいよいよ nat1 を停止してフェイルーバー機能が想定通りに動作するか試してみましょう。ここでは、serfを停止していますが、実際にサーバを shutdown してしまっても構いません。

[nat1]$ sudo initctl stop serf
2014/12/29 08:24:45 [ERR] memberlist: Push/Pull with nat1 failed: write tcp 10.0.0.1:7946: connection refused
2014/12/29 08:24:47 [INFO] memberlist: Suspect nat1 has failed, no acks received
2014/12/29 08:24:49 [INFO] memberlist: Suspect nat1 has failed, no acks received
2014/12/29 08:24:50 [INFO] memberlist: Suspect nat1 has failed, no acks received
2014/12/29 08:24:52 [INFO] memberlist: Suspect nat1 has failed, no acks received
2014/12/29 08:24:52 [INFO] memberlist: Marking nat1 as failed, suspect timeout reached
2014/12/29 08:24:52 [INFO] serf: EventMemberFailed: nat1 10.0.0.1
2014/12/29 08:24:53 [INFO] memberlist: Suspect nat1 has failed, no acks received
2014/12/29 08:24:53 [INFO] agent: Received event: member-failed
2014/12/29 08:25:00 [INFO] serf: attempting reconnect to nat1 10.0.0.1:7946

member-failedイベントが発火し、Route Tablesが書き換わっているのが分かります。

Route Tablesを書き換えることでプライベートサブネットから外部への通信がnat2経由に切り替わります。

以上、負荷の低いサーバを待機系のNATインスタンスとして設定することで、可用性を保ったままコストも最小限に抑えることができます。これで年末年始も安心して休めますね。

gitでマージして不要になったブランチを削除する

gitでマージして不要になったブランチを削除するには、以下のようにする。

% git branch --merged | egrep '^[[:blank:]]+t[0-9]+' | xargs git branch -d
Deleted branch t1529 (was ead5804).
Deleted branch t1543 (was b27e605).

※ t123などBTSのチケット番号をブランチ名に含める命名規則にしている。

GitHub リポジトリのバックアップと移行

GitHub の有料プランは利用しているプライベートリポジトリの数によって料金が変わってきます。使わなくなったリポジトリは、ローカルや自分のサーバにバックアップして削除してしまうのが賢く使うコツです。

以下に GitHub のリポジトリをバックアップして、自分のサーバ上にリポジトリを移行して開発を続ける方法を紹介します。

1. バックアップ

バックアップするだけで再利用しないのならば、以下のコマンドだけでOKです。このディレクトリを適宜 zip などで圧縮して保存しておけば良いでしょう。

$ git clone --mirror git@github.com:weboo/project.git
$ zip -r project.git.zip project.git

2. 自分のサーバで開発を続ける

リポジトリを自分のサーバに移行して開発を続けるには、1.でバックアップしたファイルをサーバにコピーして展開した後に git --bare init コマンドを実行します。

$ unzip project.git.zip
$ cd project.git
$ git --bare init

3. 開発用PCで git clone

開発用のPCで git clone するのは特に変わったことはありません。2.で作成した新リポジトリのパスに注意して clone するだけです。これで、GitHubでのコミットログやブランチを維持したまま今まで通りに開発を続けられます。

$ git clone user@example.com:repos/project.git

※example.com サーバの /home/user/repos/project.git に展開した場合

もし、cloneし直さずに既に存在するワーキングディレクトリをそのまま利用したい場合は、以下のようにしてリモートリポジトリを変更します。

$ git remote set-url origin user@example.com:repos/project.git
$ git remote -v
origin  user@example.com:repos/project.git (fetch)
origin  user@example.com:repos/project.git (push)

以上でバックアップ&移行は完了です。これで安心して GitHub から不要になったリポジトリを削除することができますね。

もしくは、プライベートリポジトリが無料で作り放題の BitBucket ならブラウザ上から必要な項目を入力するだけで簡単に移行できるので、いっそのこと BitBucket に完全移行しちゃうというのもお勧めです。

Ubuntu の ImageMagick を OpenMP 無効でリコンパイルする

今日は、画像処理に PythonMagick を使っている箇所で以下のようなエラーが出て困っていました。つい先日まで全く同じコードで動いていたのでおかしいなと思ったのですが、調べてみるとどうやら OpenMP のマルチスレッドがらみのエラーのようです。そういえば、この Ubuntu の VM の割り当て CPU 数を最近増やしたのでした。

python: magick/cache-view.c:729: GetCacheViewVirtualPixels: Assertion
 `id < (int) cache_view->number_threads' failed.

というわけで、OpenMP を無効にしてパッケージをコンパイルし直すことにしました。

% sudo apt-get buil-dep imagemagick
% apt-get source imagemagick
% cd imagemagick-6.7.7.10

rules ファイルを編集して --disable-opnemp のコンパイルオプションを追加します(58行目くらい)。ついでにRGBを内部で8bitで扱うようなオプションも設定します。これによりCPU/メモリ使用量が削減できます。

% vi debian/rules

    --x-includes=/usr/include/X11 \
    --x-libraries=/usr/lib/X11 \
    --disable-openmp \
    --with-quantum-depth=8

    # Patch the generated libtool to avoid passing -rpath when linking,

ビルドしてパッケージを入れ替えます。

% dpkg-buildpackage -b
% sudo apt-get remove --purge libmagick++5
% cd ..
% sudo dpkg -i libmagickcore5* libmagick++5*
% sudo apt-get install python-pythonmagick

サーバの CentOS では発生していないので、きっとUbuntu 12.04だけの問題なんでしょうね。最後に簡単なテストプログラムで動作確認をして完了です。

import PythonMagick

img = PythonMagick.Image("himekyun.jpg")
img.sample(PythonMagick._PythonMagick.Geometry(100,100))
img.write("himekyun_small.jpg")

関連リンク:
PerlMagick が OpenMP 有効だと高負荷になる件 :: drk7jp
ImageMagickとOpenMPの件 - blog.nomadscafe.jp

ELB の Health Check ログを隔離する(nginx)

Amazon ELB 配下で nginx を動かしているとこんなログが大量に表示されて鬱陶しいので隔離することにしました。

10.120.21.xxx - - [01/Feb/2013:17:53:39 +0000] "-" 400 0 "-" "-"
10.120.21.xxx - - [01/Feb/2013:17:54:09 +0000] "-" 400 0 "-" "-"
10.120.21.xxx - - [01/Feb/2013:17:55:29 +0000] "-" 400 0 "-" "-"

基本的に名前ベースのバーチャルホストで運用しているので、それ以外を隔離すればOK。access_log off でもいいですが、障害時の切り分けが難しくなるのでできるだけ出力するようにしておいたほうがいいと思います。

server {
    listen 80;

    access_log /var/log/nginx/elb.log;
    error_log /var/log/nginx/elb_error.log;

    location = /health_check {
        empty_gif;
    }
}

あと、うちでは Health Check 用のエンドポイントを /health_check として空のGIFファイルを返すようにしています。こんな感じで ELB からアクセスが来ます。

10.120.21.xxx - - [01/Feb/2013:17:56:10 +0000] "GET /health_check HTTP/1.1" 200
 43 "-" "ELB-HealthChecker/1.0"

CentOS 6.3 に PHP-FPM をインストール

ちょっと事情があって、CentOS 6.3 にPHPをインストールすることになりました。僕はすっかり nginx に移行してしまっていて、もう何年も Apache を使っていない上にサーバサイドは Python を使うことが多いので PHP の設定をすること自体が数年ぶりです。最近は PHP を動かすのにどうしてるんだろうと調べたところ、nginx + php-fpm というのがモダンな感じらしいのでそれを使うことにしました。

PHP-FPMは標準のyumリポジトリには含まれていないので、remiリポジトリを有効にします。

# rpm --import http://rpms.famillecollet.com/RPM-GPG-KEY-remi
# rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

PHP-PFM のインストールと設定をします。今回の用途ではほぼ自分しか使わないので worker の数は最低限にします。

# yum install php php-fpm php-cli php-devel php-gd php-mysql php-process php-mbstring php-xml --enablerepo=remi
# vi /etc/php-fpm.d/www.conf
user = nginx
group = nginx

pm.max_children = 5
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 2
pm.max_requests = 200

# service php-fpm start

次に nginx の設定ですが、今回はLAN内からのみのアクセスなのでIPアドレスによる制限をかけます。また、http://ホスト名/php/ にアクセスすると /var/www/php の下のPHPプログラムが実行されるようにします。default.conf に以下の設定を追加して再起動。

# vi /etc/nginx/conf.d/default.conf

location /php {
    root /var/www;
    index index.html index.php;
    allow 192.168.1.0/24;
    deny all;

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

# service nginx restart
/var/www/php/index.php
<?php
  echo phpinfo();
?>
試しにお決まりの上記のようなファイルを作って http://servername/php/ にアクセスして動作に問題なければ、自動起動の設定をして完了です。
# chkconfig php-fpm on

OS X Lion から Linuxサーバに Time Machine バックアップ

自分は Linux サーバを Time Machine のバックアップ先として利用しているのですが、OS X Lion にしてから、SMB経由での「Time Machine」バックアップ機能が使えなくなってしまいました。Sambaが独自開発のものに置き換えられてしまったのも影響していると思うんですが、不便なのでLinuxサーバにAFP経由でバックアップできるように設定しました。

なお、自分の環境は CentOS 5.6 なのでソースからインストールしましたが、超最新なディストリビューションの場合はパッケージを使って楽できるかもしれません。

手順を以下に示します。

(1)コンパイルに必要なライブラリをインストール
% sudo yum install avahi-devel libgcrypt-devel openssl-devel
(2)Oracle Berkeley DB をインストール

Oracle Berkeley DB Downloads からファイルをダウンロード

% tar zxvf db-5.2.28.tar.gz
% cd db-5.2.28/build_unix/
% ../dist/configure --with-uniquename
% make
% sudo make install
(3)Netatalk をインストール

Netatalk は AFP 3.3 に対応した Netatalk 2.2 をインストールする必要があります。
netatalk.sourceforge.net からファイルをダウンロード

% tar jxvf netatalk-2.2.0.tar.bz2
% cd netatalk-2.2.0
% ./configure --enable-redhat --enable-zeroconf --with-bdb=/usr/local/BerkeleyDB.5.2
% make
% sudo make install

/usr/local/etc/netatalk/AppleVolumes.default を編集して、デフォルトのパーミッションを設定します。

# The line below sets some DEFAULT, starting with Netatalk 2.1.
:DEFAULT: options:upriv,usedots cnidscheme:dbd dperm:0700 fperm:0600 ea:sys

また、Time Machine 用のディレクトリをマウント出来るようにエクスポートしておきます。自分の場合は、/mnt/NAS/TimeMachine をバックアップ用として指定しています。

# The "~" below indicates that Home directories are visible by default.
# If you do not wish to have people accessing their Home directories,
# please put a pound sign in front of the tilde or delete it.
~
/mnt/NAS/TimeMachine "Time Machine" options:tm
(4)Netatalk および avahi-daemon の起動

最後にNetatalk が自動起動するように設定して起動します。もし、ファイアウォールの設定をしている場合は、ポート 548 も忘れずに開けておきます。

% sudo /sbin/chkconfig netatalk on
% sudo /sbin/service netatalk start
% sudo /sbin/chkconfig avahi-daemon on
% sudo /sbin/service avahi-daemon start

以上で、Time Machineの設定画面から見えるようになるはずです。あとは普通に Mac 側で設定するだけ。

Netatalk 2.2のリリースに関してはひと悶着あったようですが、個人ユーザとしては継続して公開してもらえるのは嬉しいところです。

GeForce 7300 で Unity 3D を動かす

KernelやAndroidのビルドに利用しているデスクトップPCのほうには、GeForce 7300という少々(かなり?)古めのビデオカードが刺さっています。この充分に枯れたカードで、今まで Compiz が問題なく使えていたのに、Ubuntu 11.04 にアップグレードしたところ、なぜか Unity が有効になりません。

おかしいなと思って調べてみると、何とブラックリスト入りしていました。

hide@ubuntu %  /usr/lib/nux/unity_support_test -p
OpenGL vendor string:   NVIDIA Corporation
OpenGL renderer string: GeForce 7300 SE/7200 GS/PCI/SSE2
OpenGL version string:  2.1.2 NVIDIA 173.14.30

Not software rendered:    yes
Not blacklisted:          no
GLX fbconfig:             yes
GLX texture from pixmap:  yes
GL npot or rect textures: yes
GL vertex program:        yes
GL fragment program:      yes
GL vertex buffer object:  yes
GL framebuffer object:    yes
GL version is 1.4+:       yes

Unity supported:          no

調べてみると、同じ状況で困っている人はいるようで、NVIDIA の Version 173 のドライバをインストールして、/etc/environment に次の記述を追加することで起動するようになりました。

UNITY_FORCE_START=1

NVIDIAのドライバは、[システム]-[システム管理]-[ハードウェア・ドライバ]からインストールできます。

Unity を使ってみた感じなんですが、悪くないです。まだ発展途上な感じは否めないものの、短期間で良くここまで仕上げたなという印象。ネットブックはもうUbuntuでいいかもしれません。

関連リンク:
» Geforce Go 7300/7400 blacklisted, can I still run Unity? - Ask Ubuntu

Ubuntu 11.04 へアップグレードして困ったこととその対策

Ubuntu を 11.04 にアップグレードしました。スクリーンショットを見て分かる通り、僕は Ubuntu を VMware Fusion 内で動かしていて、ウィンドウマネージャには awesome を使っているので Unity 何それ状態です。何が変わったか分かりません。

逆に困ったことがあって、Natty の Kernel だと純正の VMware Tools がコンパイルエラーになります。このため、HGFS やクリップボード共有といった便利な機能が使えなくなってしまいました。ここで紹介されているパッチを当てれば HGFS の read は可能になるものの、書き込みで Segmentaion Fault が発生してしまうような状況です。

なので、仕方なく今は open-vm-tools を使っています。

  • open-vm-dkms
  • open-vm-tools

の2つのパッケージをインストールすることで、共有フォルダをマウントできるようになりました。また、純正ツールと違ってそのままでは起動時に自動マウントしてくれないため、/etc/fstab に以下の設定を記述しています。

.host:/ /mnt/hgfs vmhgfs defaults,ttl=5 0 0

これで HGFS に関しては問題なく動作するようになりました。設定ファイルの類は VM ホスト上にインストールした Dropbox フォルダをマウントして参照しているので、これが使えないと限りなく無力なのです。

しかし、あちらを立てればこちらが立たずで、open-vm-tools にしたら、今度はクリップボードの共有ができなくなってしまいました。こちらは、その昔、「仮想な背中」というサイトで公開されていた vmw コマンドを使うようにしました。

kill-ringをクリップボードと同期するための .emacs 設定

;; share clipboard
(defvar prev-yanked-text nil "*previous yanked text")
(defun copy-from-host ()
  (let ((coding-system-for-read 'utf-8))
    (let ((text (shell-command-to-string "vmw paste")))
      (if (string= prev-yanked-text text)
          nil
        (setq prev-yanked-text text)))))

(defun paste-to-host (text &optional push)
  (let ((process-connection-type nil))
    (let ((proc (start-process "vmwcopy" "*Messages*" "vmw" "copy")))
      (set-process-coding-system proc 'utf-8 'utf-8)
      (process-send-string proc text)
      (process-send-eof proc)))
  (message "Copied to clipboard."))

(setq interprogram-cut-function 'paste-to-host)
(setq interprogram-paste-function 'copy-from-host)

awesome/rc.lua 用の設定

awful.key({ modkey }, "c",
          function () awful.util.spawn_with_shell(
                "xclip -o -selection clipboard | vmw copy")
          end),
awful.key({ modkey }, "v",
          function () awful.util.spawn_with_shell(
                "vmw paste | xclip -i -selection clipboard")
          end)

とりあえず今はこれで凌いでいますが、早く純正の VMware Tools が使えるようになって欲しいところです。

2011/05/05追記:
.emacsでペースト用の設定が抜けていたので追記しました。
elispがうまくハイライトされていなかったのを修正しました。