XamarinでAndroidアプリ公開(内部テスト)

VisualStudio2019のXamarin.Formsでのバーコードアプリ開発ですが、テスト版をGoogle Playにリリースしました。 つまづいたポイントをメモ。

(1)ReleaseモードにしてProGuardでコンパイルしたらエラー

「 ”java.exe” はコード 1 を伴って終了しました。」

というエラーです。直接の解決はできなかったのですが、下図の通りshrinkerを「ProGuard」から「r8」に変更したらエラーが出なくなりました。これに伴い、Dexコンパイラも「d8」に変更しています。なんだったんだろうか?

(2)文字コードのエラー

履歴データをCSVで吐き出す機能を付けたのですが、文字コードにShift-JISを使っていて、ReleaseモードでCSV出力するとエラーになりました。

デバッグモードのときは「共有ランタイムの使用」が有効になって問題は出なかったのですが、以下のように、「サポートされているその他のエンコーディング」で「CJK」を指定すればReleaseモードでもOKでした。

(3)Rsourceに指定した画像ファイルが画面に表示されない

全く原因が分からなかったのですが、Xamarin.Formsのバージョンを上げたら治りました。よく分からんです。

「4.8.0.1451 → 4.8.0.1534」

メイン画面のメニューボタンはにイメージボタンを使っていたので、起動したら真っ黒な画面しか表示されなかったときは少し焦りました。デバッグモードの時は問題なかったのですが・・・。

(4)2020年8月からAndroid9.0のアプリは新規公開できなくなった

Releaseモードで手持ちのスマホでは問題がなくなったところでGoogle Playへの公開作業です。

そして、、、Google Play Consoleでのアップロードの途中で「Android10以降で作ってね」とエラーになりました・・・。

知りませんでした。ターゲットフレームワークはAndroid9.0で作っていました。後戻りして最初からコンパイルしなおしです。

(5)Android10に上げたらコンパイルエラー

振り出しに戻ったら、一歩目でいきなりエラーです。まあ、しょうがないですね。ここはがまんのしどころです。

java関連のエラーがうじゃうじゃと10件以上。

開発環境のOSはWindows10。nugetパッケージの参照パスが漢字のユーザー名を含むパスになっていて、こいつが悪さをしていたようです。ユーザーをAdministratorに切り替え、参照パスに日本語文字を含まないようにしてからコンパイルするとうまくいきました。

日本語を含む参照パスが悪さをすることって時々あるけど、Android9.0のときはエラーにならなかったのは今でも不明。おかげで気づくまで半日ほどかかってしまった。

こんな感じで回り道しながらも、ようやく内部テスト版を公開できました。

今日はここまで。

ZXingでバーコードアプリ開発(4)

やっと、Xamarin.Formsのアプリとして詰め込みたい機能がそろってきたのでテストフェーズに入ってきたんですが、ここでZXingのバグに気づきました。

バーコードをスキャンする際、ZXing.Net.Mobileを使って ZXingScannerView のインスタンスをコードで生成して画面表示しています。

インスタンス生成のコードはこんな感じです。

//使っているZXing.Net.Mobile.Formsのバージョンは v3.0.0-Beta5

//スキャン可能なBarcodeフォーマットの一覧
List<ZXing.BarcodeFormat> barcodeFormats = new List<BarcodeFormat>
{
    BarcodeFormat.QR_CODE,      //QR
    BarcodeFormat.CODABAR,      //NW-7 (JANCODEよりはBARが短くて済む)
    BarcodeFormat.CODE_128,     //CODE128, GS1-128
    BarcodeFormat.CODE_39,      //CODE39
    BarcodeFormat.CODE_93,      //CODE93
    BarcodeFormat.DATA_MATRIX,  //DataMatrix
    BarcodeFormat.EAN_8,        //JANCODE (8桁)
    BarcodeFormat.EAN_13        //JANCODE (13桁)                    
};

