スナップショットから作成した EBS ボリュームをマウントする

この記事では EBS ボリュームのスナップショットを、新しい EC2 インスタンスでマウントする方法について記述する。すでに EBS ボリュームのスナップショットは作成されていると仮定する。まだであれば、ひとつ前の記事を参照してほしい。 AWS コンソールでぽちぽちと新しい EC2 インスタンスを作成し、途中の “Add Storage” のプロセスで /dev/sdf 辺りに前述の記事で作成したスナップショットIDを使ってボリュームを追加するとしよう。 最終的に作成されたインスタンスに ssh でログインし、lsblk を実行すると次のように表示される。ブロックデバイスは認識されているものの、マウントされていないことがわかる。 ## /dev/xvdf はアタッチされているが、マウントされていない (MOUNTPOINT が空) ## (lsblk の NAME は "/dev/" が省略される) $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT xvda 202:0 0 8G 0 disk └─xvda1 202:1 0 8G 0 part / xvdf 202:80 0 512G 0 disk ## ちなみに xvdf は /dev/sdf のエイリアス $ ls -l /dev/sdf lrwxrwxrwx 1 root root 4 Jun 14 08:16 /dev/sdf -> xvdf ## /dev/xvdf にファイルシステムは存在することを確認する (ない場合は mkfs を使う) $ sudo file -s /dev/xvdf /dev/xvdf: Linux rev 1. [Read More]

AWS CLI で EBS のスナップショットを作成する

この記事は AWS CLI で EBS のスナップショットを作成するためのメモだ。

正直なところ、何も難しいことはない。ボリューム ID が “vol-xxxxxxxx” の EBS ボリュームのバックアップを取るなら aws ec2 create-snapshot --volume-id vol-xxxxxxxx --description "My Backup" とすればいいだけだ。

ただし、create-snapshot はオプションが少なく、スナップショットの作成と同時にタグ付ができない。例えば、スナップショットの Name タグを “MySnapshot” とし、Cost を タグを “MyService” としたければ、create-tags コマンドを別に叩く必要がある。

create-snapshot は作成するスナップショットの情報を JSON で STDOUT に出力する。この JSON にはスナップショット ID の情報も含まれているので、次のようにすることで目的の処理を達成できる。

$ SnapshotId=$(aws ec2 create-snapshot --volume-id vol-xxxxxxx --description "MySnapshot") | jq -r .SnapshotId)
$ aws ec2 create-tags --resources $SnapshotId --tags Key=Cost,Value=MyService Key=Name,Value=MySnapshot

なお、AWS では EBS ボリュームのスナップショットを連続で作成した場合、後から作られるスナップショットは前回のスナップショットからの増分スナップショットになる。

*nix が wait 絡みのデッドロックを防ぐ仕組み

引き続き「Working With Unix Processes」を読んでいる。

サンプルで「デッドロックが起こりそう だけど、起こらない」コードが掲載されていた。次のスニペットは、そのサンプルを少し書き換えたものだ。

#!/usr/bin/env ruby

# ふたつの子プロセスをつくり、すぐに殺す
2.times do
  fork do
    abort "おしまい"
  end
end

# 最初の子プロセスを待ち、その後は3秒ほど寝る
# 寝ている間にもうひとつの子プロセスも終了する
puts Process.wait
sleep 3

# もう子プロセスは終了しているので、これはデッドロックするはずでは? => 実際はしない
puts Process.wait

コードのコメントに書いた通りなのだが、最後の Process.wait はデッドロックになっても不思議ではない… けど、実際にはデッドロックにならない。

カーネルには exit したプロセスの情報をキューに詰めておく機構があり、親プロセスは死んだ子プロセスの順にその情報を取得できる。だから、サンプルでの最後の Process.wait は実際には子プロセスの終了を待つのではなく、キューから「既に死んだ」子プロセスの情報を取得している。

ただ、子プロセスが存在しない「かつ」前述のキューにもデータが存在しないとき、Process.waitErrno::ECHILD 例外を起こす。

まあ、それはそうだよね。

Ruby 2.0 (or later) の CoW

Working With Unix Processes」を読んでいる。

これによると、Ruby (MRI) では 2.0 まで CoW (Copy on Write) が実装されていなかったそうだ。理由は Ruby の GC がナイーブなマーク・アンド・スイープであったから、らしい。

バージョン 1.9 までの Ruby は、マークのタイミングでオブジェクト内に直接「使用中」フラグを立てていたそうだ。つまり、オブジェクトに変更を加えることになるので、このタイミングでオブジェクトのコピーが発生してしまう。

バージョン 2.0 からは、マーク・アンド・スイープのために専用のメモリ領域をつくるので、マークのタイミングでオブジェクト自身を変更する必要はない。これなら CoW を機能させることができる。

なるほどなあ。

Gradle で "Failed to load native library 'libnative-platform.so' for Linux amd64." と言われるときの対処

gradle build をして、次のようなエラーに遭遇した:

FAILURE: Build failed with an exception.

* What went wrong:
Failed to load native library 'libnative-platform.so' for Linux amd64.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

いかにも何か依存パッケージが足りていないようなエラーメッセージだ。検索してみると「libstdc++ をインストールすると解決するよ」という記事も実際に存在する。

僕も libstdc++ をインストールしてみたが、問題は解決しなかった。実際には ~/.gradleroot 権限でディレクトリが作られてしまっていたことが問題であった。単に ~/.gradle/* を削除して gradle build を実行しなおすことでビルドを実行できた。

わかってしまえば簡単な問題だけど、エラーメッセージが不親切だと時間を無駄にしてしまう事例だ。

Hello World

Hugo で静的なファイルをホストする実験です。

mahata.org のドメインを所有してはいたものの、ずっと活用していなかったので、これを機に使っていこうかと思案中。

Pygments によるハイライトも試しておこう。

int main() {
  return 0;
}