令和の時代に Perl で CSV ファイルを操作する
はじめに
とあることから久しぶりに CSV ファイルの生成を行う必要がありましたので、忘備録としてこの文章を作成しています。
また今どき Perl を使ったものなのですが、検索すると古めの情報が多かったので少しだけ頑張ってみました。
コピペで実行可能な内容にしていますので、困っている人の役に立てれば幸いです。
背景
CSV ファイルは「カンマ区切り」と単純な形式と思われますが、実際は実装依存である場合が多いため、意外と面倒な事が多いです。
このため、自前で頑張って実装するより、よくデバッグされたライブラリを使用したほうが確実です。
また RFC は存在していますが、参考程度にしておいたほうが良いです。 https://datatracker.ietf.org/doc/html/rfc4180
ちなみに「Microsoft Excel で処理ができる形式」が無難かもしれません。 これは非技術者層でデータの生成手段として、Excel が多く使われている傾向があるためです。
※ 今日日は JSON や YAML などが多く使われますが、これらは手書きが面倒でプログラムから生成する前提となっています。
想定される環境
環境は下記の表とします。
項目 | 内容 | 備考 |
---|---|---|
OS | Ubuntu 22.04.5 LTS | いわゆる UNIX ぽい環境 |
シェル | zsh | Bourne Shell 系 |
言語 | perl | 好み |
OS に依存した部分は少ないはずなので、他のいわゆる UNIX 環境でも同様の手順でできるはずです。
今日日 perl なのは個人的な好みで「1ダースほどのプログラム言語経験から、比較的面倒が少ない」からです。
※ 他の言語はナウい情報がネットに溢れているので、そちらを参照してください。WEB 系なら PHP でも良いかも。
必要なものをインストールする
perlbrew と cpanm とあわせてホームディレクトリ以下にインストールする方法を推奨します。
perlbrew のインストール
perlbrew をインストールします。 https://perlbrew.pl/
% curl -L https://install.perlbrew.pl | sh
インストールできたら、perlbrew 用の $PATH の設定を行います。
% echo 'source ~/perl5/perlbrew/etc/bashrc' >> ~/.zshrc % source ~/.zshrc
$PATH に $HOME/perl5/perlbrew/bin が追加され、perlbrew コマンドが実行できることを確認します。
% echo $PATH /home/popopo/perl5/perlbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin % perlbrew version /home/popopo/perl5/perlbrew/bin/perlbrew - App::perlbrew/1.01
まずは perlbrew available でインストール可能な perl のバージョン一覧を確認します。
% perlbrew available # perl perl-5.40.0 perl-5.38.2 perl-5.36.3 perl-5.34.3 perl-5.32.1 perl-5.30.3 perl-5.28.3 perl-5.26.3 perl-5.24.4 perl-5.22.4 perl-5.20.3 perl-5.18.4 perl-5.16.3 perl-5.14.4 perl-5.12.5 perl-5.10.1 perl-5.8.9 perl-5.6.2
どのバージョンを使うのは好みで良いですが、コアモジュールの構成が異なることがあります。
とりあえず普段使いの FreeBSD における FreeBSD Ports でのデフォルトでは 5.36 のようなので、それに準拠してみます。
https://cgit.freebsd.org/ports/commit/?id=039a6a2aed7b227b06e07147e5246d04f0a004fb
% perlbrew install perl-5.36.3
次に OS 側にインストールされた perl から切り替えます。
現状は OS 側にインストールされた perl を使用している % perl -V:version version='5.34.0'; % which perl /usr/bin/perl perlbrew でインストールされた perl の一覧を確認する % perlbrew list perl-5.36.3 perlbrew switch で使用する perl を切り替える % perlbrew switch perl-5.36.3 perl コマンドで実行されるものが perlbrew でインストールしたものに切り替わっていることを確認する % perl -V:version version='5.36.3'; % which perl /home/popopo/perl5/perlbrew/perls/perl-5.36.3/bin/perl
cpanm のインストール
cpanm を導入します。
今回は perlbew で $HOME 以下にインストールされた環境への導入になるため、特権は不要です。
% curl -L http://cpanmin.us | perl - App::cpanminus % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 295k 100 295k 0 0 1720k 0 --:--:-- --:--:-- --:--:-- 1725k --> Working on App::cpanminus Fetching http://www.cpan.org/authors/id/M/MI/MIYAGAWA/App-cpanminus-1.7048.tar.gz ... OK Configuring App-cpanminus-1.7048 ... OK Building and testing App-cpanminus-1.7048 ... OK Successfully installed App-cpanminus-1.7048 1 distribution installed % which cpanm /home/popopo/perl5/perlbrew/perls/perl-5.36.3/bin/cpanm
Text::CSV_XS のインストール
次に Text::CSV_XS をインストールします。
% cpanm Text::CSV_XS --> Working on Text::CSV_XS Fetching http://www.cpan.org/authors/id/H/HM/HMBRAND/Text-CSV_XS-1.58.tgz ... OK Configuring Text-CSV_XS-1.58 ... OK Building and testing Text-CSV_XS-1.58 ... OK Successfully installed Text-CSV_XS-1.58 1 distribution installed
インストールしたモジュールが使えるかを確認します。
% perl -MText::CSV_XS -le 'print $Text::CSV_XS::VERSION' 1.58
コンパイラが使えない環境などへの移植性を考慮して Text::CSV をインストールしても良いです。
※ ただし、Text::CSV は Text::CSV_XS が存在しない環境では Text::CSV_PP を使います。これは XS と比較すると動作はかなり遅いです。
Text::CSV_XS を用いたサンプルコード
実際に CSV ファイルを扱うサンプルコードを書いてみます。
https://metacpan.org/pod/Text::CSV
CSV データの用意
使用するデータは下記 URL から取得できる郵便番号とします。
https://www.post.japanpost.jp/zipcode/dl/utf-zip.html
% mkdir ~/src/csvtest % cd ~/src/csvtest % curl -L -O https://www.post.japanpost.jp/zipcode/dl/utf/zip/utf_ken_all.zip % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1984k 100 1984k 0 0 7292k 0 --:--:-- --:--:-- --:--:-- 7322k % ls utf_ken_all.zip % unzip utf_ken_all.zip Archive: utf_ken_all.zip inflating: utf_ken_all.csv
CSV データの読み込み
読み込んだ郵便番号データから任意の都道府県のものだけを出力する処理とします。
要件は下記となります。
- 引数として下記を受ける
- 読み込み対象となる郵便番号データのファイルパス
- 取り出したい都道府県名を指定できる
- 出力されるファイル名は下記とする
- 出力されたファイルは Microsoft Excel で読み込める
- そのままダブルクリックで開くには BOM が存在している必要がある
実際のサンプルコードは下記になります。
#! /usr/bin/env perl # use v5.36; use utf8; binmode STDOUT, ":utf8"; use Text::CSV_XS; # UTF で文字化けするので上書きする use Data::Dumper; { package Data::Dumper; { no warnings; sub qquote { return shift; } } } $Data::Dumper::Useperl = 1; ## サブルーチン # usage sub usage { say STDERR @_; say "usage: $0 <csvfile> <prefecture>"; exit -1; } ## メイン # CSV ファイルの指定 my $CSV_FILE = $ARGV[0] || ""; if ( ! -f $CSV_FILE ) { usage( "Error! csv file not set." ); } # 取り出したい都道府県 my $TARGET_PREF= $ARGV[1] || ""; if ( ! $TARGET_PREF ) { usage( "Error! target prefecture not set." ); } utf8::decode( $TARGET_PREF ); my $csv = Text::CSV_XS->new ( { binary => 1, auto_diag => 1 } ); open my $fh, "<:encoding(utf8)", $CSV_FILE or die "$CSV_FILE: $!"; my @results; while ( my $row = $csv->getline( $fh ) ) { # 7. 都道府県名 ………… 漢字(コード順に掲載) $row->[6] eq $TARGET_PREF or next; push( @results, $row ); } close( $fh ); # デバッグ用 # say Dumper( @results ); # 書き出し my $output_filename = "postcode_$TARGET_PREF.csv"; open( my $nfh, ">:encoding(utf8)", $output_filename ) or die "$output_filename: $!"; # Excel でそのままダブルクリックで開きたい場合は BOM を付ける (他に良い方法があるはず) print $nfh "\x{FEFF}"; $csv->say( $nfh, $_ ) for @results; close( $fh ); exit;
下記のように実行します。
北海道のみ取り出す % ./read_csv.pl utf_ken_all.csv 北海道 兵庫県のみ取り出す % ./read_csv.pl utf_ken_all.csv 兵庫県
次に出力結果が期待したものになっているかを雑に確認します。
- grep -c で検索単語のカウント数を出力する
- wc -l で行数を出力する
- 出力結果の行数を求める
- これらの実行結果が同一であれば、出力されたデータは正しいと判断する
※ 他にも方法はありそうなのですが、それはお好みで
% grep -c 北海道 utf_ken_all.csv 8190 % wc -l postcode_北海道.csv 8190 postcode_北海道.csv % grep -c 兵庫県 utf_ken_all.csv 5228 % wc -l postcode_兵庫県.csv 5228 postcode_兵庫県.csv ちなみに下記のように間違ったデータが含まれていないことを確認しても良い % grep -vc 北海道 postcode_北海道.csv 0 % grep -vc 兵庫県 postcode_兵庫県.csv 0
まとめ
令和の時代ですが、Perl と Text::CSV を用いた CSV ファイルの処理について記載しました。
DX などでデータの抽出や連携で必要になり無理難題を言われた方の参考になれば幸いです。
pf ユーザのための ufw + ipset 運用
はじめに
気がついたら 13年ぐらいはてなブロクを放置していました。
いや、Twitter で良いとは思っているのですが、細かい話などになるとこっちの方かな、と思い出した次第です。
で、相変わらずニッチな部分の記録の吐き出しとなります。
ufw は面倒くさいし、iptables もさらに面倒くさい
ubuntu ホストでファイヤーウォールの設定となると ufw になりますが、これがかなり面倒です。
これを pf で言うところの外部ファイルに設定し table を定義する形式したいです。
table <blocklist> persist file "/etc/pf.blocklist" (snip) block in quick from <blocklist>
こんな感じで気に入らないネットワーク情報を /etc/pf.blocklist に突っ込む → pfctl reload する運用に近い感じにしたいのです。
要は「ファイルで設定をばら撒ける」みたいな感じ。(FreeBSD と Linux が混在しているので面倒なのです)
また、外部のブラックリストを拾ってきて適用する、みたいな運用を想定しています。
注意点
ufw は設定済みです。
- 管理用ネットワークからの接続は許可
- 公開サービスのポートのみ接続を許可
- 普通? のファイヤーウォール設定は済
どうするか
ipset を使うと良いみたい。
/etc/ufw/after.init 内で設定してみる、感じです。
これがそのまま使えそうです。
導入
導入は ufw-ipset-blocklist-autoupdate の README そのままで良いです。
ただし、ローカルのファイルを読み込めるようにしたいので、下記のように変更しています。
% git diff update-ip-blocklists.sh diff --git a/update-ip-blocklists.sh b/update-ip-blocklists.sh index f40ee03..17fe7be 100755 --- a/update-ip-blocklists.sh +++ b/update-ip-blocklists.sh @@ -200,7 +200,7 @@ function update_blocklist() { log "Updating blacklist '$1' ..." log_verbose "Downloading blocklist '$1' from: $2 ..." local tempfile=$(mktemp "/tmp/blocklist.$1.XXXXXXXX") - wget -q -O "$tempfile" "$2" + curl -s -o "$tempfile" "$2" # Check downloaded list linecount=$(cat "$tempfile" | wc -l)
wget コマンドは file プロトコルに対応していないため、curl コマンドに変更しています。
これにより、下記のようにローカルにあるファイルから読み込めるようになります。
% sudo /path/to/update-ip-blocklists.sh -l "match-set-name file:///path/to/iplist"
動作確認
これはそのまま ipset と iptables の実行結果を確認します。
とりあえず、ufw-ipset-blocklist-autoupdate の README にある blocklist.de のリストが適切です。 (ここのリストは問題が少ないので、実運用に適用しても良いです)
% sudo ipset l -n bl-blocklist-inet % sudo iptables -L -n | grep ^DROP | grep match-set DROP all -- 0.0.0.0/0 0.0.0.0/0 match-set bl-blocklist-inet src
実際にブロックされるか試してみたい場合は下記のようにしてみます。
% echo "ブロックされたい IP アドレス" > /path/to/match-set-test % sudo /path/to/update-ip-blocklists.sh -l "match-set-test file:///path/to/match-set-test"
ブロックされたい IP アドレスのホストから通信をしてみて確立しなければ可とします。 (curl とかで。あわせて tcpdump などでパケットダンプを見るもの良いです)
少し調整
ログの出力が多すぎるて困る場合は、下記のようにします。 あまり良くない方法なのですが、単純に /etc/ufw/after{6}.init にて LOG エントリを設定しないようにするぐらいしか思いつきませんでした。
$IPSET_BIN restore -! < "$f" iptables -I INPUT -m set --match-set "$listname" src -j DROP #iptables -I INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] "
まとめ
「ファイルのばらまきでやりたい」てな人はこういうやり方もあるよ、みたいな感じです。
また、外部ブラックリストの採用を検討されている方の参考になると幸いです。
(おまけ) ブラックリストはどれを使えば良いのよ
どれでも良いですが、ポリシが明確である所が良いです。
- 登録される理由が提示されている
- 解除できる理由が提示されている
この解除できるというのが重要です。
また、近年においてはクラウドなどでネットワークのいわゆる「使いまわし」が多いため、長期のブロックをしていると何らかの問題が発生することもあります。 (再利用までの期間が短い + クリーニングをしない事業者もいます)
特に仕事でやってる方は気をつけたほうが良いです。
また、この場合は必ずホワイトリスト運用もあわせて行ってください。
Source Dedicated Server (SRCDS)
Team Fortress 2 が play for free になったので、Ded鯖を立ててみることにしてみました。
昔 Quake 系はガンガン立てていたけれど、Source 系はさっぱりだし良い機会ということで。
Dedicated Server
ここでは主に PC ゲームの専用サーバ、俗にいうゲームサーバを指します。
主に家庭用ゲーム機ではプレイヤーの一人がホストとなってマルチゲームを行いますが、PCゲームの大半ではマルチプレイ専用のサーバを別途用意することが多いです。
環境
FreeBSD-7.1 (amd64)
SRCDS は FreeBSD 向けのバイナリはありませんが、Linux エミュレーションで FreeBSD でも動作します。
今回は OS 依存の部分はあまりないので、Linux でも同じ手法でできるはずです。
また、あんまりスペックは要求されないですが、回線は光必須と考えたほうが無難です。
上り回線が細い ADSL や安定しない CATV は諦めてください。
FreeBSD での Linux エミュレーション
方法は割愛。ports から fc10 を使っています。
カーネルモジュールを確認します。
azusa# kldstat | grep linux 7 1 0xffffffffb073f000 18a2c linux.ko
linprocfs を mount します。
azusa# cat /etc/fstab | grep linprocfs linprocfs /compat/linux/proc linprocfs rw 0 0
SRCDS
azusa# pwd /usr/ports/games/linux-steam azusa# make install clean (ライセンスの確認を行って問題なければ yes)
ただし、SRCDS は ports を使う恩恵があまりないので直接ダウンロードしてもいいかもしれません。
azusa# wget http://steampowered.com/download/hldsupdatetool.bin
SRCDS 実行ユーザの作成
これがポイント。実行ユーザのホームディレクトリに .steam ディレクトリが必要です。
そこそこ大きいファイルがダウンロードされるため、root ではなく専用のユーザを作成したほうが無難です。
(データファイルの保存場所が設定できないっぽい?)
ユーザを作成します。FreeBSD の場合。Linux は useradd コマンドを使ってください。
(pw に -m オプション付けずに面倒くさいことをやっているのはskel経由で生成されるファイルが邪魔だからだけです)
azusa# mkdir /home/steam azusa# pw useradd steam -d /home/steam azusa# chown steam:stream /home/steam
steam ユーザにスイッチして初期設定を行います。
steam 側のサーバの機嫌が悪い時には数回行う必要があります。
azusa# su - steam $ pwd /usr/home/steam $ mkdir .stream $ ./steam Checking bootstrapper version ... Getting version 44 of Steam HLDS Update Tool Downloading. . . . . . . . . . . .Steam Linux Client updated, please retry the command CAsyncIOManager: 0 threads terminating. 0 reads, 0 writes, 0 deferrals. CAsyncIOManager: 21 single object sleeps, 0 multi object sleeps CAsyncIOManager: 0 single object alertable sleeps, 0 multi object alertable sleeps
Team Fortress 2 サーバの構築
サーバに必要なファイルをダウンロードします。
CDNに乗っていないせいか結構時間がかかりますので、風呂にでも入って身を清めておきましょう。
オプション の -game で対象のゲームを指定します。今回は tf です。
$ ./steam -command update -game tf -dir . Checking bootstrapper version ... Updating Installation No installation record found at ./orangebox No installation record found at ./orangebox No installation record found at . No installation record found at . No installation record found at . No installation record found at ./orangebox Checking/Installing 'Team Fortress 2 Content' version 254 0.12% downloading ./orangebox/tf/bin/server.dll 0.29% downloading ./orangebox/tf/bin/server.dylib (このあと延々と)
サーバの cfg をいじります。
% cd orangebox/tf/cfg % vi server.cfg
Quake 系に近いので特に問題はないはずですが、マップを回すのは別ファイル (mapcycle.txt、maplist.txt)ぽい?
server cvar についてはググるとすぐ出てきます。
当たり前のことですが、テスト時には LAN モードにしてください。(sv_lan 1)
Team Fortress 2 サーバのテスト起動
コンソールから下記のコマンドで起動しみます。
azusa% orangebox/srcds_run -game tf +maxplayers 24 +map ctf_2fort
他のマシンで Team Fortress2 を起動して開発者コンソールから
connect <サーバの IP アドレス>
と実行してサーバに接続できるかを確認してください。
Team Fortress 2 サーバの起動
毎回コマンド打つのも面倒なので、起動用スクリプトを用意します。
FreeBSD なら $LOCALBASE/etc/rc.d あたりに設置します。
(Linux でも動くように依存した処理はいれていません)
azusa# cat tf2server.sh #!/bin/sh BASEDIR=/home/steam USER=steam CONSOLE_LOG=$BASEDIR/console.log su "$USER" -c "exec $BASEDIR/orangebox/srcds_run -game tf +maxplayers 24 +map ctf_2fort > $CONSOLE_LOG 2>&1" & exit
have fun :D
xenの DomainU として FreeBSD を動かす
ようやく作業が完了したので、まとめてみます。
環境と目的
ubuntu あたりを Xen のサーバとして使うほうが楽なのですが、家にいてまで必要以上に Linux は触りたくないので NetBSD で。
ちなみにノート PC には ubuntu 入れて使っています。軽作業ならこれで十分ですしおすし。
構築手順
FreeBSD の Xen 用カーネルを作る。
FreeBSD xen の ML を見ると pmap で panic する修正が入っているとのことだったので、CURRENT で作ります。
このあたりの色々な修正は RELENG 8.2 へ MFC されていないので、おとなしく CURRENT です。
(STABLE へは MFC されてます)
CURRENT を作るのは先日の日記を参照。
http://d.hatena.ne.jp/po3/20110515/1305460610
Xen 用のディスクイメージを作る
下記 URL を参照しました。
http://forums.freebsd.org/showthread.php?t=10268
ただし、ディスクイメージを作るときは truncate ではなくて dd コマンドで作っています。
# dd if=/dev/zero of=disk.img bs=1m count=2k
俗にいう穴あきファイル(sparse) はあんまりよく分からないし、VMWare でも qemu でもパフォーマンスがガタ落ちだったの dd でフルに容量を使って作成しています。
Linux だと virtio を使うとマシになるのですが、やっぱり根本的に遅いし、ディスクも安いのでキニシナイ!
作ったディスクイメージに色々するのは先日の日記を参照。
/etc/fstab を適当に弄って /etc/ttys に xc0 を追加してください。
http://d.hatena.ne.jp/po3/20110514/1305384444
Xen の設定ファイルを作る
これは単純に下記のようなファイルを用意します。
memory = 855 name = "FreeBSD_DOMU" kernel = '/usr/home/xen/FreeBSD-CURRENT/xen.kernel' disk = [ 'file:/home/xen/FreeBSD-CURRENT/disk.img,hda1,w', ] extra = 'boot_verbose,boot_single,kern.hz=100,machdep.idle_mwait=0,vfs.root.mountfrom=ufs:/dev/ad0s1a' vcpus = 1 on_poweroff = 'destroy' on_reboot = 'restart' on_crash = 'restart'
machdep.idle_mwait=0 はもういらないかもしれない。
起動してみます。
gomyway# xm create ./xen.cfg -c Using config file "././xen.cfg". Started domain FreeBSD_DOMU 3DNow!> AMD Features2=0x11f<LAHF,CMP,SVM,ExtAPIC,CR8,Prefetch> real memory = 896532480 (855 MB) avail memory = 866402304 (826 MB) [XEN] IPI cpu=0 irq=128 vector=RESCHEDULE_VECTOR (0) [XEN] IPI cpu=0 irq=129 vector=CALL_FUNCTION_VECTOR (1) [XEN] xen_rtc_probe: probing Hypervisor RTC clock rtc0: <Xen Hypervisor Clock> on motherboard [XEN] xen_rtc_attach: attaching Hypervisor RTC clock xenstore0: <XenStore> on motherboard xc0: <Xen Console> on motherboard Timecounters tick every 10.000 msec xenbusb_front0: <Xen Frontend Devices> on xenstore0 [XEN] hypervisor wallclock nudged; nudging TOD. xenbusb_back0: <Xen Backend Devices> on xenstore0 xctrl0: <Xen Control Device> on xenstore0 xbd0: 2048MB <Virtual Block Device> at device/vbd/769 on xenbusb_front0 xbd0: attaching as ad0 Timecounter "TSC" frequency 2109592000 Hz quality 800 WARNING: WITNESS option enabled, expect reduced performance. Trying to mount root from ufs:/dev/ad0s1a []... rtc0: [XEN] xen_rtc_gettime rtc0: [XEN] xen_rtc_gettime: wallclock 1306675669 sec; 965899053 nsec rtc0: [XEN] xen_rtc_gettime: uptime 665 sec; 6026720 nsec rtc0: [XEN] xen_rtc_gettime: TOD 1306676334 sec; 971925773 nsec Setting hostuuid: 0f12f2c1-8947-11e0-bda0-6389d0dd6e1d. Setting hostid: 0x419c4544. No suitable dump device was found. Entropy harvesting: interrupts ethernet point_to_point kickstart. Starting file system checks: /dev/ad0s1a: FILE SYSTEM CLEAN; SKIPPING CHECKS /dev/ad0s1a: clean, 835786 free (1474 frags, 104289 blocks, 0.1% fragmentation) Mounting local file systems:. /etc/rc: WARNING: $hostname is not set -- see rc.conf(5). Starting Network: lo0. lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384 options=3<RXCSUM,TXCSUM> inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL> Starting devd. add net ::ffff:0.0.0.0: gateway ::1 add net ::0.0.0.0: gateway ::1 add net fe80::: gateway ::1 add net ff02::: gateway ::1 Creating and/or trimming log files. Starting syslogd. /etc/rc: WARNING: Dump device does not exist. Savecore not run. ELF ldconfig path: /lib /usr/lib /usr/lib/compat a.out ldconfig path: /usr/lib/aout /usr/lib/compat/aout Clearing /tmp (X related). Updating motd:. Starting cron. Starting background file system checks in 60 seconds. Sun May 29 13:39:02 UTC 2011 FreeBSD/i386 (Amnesiac) (xc0) login:
なんとか起動しました。
TODO
とりあえず動かすところまではできましたが、メモリを 855MBよりも多くすると、また pmap で落ちます。
ルータとして動かすのでメモリはそんなにいらないので、この問題についてはスルーします。
USBメモリからXenServerをインストールしてみる
先日 Xen の DomU として FreeBSD を入れようと思ったものの、pmap_init で panic で落ちる問題はさっぱり。
そんな訳で現実逃避として XenServer をインストールしてみた。
インストール用の USB メモリを作る
何時買ったのかさっぱり思い出せない適当な 4GB の USB メモリからインストールしてみます。
自宅内のインストールサーバが停止中なので、わざわざ CD-R 焼くのは面倒だし、かなり地球に優しいエコじゃん. Jumping Now ってことで。
やることは
これだけ。ね、簡単でしょう?
FAT32 で USB メモリをフォーマットする
Windows 環境でやるなら HP USB Disk Storage Format Tool あたりで。
hp.com のどこにあるのかは分からなかったので詳細はググってください。
XenServer の ISO から USB メモリにコピー
Citrix のサイトから XenServer 無償版をダウンロードします。
http://www.citrix.co.jp/products/xenserver/download.html
ISO イメージをマウントできる適当なツール(DAEMON Tools Light)で、ISO の中身をそのまま USB メモリにコピーします。(すべてコピーする必要はないのですが、別に容量が足らないわけではないので)
次に USB メモリにコピーしたディレクトリとファイルをリネームする必要があります。isolinux から syslinux に変更します。
(例として G ドライブに USB メモリがささっている場合)
コマンドプロンプトでの例
C:\Users\popopo>g: G:\>move isolinux\isolinux.cfg isolinux\syslinux.cfg 1 個のファイルを移動しました。 G:\>move isolinux syslinux 1 個のディレクトリを移動しました。
syslinux でブートローダをインストールする
下記 URL から適当にダウンロードします。
http://www.kernel.org/pub/linux/utils/boot/syslinux/
D:\Download\syslinux-4.04> cp mboot\mboot.c32 g:\syslinux D:\Download\syslinux-4.04> cd win64 D:\Download\syslinux-4.04\win64> syslinux64.exe -am g:
として、必要なファイルを差し替えたのちブートローダを仕込みます。
mboot\mboot.c32 を USB メモリにコピーするのは、ISO 側の syslinux が Ver.3だから(多分)
このファイルを差し替えてやらないと、ローダで延々とエラー吐かれる。
(vesamenu.c32 も差し替えないと駄目なような…)
おまけ:1台の XenServer でなんとかする
仮想マシンを構築しようとしたものの、どうも ISO イメージは外部のストレージに置くことが前提、みたいな…
NFS サーバ作るのめんどい、samba サーバ作るのめんどいし、Windowsの共有フォルダがうまく動かない、ぐぬぬ。
ググったら下記のサイトが参考になりました。
http://www.noop.tk/index.php?XenServer
/home/iso に各 ISO イメージを格納する場合
# mkdir /home/iso # xe sr-create name-label="local iso" type=iso device-config:location=/home/iso device-config:legacy_mode=true content-type=iso fa54baf1-5ed0-e68a-873f-ed5257cce42d
おまけ:XenCenter 感想
起動が遅い(小学生並の感想)
これはハードウェアスペックに関係なく、サーバ自体の起動がやや遅いです(*BSDに比べて)
似たような製品の VMWare ESX に比べると対応しているデバイスドライバの数は多く、ハードウェア的な制限が低いのが利点、ぐらい。
XenServer の HCL。
http://hcl.xensource.com/
FreeBSD-CURRENT の環境を作る
Xen の DomainU で FreeBSD を動かしたいけれど、うまく動かないでの CURRENT の Xen kernel を作ってみることに。
FreeBSD CURRENT の作り方はハンドブックを眺めると書いてありますが、個人的にはあまりやらない作業なので、なにをやったかを記録しておきます。
やり方としては手抜きですが、仕事でやるときは丁寧にやってます、はい(明後日の方向を見ながら)
csup で使う supfile を作ります。これは cvsup のものを転用します。tag は . を指定します。
gomyway# cp /usr/share/examples/cvsup/standard-supfile /home/work gomyway# egrep -v '^#|^$' /home/work/standard-supfile *default host=cvsup3.jp.freebsd.org *default base=/var/db *default prefix=/usr *default release=cvs tag=. *default delete use-rel-suffix src-all gomyway# csup /home/work/standard-supfile
csup でソースを拾ってきてビルドします。kernel をインストールして新しい kernel で再起動します。
gomtway# cd /usr/src gomywat# make -j64 buildworld && make buildkernel && make installkernel gomyway# reboot
本来なら single mode で作業をすべきなのですが、手が届く端末ですし普通に。こういうことをやっていいのか、それとも駄目なのかは自分で判断してください。今回は素の試験環境なのでそのあたりは気にせずに。
installworld します。ややこしいことが嫌いなのでまたリブートします。
gomyway# cd /usr/src gomyway# make installworld gomyway# reboot
mergemaster で /etc を可愛がります。本来なら installworld の前にすべきなのですが、忘れてた。
また、面倒な mergemaster の代替ツールがあったはずなのですが思い出せませんでした。
gomyway# mergemaster
(cvd id を無視するの忘れてた)
本来の目的である CURRENT での Xen kernel を作ります。
gomyway# cd /usr/src gomyway# make buildkernel KERNCONF=XEN
前回手を抜いたビルドした kernel がどこに生成されるのかは…そりゃ /usr/obj 以下ですよね、アタシってほんと馬鹿。
gomyway# find /usr/obj -name kernel /usr/obj/usr/src/sys/XEN/kernel /usr/obj/usr/src/sys/GENERIC/kernel
installkernel 時になにかやっているわけではなさそうなので、ここから kernel をコピーします。
gomyway# sha256 /boot/kernel/kernel SHA256 (/boot/kernel/kernel) = caeef8f9882d7538c5a8f38e2488822b48f43f6fafdece80c8efade6ca548956 gomyway# sha256 /usr/obj/usr/src/sys/GENERIC/kernel SHA256 (/usr/obj/usr/src/sys/GENERIC/kernel) = caeef8f9882d7538c5a8f38e2488822b48f43f6fafdece80c8efade6ca548956m
こんな感じ。
本来の目的である DomainU での FreeBSD は状況変わらず。
# xm create -c ./xen.cfg Using config file "././xen.cfg". Started domain FreeBSD8.22_i386_DOMU WARNING: loader(8) metadata is missing! GDB: no debug ports present KDB: debugger backends: ddb KDB: current backend: ddb Copyright (c) 1992-2011 The FreeBSD Project. Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD is a registered trademark of The FreeBSD Foundation. FreeBSD 9.0-CURRENT #1: Sun May 15 18:55:50 JST 2011 admin@gomyway.continue:/usr/obj/usr/src/sys/XEN i386 WARNING: WITNESS option enabled, expect reduced performance. panic: pmap_init: page table page is out of range cpuid = 0 KDB: enter: panic [ thread pid 0 tid 0 ] Stopped at 0xc0119c4a: movl $0,0xc0423af4 db>
どうするかね、これ。
FreeBSDのXen Kernelを作る
放置するのもなんですし、日々の調べ物を書くチラシの裏として活用しようかと。
しかしながら、内容が小出しになる、もしくは途中で無駄だと判断して中断することもあるので、答えが知りたくてググッてきた人には悪いかもしれません。
んじゃ、本題。
NetBSD 5.1 (AMD64)で動いている Xen 環境に DomainU として FreeBSD を動かしたいので、準仮想化用に使う Kernel を作ってみました。
いつもの方法で kernel を作ります。
gomyway# uname -rm 8.2-RELEASE i386 gomyway# cd /usr/src/ gomyway# make buildkernel KERNCONF=XEN
ここでちょいと迷ったのが、どこにビルドされた kernel があるのか分からない。面倒になったので、適当なパーティションを作ってそこにインストールしてから取り出すことにしてました。
適当にイメージファイルを作って mdconfig でメモリディスクをアタッチします。
gomyway# dd if=/dev/zero of=/home/freebsd8.2.img bs=1m count=1024 gomyway# mdconfig -a -t vnode -u 0 -f /home/freebsd8.2.img
ファイルシステムを作って bsdlabel で fstype を 4.2BSD に変更します。
gomyway# bsdlabel -w /dev/md0 a gomyway# bsdlabel -e /dev/md0 gomyway# newfs /dev/md0a
mount します。
gomyway# mount /dev/md0a /mnt
メモリディスクにカーネルをインストールします。
gomyway# cd /usr/src gomyway# make installkernel DESTDIR=/mnt KERNCONF=XEN
これで /mnt/boot/kernel/kernel に Xen kernel があります。
これを Xen ホストにコピーして DomainU として起動してみますが… OS起動時にpmap_init で落ちる。
# xm create -c freebsd.conf (snip) panic: pmap_init: page table page is out of range
ワケがわからないよ。
ググッてみたら、AMD特有の問題のようで 2011年1月ぐらいにFIX入っているみたいなので、後日CURRENT で Xen Kernel を作ってもう一度トライしてみます。