//インスタンス生成 
zxing = new ZXingScannerView()
{
    HorizontalOptions = LayoutOptions.FillAndExpand,
    VerticalOptions = LayoutOptions.FillAndExpand,
    AutomationId = "zxing",
    IsScanning = true,
    IsAnalyzing = true,
    Options = new ZXing.Mobile.MobileBarcodeScanningOptions
    {
        UseFrontCameraIfAvailable = false,  //フロントカメラの設定
        TryHarder = true,                   //厳しめに解析(速度が遅くなる)
        PossibleFormats = _barcodeFormats,  //バーコードフォーマット指定
        AssumeGS1 = true,                   //GS1の読み込みに必要
        UseNativeScanning = false,          //iOSのスキャナエンジンを使う場合に必要
        AutoRotate = true,                  //90度回転して解析するかどうか
        DisableAutofocus = true      //オートフォーカス
    }
};

ここで気づいたのですが、例えば後から CODE_39 をPorssibleFormats から外す処理を実行しても、残念なことに CODE_39 が読み込めてしまうんですね。PossibleFormatsを絞り込むとバーコードの読み取り速度が上がるので、重要な設定です。

でも、PossibleFormats をCODE_39を外した状態でインスタンスを再作成する方法だと、CODE_39は読めなくなり期待通りの動きをします。

どうやら、都度、インスタンスを作り直さないと設定変更が反映されないということみたいですね。 PossibleFormatsだけでなく、他のプロパティも疑った方がいいかもしれません。

なにかしらの読み込み設定の変更処理を行うときは、インスタンスを作成しなおすようにコード修正することにしました。

ZXingでバーコードアプリ開発(3)

GS1-128, GS1 DataMatrixの生成時にFNC1を埋め込む件

GS1を扱うときにFNC1の処理は避けて通れないのですが、ZXingがFNC1をどう扱っているのかが不明でした。日本語のページでもそのことに言及しているサイトが見つからなかったので、ZXingでエンコードしたバーコードをデコードしてRawデータを確認することにしました。

FNC1をバーコードに埋め込むルールは以下の通りです。

(1)可変長のセクションの後に付ける

  AI(10)のロットや、AI(30)の入り数などにおいて、セクションの終わりの印として使います。これは、GS1-128 と GS1 DataMatrix の両方に共通するルールです。

(2)GS1-128のスタートコードの後に付ける

  GS1-128とCODE128を区別するため、スタートコードの後にFNC1を埋め込むことになっています。

(3)GS1 DataMatrixの先頭

  GS1 DataMatrixでは必ずFNC1を先頭に付けます。

尚、読み取り(デコード)時はFNC1は「GS (グループセパレータ)」に置き換えて出力することになっています。 GSはASCIIコード29の制御文字なので、印刷しても出力されません。そのため、市販のバーコードスキャナではGSをスペースに置き換えるなどの機能がついていたりします。

で、ZXingでバーコードを生成するときに、FNC1やSTARTコードをどのように指定すればよいのかを調べたところ、以下の通りとなりました。

表.ZXing.BarcodeWriterのGS1エンコードの動作

フォーマットコード解釈C#でZxingに
渡す文字
バーコード内のコード
GS1-128105START C不要 (注1)105
GS1-128102FNC1(char)0x00F193 (注2)
GS1 DataMatrix232先頭のFNC1(char)29232 (注3)
GS1 DataMatrix232可変長項目の
終端につけるFNC1
(char)2930(注4)

【注1】 ZXingではBarcodeFormatの値を「CODE_128」に指定すると自動的にスタートコードとして「105」が埋め込まれます。 ちなみに、文字列の途中でアルファベットを検知すると「CODE B」への切り替え文字も自動的にバーコードに埋め込んでくれます。

【注2】 GS1-128での「93」は制御文字「GS (ASCII 29)」を表します

【注3】 GS1 DataMatrixでは先頭は必ずFNC1と決められています。ZXingはBarcodeFormatの値を「DATA_MATRIX」にすると、GS (ASCII 29)を「232(FNC1)」に変換してバーコードに埋め込んでくれます。

【注4】 ZXingはBarcodeFormatを「DATA_MATRIX」にすると、先頭以外のGS (ASCII 29)は 「30 (GS)」をバーコードに埋め込みます。

例えば、C#で書くとこんな感じになります、、

// (01)14512345678903(10)ABCD123(17)201201 をエンコードする例
//writer.Optionsによる画像サイズや余白マージンの指定などはここでは省きます

BitMatrix bitMatrix;
ZXing.BarcodeWriterPixelData writer = new BarcodeWriterPixelData();
string _code;

//GS1-128の場合
writer.Format = BarcodeFormat.CODE_128;
_code = $"{(char)0x00F1}"
      + "0114512345678903"
      + "10ABCD123" + $"{(char)0x00F1}"
      + "17201201";
bitMatrix = writer.Encode(_code);  

//-----------------------------------
//bitMatrixからBitmapを作成する処理 (省略)
//-----------------------------------


//GS1 DataMatrixの場合
writer.Format = BarcodeFormat.DATA_MATRIX;
_code = $"{ (char)29}" 
      + "0114512345678903"
      + "10ABCD123" + $"{ (char)29}" 
      + "17201201"
bitMatrix = writer.Encode(_code);

//-----------------------------------
//bitMatrixからBitmapを作成する処理 (省略)
//-----------------------------------

調査してみて、、、

DataMatrixの可変長項目のFNC1に「GS(ASCII 29) を指定すると、コードワード232を指定したことになる」っていうところが分かりにくかったですね。コードワードにも「30」というGSを表すコードがあるのがややこしい・・・。調査に何日かかかってしまいました。

ZXingでバーコードアプリ開発(2)

前回の投稿の続きです。

2値画像化してからのバーコード認識にトライしていましたが、ようやくできました! とりあえずは。

Xamarin.AndroidのコードなのでAndroid限定ですが、Android.Hardware.Camera2 のキャプチャ画面からByte配列の画像データを取得するところは、

https://github.com/vtserej/Camera2Forms

を参考にしました。

このサンプルの中にある CameraViewServiceRenderer.OnPhoto() にて、画像のバイト配列が取得できるようになっています。

private void OnPhoto(object sender, byte[] imgSource)
{
    //imgSourceにカメラビュー画像が入っているので、
    //ここで煮るなり焼くなり


    Device.BeginInvokeOnMainThread(() =>
    {
        _currentElement?.PictureTaken();
    });
}

AndroidのCamera2からシャッター音を鳴らさずに無音で画像を取得するには、このサンプルがちょうどいいかと思います。

画像はARGB画像です。ARGBの4種類がそれぞれ1バイト(256諧調)なので、1ピクセル4バイトになります。

2値化画像にする手順は、

  • グレースケール化(RGBの3色の数値を平均化する)
  • 閾値を決めて、1ピクセルごとに「0 or 255」にする

ということになります。

これも変換関数を作って何とかなりました。・・・が、肝心のバーコード認識率はほとんど変わりませんでした。

それぞれ、生画像、グレースケール、2値化画像を比較したのですが、2値化の段階で1次元バーコードの斜め線になったところが「ギザギザ」になっていました。

また、照明の当たり具合はバーコードの部分ごとに異なることが当然あります。すると、ハレーションのような現象が出て、バーコードが部分的につぶれてしまいます。

下の画像は桁数がまあまあ多いGS1-128のバーコードで、真ん中あたりが照明で明るく照らされていたものです。

2値化したことにより、バーコードそのものが部分的にかすれてしまっています。

つまり、単純な2値化の閾値設定では状況の変化に対応できず、意味がないことが分かりました。今まで画像処理に縁がなかったのですが、なかなか手ごわいです。

画像処理のサイトを検索すると、いろいろな画像処理のテクニックがあるようですが、今のところ有効そうなのは、

  • カメラビューまたはグレースケール化のタイミングで解像度を上げる
  • 閾値方式だけではなく、周囲のピクセルとの比較によって白 or 黒を決定し、なめらかな線を目指す
  • 1ピクセルあたりのバイト数を減らす (高速化のため)

といったところでしょうか。(自分にできるのか不安)

GooglePlayを漁っていると、GS1-128でアルファベットや桁数を多く含み、しかも撮影条件が悪くても高速に読み取るソフトが中には存在します。キーエンスのハンディターミナルと同等レベル? ってぐらい優秀です。

一体、どうやって実現しているんだろうか?

[追記 2020-09-11]

GS1-128の読み取りが悪いですが、逆に、GS1-128以外はそれなりの読み取り速度なので、画像処理は時間がかかりそうなのであきらめました。今後の努力課題として、取り急ぎGS1 DataMatrixの生成処理をすることにしました。

ZXingでバーコードアプリ開発

最近、スマホアプリ開発の勉強として VS2019のxamarinとC#とZXingの組み合わせでAndroid版のバーコードアプリを作っています。

バーコードの読み取り、書き出しの両方に対応させようとしていますが、おかげで、かなり勉強になりました。

GS1-128のFNC1のエンコードを通して文字コードの勉強になりましたし、QRコードはデンソーウェーブの登録商標であるとか、デンソーウェーブがQRコードサービスで位置情報を無断で収集していたとか、興味深い情報も初めて知りました。

最初は雑誌のQRコードを読み込んでから自作アプリでエンコードすると同じ模様のQRコードが作れなくて悩みました。

バーコードは枯れた技術ですが奥が深い・・・。

ちなみに、バーコードSDKのZxingには問題がいくつかあったのでメモ。

(1)ZXingScannerViewが頻繁にフリーズ

バーコードをスキャンしてからスキャン結果の画面に移動し、再びZXingScannerViewを埋め込んだ画面に戻るとZXingScannerViewがわりと簡単にフリーズします。こちらは、ZXing.Net.Mobileが2020年3月に2年ぶりにバグ修正をして更新されています。バージョンは「3.0.0-beta5」とベータ版なのですが、こちらにアップデートするとフリーズしなくなりました。

NuGetで検索キーワードに「ZXing.Net.Mobile」を指定する際に「プレリリース」にチェックを入れると開発環境にインストールできます。

(2)EAN13やEAN8、GS1-128の下段の数字が印字できない

バーコードを作成するときのオプションで「PureBarcode」プロパティがあります。EAN13などは通常、下段にバーコードモジュールの下部に数字が印字されますが、この「PureBarcode」をfalseに設定すると数字も一緒に出力されます。

しかし、

ZXing.BarcodeWriterPixelData writer = new BarcodeWriterPixelData();

writer.Format = BarcodeFormat.EAN_13;

writer.Options.PureBarcode = false;

としても、バーコード画像の下段にエンコードする前の数字が印字されません。どうやら、Androidでは有効にはならないようです。

対策として、自分で数字のBitmapを作ってCanvasオブジェクトで重ね合わせれば何とかなります。力技ですね。

(3)GS1-128などの高密度の1次元コードの読み取りが極端に弱い

ZXingScannerViewを使っているのですが、わりとQRコードなどは高密度でもすんなりとデコードしてくれます。しかし、GS1-128などの高密度の1次元コードは全然、読み込んでくれません。でも、他社さんのスマホバーコードアプリで高速読み取りを謳い文句にしているソフトは速攻でGS1-128も読み込みます。

違いはなんだろ・・・?

そこで、「ZXing 認識率」で検索すると結構、対策がヒットします。2値画像処理など、まだまだやれることはありそうです。

ZXingScannerViewに頼らず、カメラ画像を加工してからZXingに食わすのがいいのかもしれません。

「子供がスマホで勝手に課金」を解決

6歳の子供が「マリオカートツアー」というスマホアプリをやりたがったので、私のスマホにインストールしたら、Google Pay経由で勝手に3,300円が課金されてしまいました(泣)。

このアプリ、すぐに課金画面に誘導します。しかも、誘導のタイミングなどが結構、エグい感じです。任天堂ってこんなに「カネよこせ~」って感じでしたっけ? 

まあ、とにかくGoogle Payなどの課金システム側でなんとかする必要があるのでしょう。

そこで、親のGmailアカウントでGoogleにWebブラウザでログインした後、「ファミリー(https://families.google.com/families)」という機能を使えば何とかなることが分かり、以下の作業をしました。

(1)古いAndroidスマホを子供専用に準備

(2)子供専用のGmailアカウントを作成し、親のGmailアカウントを管理者としたファミリーグループの子供メンバー(18歳以下)として紐付け

(3)子供専用スマホに子供用Gmailアカウントを登録・紐付け作業

(4)親のスマホに「保護者向け Googleファミリーリンク」という管理ソフトをインストール

これで子供のスマホは親のスマホの完全な管理下に収まりました。

・許可を与えたアプリだけがパケットを使うことができる

・利用時間の上限が設定できる

・課金は基本的にできない

・アプリのインストールは親のGmailへの承認申請が必要

・子供のスマホの位置情報が取得できる

その他、多くの設定が用意されています。

とまあ、Googleのファミリーのしくみを導入すれば、完全に子供用スマホとして簡単に管理できます。このおかげで、こんな会話になりました。

子供「次の画面に進めない!」

私 「ライフがなくなったからでしょ。時間が経過したらまた遊べるよ」

子供「・・・」

私 「お勉強したら? その間にライフが貯まるんじゃない?」

子供「・・・お勉強する」

Googleのファミリーアカウントのおかげで「勝ったな!」という気持ちになりました。もちろん、子供にではなく、あの手この手で課金しようとする任天堂に対してです。

アプリごとの利用時間をグラフ表示もできるので、遊び過ぎていないかどうかを親のスマホで確認できます。

キャンペーン中の楽天モバイル UN-LIMITのSIMを使えば、外出先でも1年間は無料で使えますな~。iPhoneは確認していないのですが、古くて余っているAndroidがあれば、高価なゲーム機はいらないのでは?

vApp自動起動

Citrix HypervisorでvAppを使うとVM(仮想マシン)をグループ化し、複数のVMを指定した順番で起動したりシャットダウンしたりできるようになりますが、vAppには自動起動が備わっていません。

vAppの作成そのものはXenCenterを使って上図の画面で簡単に設定できます。しかし、vAppの自動起動の設定項目がXenCenterに見当たりません。

vAppを手動で起動する場合、以下のようにXenCenterで別のマシンからHypervisorに接続してから「Start vApp」をクリックする必要があり、少々面倒です。

そこで、vAppを自動起動するためにスクリプトの力を借ります。

HypervisorにTeraTermを使ってSSH接続し、以下の内容でスクリプトを作成します。

#AutoStart XenServer vApps with the tag autostart in their description
# Script originally created by Raido Consultants - http://www.raido.be
# Script updated and shared by E.Y. Barthel - https://www.virtues.it
TAG="autostart"

# helper function
function xe_param()
{
    PARAM=$1
    while read DATA; do
        LINE=$(echo $DATA | egrep "$PARAM")
        if [ $? -eq 0 ]; then
            echo "$LINE" | awk 'BEGIN{FS=": "}{print $2}'
        fi
    done
} # Get all Applicances
sleep 20
VAPPS=$(xe appliance-list | xe_param uuid)
for VAPP in $VAPPS
do
    # debug info
    # echo "Esther's AutoStart : Checking vApp $VAPP"
    VAPP_TAGS="$(xe appliance-param-get uuid=$VAPP param-name=name-description)"
    if [[ $VAPP_TAGS == *$TAG* ]]; then
        # action info:
        echo "starting vApp $VAPP";
        xe appliance-start uuid=$VAPP;
        sleep 20
    fi
done

(引用元:https://www.virtues.it/2014/12/step-by-step-guide-automatically-start-a-vapp-on-xenserver/

このスクリプトを以下のパス、ファイル名で保存します。

/opt/autostartvapps.sh

次にviエディタでrc.localを編集し、先ほどのスクリプトが電源投入時に自動実行されるようにします。

vi /etc/rc.d/rc.local

以下の内容を追記して保存します。余裕を見て、40秒待機してからスクリプトを実行するようにしています。

sleep 40

sh /opt/autostartvapps.sh

最後にパーミッションを調整して終了です。

chmod u+x /etc/rc.d/rc.local

これで、次回からvAppが自動起動されるようになりました。

Asteriskを使ってみる(1)

Asteriskをインストール

以前、スマホを自宅の子機にする話を書いたのですが、その後、フリーのIP-PBXであるAsteriskにも興味が沸いたので構築してみることにしました。

とりあえずの目標は「ひかり電話の着信をIP-PBXを介し、指定したスマホで受ける」です。その先は鳴り分けとかもやってみたいですね。

まあ、とにもかくにもフリーのIP-PBXであるAsteriskのインストールですね。voip-info.jp様のページを参考にしてインストールしました。結構、いろんな組み合わせを試しましたが、最終的には以下の組み合わせで構築しました。

ハイパーバイザ:Citrix Hypervisor 8.1

OS:CentOS 6.10

IP-PBX:Asterisk1.6

(1) CentOS 6.10のセットアップ

CentOS6.10用のVMをHypervisorに作ります。今回はストレージを30GBで割り当てました。仮想DVDにはCentOS 6.10 のインストール用ISOをダウンロードしてセットします。

あとはServerモードでGUIなしのインストールをし、ネットワークの設定(/etc/sysconfig/network-scripts/ )を確認し、プライベートの固定IPを割り当てておきます。

(2) Asteriskのダウンロード

Asteriskのバージョンは1.6を選定しました。ネットでも情報が多そうなのと、新しすぎず、古すぎずといったところで選びました。 (実はCentOS8 + Asterisk1.8 や、 CentOS 7 + Asterisk1.3 も試したりしました。いずれも、私の環境ではコンパイルエラーになったり、Asteriskが起動できても停止と起動を頻繁に繰り返したりとうまくいきませんでした)

#Asterisk 1.6ダウンロードと展開

wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-16-current.tar.gz

tar zxvf asterisk-16-current.tar.gz

cd asterisk-16

(3) Asteriskのコンパイル準備

各種ツールをインストールします。

#開発ツールのインストール

yum install wget bzip2 patch

yum install subversion

yum install gcc gcc-c++

yum groupinstall “Additional Development”

yum groupinstall “Development tools”

yum install libxml2 libxml2-devel openssl-devel ncurses-devel sqlite-devel newt-devel libuuid-devel libedit-devel

#json-c

yum install json-c json-c-devel

#mysql

wget https://repo.mysql.com/yum/mysql-connectors-community/el/8/x86_64/mysql-connector-odbc-8.0.19-1.el8.x86_64.rpm

yum install mysql-connector-odbc

yum install unixODBC unixODBC-devel mysql-connector-odbc

yum install libtool-ltdl libtool-ltdl-devel

最後にインストール済みパッケージをまとめてupdate。

#update

yum update

ここまでできたらコンパイルの準備OKです。

(4) Asterisk 1.6 インストール

いよいよAsterisk1.6をコンパイルしてインストールします。

#configure

./configure –with-jansson-bundled

あと、日本語音声ファイルを追加するためにAsteriskの日本語音声モジュールを追加するためにmenuselect画面で「CoreSoundPakages – CORE_SOUNDS_JA_*」 にチェックをつけます。

#Asteriskモジュール選択

make menuselect

#インストール実行

make

make install

make samples

make config

ここまでエラーが出なければもうひと踏ん張りです。

この後、Asterisk1.6の設定サンプルファイルをダウンロードして配置します。

#Asterisk1.6 サンプルファイルダウンロード元

https://voip-info.jp/downloads/asterisk/conf/


#Asteriskの設定ファイル配置場所

/etc/asterisk

(5)実行権限設定

この後、Asteriskをrootで実行しないようにするために、ユーザー「asterisk」を作成して権限を割り当てます。

#パーミッション設定

groupadd asterisk

useradd -d /var/lib/asterisk -s /sbin/nologin -g asterisk asterisk

chown -R asterisk:asterisk /var/lib/asterisk

chown -R asterisk:asterisk /var/log/asterisk

chown -R asterisk:asterisk /var/spool/asterisk

chown -R asterisk:asterisk /etc/asterisk

chmod -R u=rwX,g=rX,o= /var/lib/asterisk

chmod -R u=rwX,g=rX,o= /var/log/asterisk

chmod -R u=rwX,g=rX,o= /var/spool/asterisk

chmod -R u=rwX,g=rX,o= /etc/asterisk

「vi /etc/asterisk/asterisk.conf」の設定変更も必要です。 runuser, rungroupを「asterisk」に設定します。作業としてはコメントアウトされていたrunuserとrungroupを探して、コメントアウトを外すだけでした。

(6) 起動確認

最後にasteriskを起動して実行ユーザーを確認します。

#起動確認

/etc/init.d/asterisk start

/etc/init.d/asterisk status

ps -u asterisk

これで一応、Asteriskのインストールは完了です。

尚、この後、SIPクライアントから接続できるようにファイアウォールの設定変更が必要です。OSで iptables が自動起動されるようになっていたので、Asteriskが利用できるようにするために5060番のポートを開放する必要がありました。

ディスクの使用容量は以下の通りで、30GBのうち16%しか消費していませんでした。

メモリは2Gしか割り当てていませんが、私一人でテストするだけなので、とりあえずはこれで十分。

Citrix Hypervisor にSRを追加

先日購入したマザーボードASUS H310M-A R2.0 のマシンにCitrix Hypervisor Express Edition (無償版)をインストールして、LinuxやWindowsのVM (virtual machine)を構築しました。

あとはバックアップの方法ですが、メールや文書ファイル、資料などはOffice 365 (Microsoft 365)でクラウド保管なので、何らかのシステム変更があったときだけディスクイメージを取るというやり方です。

ディスクイメージはバックアップソフトでも取れますが、Hypervisorにストレージを追加してVM Copyを実行するのがお金もかからず手っ取り早いです。

いざというときはコピーしておいたVMをそのまま起動しちゃえば復活です!

この方法なら、リカバリ時間はほぼゼロ。とっても楽です。

大規模になれば「どこに冗長化を置くのか」「復元ポリシーをどう定義するのか」などを入念に検討する必要がありますが、小規模な開発環境のバックアップならとりあえずSRを増やして、SRをとっかえひっかえして小回りよく動くことが得策かと思います。

今回は手元に古いHitachiの1TBのSATAのHDDがあったので、これをHypervisorのSR(Storage Repository)に追加します。

XenCenterでコンソールを開き、fdiskコマンドで追加したハードディスクを初期化して単一パーティションを作成した後、「ll /dev/disk/by-id」でHitachiのディスクがsdb1として認識されていることが確認できました。

後はコンソールにて以下の手順でHDDをSRに登録します。

(1) host uuid を調べる

# xe host-list

(2) SR作成します。「Local Hitachi_HDE721010SLA330」という名前で作成しました。 ここでSRのuuidが生成されますのでメモしておきます。

# xe sr-create type=lvm content-type=user host-uuid=<host uuid> device-config:device=/dev/sdb1 name-label=”Local Hitachi_HDE721010SLA330″

(3) SRをスキャンしてエラーが出ないことを確認します。 尚、ローカルハードディスクを使う場合は typeパラメータを「lvmohba」にします。iSCSIなら「lvmoiscsi」、 NFSなら「nfs」を指定します。

# xe sr-probe type=lvmohba device-config:device=/dev/sdb1

(4) SRのuuidをイントロデュースします

# xe sr-introduce uuid=<sr uuid> shared=false type=lvmohba name-label=”Local Hitachi_HDE721010SLA330″

(4) SRに添付するPBDを作成します。これにより、新規PBDのUUIDが返されます。

# xe pbd-create sr-uuid=<sr uuid> device-config:device=/dev/sdb1 host-uuid=<host uuid>

(5) 作成したpbdをプラグします。

# xe pbd-plug uuid=<pbd uuid>

以上をもってXenCenterにてSRが追加されたことが確認できました。めでたし。

尚、SRを他のHypervisorで使いたくなったら、「xe pbd-list」でpbd uuidを確認してからアンプラグしてHypervisorから離脱させ、移動先のHypervisorでさきほどの手順を実行してプラグしてやれば、SR内のデータを壊さずに復元できます。

# xe pbd-list

# xe pbd-unplug uuid=<pbd uuid>

# xe sr-forget uuid=<sr uuid>

参考URL: https://support.citrix.com/article/CTX220536

しかし、あれですね、Citrix XenServerから製品名を変えたCitrix Hypervisorの行く末はどうなるのでしょう? 

管理ツールはなぜか「XenCenter」から名称が変更されておらず、Xenの名が残っていますが・・・。

無償版のハイパーバイザはKVMが人気のようで、自分は10年以上もXenServerを触っているので慣れているというだけで使っています。今後、KVMの勢力がどれぐらい大きくなるのかが気になります。