まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:windows

趣味で古い PC の環境を残しているのですが、しばらくの間、動作確認ができなかった環境を動作させることに成功した時の話です。同じ悩みを持つ人はほとんどいないと思っていますが、備忘録としてブログエントリに残しておきます。


【KVM 環境下の Windows7 内で Virtual PC を動かす必要に迫られた背景】
もともとはずっと OS/2(Warp 4) が動作する環境を残しておきたいと思っていました。最大の理由は「ノーツのバージョン1」が動く、数少ない環境だから」です。それ以外だと同様にして DOS 版 Lotus 1-2-3 や懐かしい DOS ゲームが動くという意味での PC-DOS が動作する環境も残しておきたいと思っていました。ちなみにこれらのインストールメディアは OS 含めて今も持っています。

この環境を残す、という目的のためだけに、しばらくの間は実際にこれらが導入された PC (OS/2 は IBM Aptiva、PC-DOS は東芝 Libretto)を残していました。西暦 2000 年頃の話です。

ただ「個人管理でハードウェアを残す」のはやはり大変でした。なにしろ「滅多に電源すら入れない PC を決して広くもない家に捨てずに残しておく」わけです。ソフトウェアやハードウェアの知識も陳腐化してゆきます。

転換期となったのは「仮想化ソフトウェア」でした。VMWare Workstation をはじめとする PC の仮想化により、ハードウェアそのものは不要となり、ハードディスクをイメージ化することで、ソフトウェアだけでこれらの環境を残すことが可能になりました。PC-DOS は今でも多くの仮想化ソフトウェアで動作しますが、OS/2 が動く仮想化ソフトウェアはあまり多くありませんでした。しかし Microsoft Virtual PC だけは当初のバージョンから OS/2 も動かすことができ、OS/2 を仮想環境下で動かすことが可能となりました。これを知った直後から自分は当時使っていた Microsoft Windows 環境内で Virtual PC を使って OS/2 と PC-DOS 環境を仮想化して残すことができました。

時は流れ、Windows 7 のサポート終了(2020/01/14)が近づくと、多くの Windows 7 ユーザーが Windows 10 へと環境移行しました。自分もメイン機は早々と Windows 10 へ乗り換えました。が、この Windows 10 では Virtual PC は動作しない(サポートされないではなく動作しない、インストールもできない)という問題がありました。ずっと残してきた OS/2 や PC-DOS 環境は Virtual PC 環境向けのイメージとなっていて、動かしていた当時のハードウェアはとっくに残してありません。Virtual PC を動かすためには Windows 7 が必要となり、Windows 7 を動かすためだけに専用の PC を残しておく必要があり、・・・となってしまうと元々上述した問題と同じことになってしまいます。

そこで考えたのが「仮想環境化で Windows7 環境を作り、その中に Virtual PC をインストールすれば今の OS/2 や PC-DOS の仮想資産を残すことができる」でした。当時の自分は Linux をベースとした仮想化システムに興味があり、当時の CentOS 6 の標準機能でもあった KVM を使った仮想環境構築にはある程度慣れていました。このような紆余曲折を経て KVM 環境化に Windows7 をインストールして、その Windows7 内で Virtual PC を使うという環境が生まれることになりました。


【KVM 環境下の Windows7 内で Virtual PC を動かしてわかった問題点】
KVM はある程度わかっているつもりでしたので、KVM 環境で Windows7 の仮想マシンをインストールして動かすこと自体は問題ありませんでした。またその環境にVirtual PC(2007) をダウンロード&インストールすることも普通にできました。あとは Virtual PC を実行して新しい仮想マシンを既存の(PC-DOS と OS/2 それぞれの)イメージファイルを使って作るだけ、と思っていました。

が、ここで大きな問題が発生しました。KVM 環境の Windows7 にインストールした Virtual PC を実行しようとすると、実環境下ではみたことがない以下のようなエラーが発生してしまいました。Virutal PC の実行直後(既存の仮想マシン一覧が表示される前)にこのエラーが発生してしまうため、実行を諦める以外の選択肢がありません:
2020122601


このエラーメッセージ(「このコンピュータの物理プロセッサとは互換性がありません」)の意味がわかりにくく、最初は 64 ビット版の Virtual PC と間違えて 32 ビット版の Virtual PC をインストールしてしまったのかと思いましたが、この推測は間違っていました(64 ビット版 Windows7 に 32 ビット版 Virtual PC をインストールしようとすると、インストール中にエラーとなり、インストールは完了しません。今回はインストールまでは完了しているのでこの現象とは異なります)。

ともあれ、Virtual PC が動かないのであれば、既存の Virtual PC で動作実績のある仮想ディスクファイルが存在していても PC-DOS や OS/2 を動かすことはできません。結局の所 Windows 10 環境へ移行したタイミングで OS/2 が動作する仮想環境を失ってしまうことになりました(PC-DOS は動かそうと思えば KVM 内で直接動かすことは可能でしたが、OS/2 は KVM では動きません)。特殊な環境ということもあったのか、この現象をググって調べても解決することはありませんでした。そのため OS/2 の動作環境を残すという目的のためだけに Windows7 の実機を残しておく必要に迫られ、結局「IBM Aptiva を残しておいた頃と同じ、元に戻ってしまう」ことになってしまったのでした。

ここまでが約1年前の話です。その後、この問題が未解決のままだったことをすっかり忘れてしまい、そのまま約1年が経過して、年末の PC 環境整理中に再びこの問題を思い出すことになったのでした。


【KVM 環境下の Windows7 内で Virtual PC を動かすために必要な設定】
改めてエラーメッセージ(「このコンピュータの物理プロセッサとは互換性がありません」)を、KVM というキーワードと合わせてググってみても同様の現象を見つけることが出来なかったので、もう解決策があるという前提で試行錯誤で行くしかありません。

で、仮想マシンの KVM 側の設定を眺めているうちに、このような画面にたどり着きました:
2020122600


KVM 側から見た、仮想マシンの Processer 設定画面です(普段はこのような画面を見る必要すらないので、こんな設定項目があることすら気づいていませんでした)。物理 CPU の割当数を変更したりする画面なのですが、その中に Configuration という項目があり、モデル欄が空になっています。。

このモデル欄は "486" とか "Pentium" といった CPU モデルを選択可能な項目になっているのですが、そのモデルが選択されていないため空になっている、という設定内容でした。念の為書いておきますが、他の Windows や Linux 仮想マシンでも、このモデル欄は空の設定になっていて、それでも問題なく動いています。実際この Windows 7 でも Virtual PC を導入しようとするまでは、この設定で問題にはなっていませんでした。

試しにここで "Copy host CPU configuration" ボタンを押して、ホストマシンの CPU 情報を参照して同じ設定にしてみました(モデル欄には "Opteon_G3" という値が自動入力されました。この値でなくても、ホストで使われている CPU の値が指定されていれば大丈夫だと思います)。この状態で「適用」しました:
2020122602


そして改めて仮想マシン(Windows 7)を起動し、Virtual PC を実行すると・・・ なんと!問題なく実行され、初期画面(新しいバーチャルマシンウィザードの開始画面)が表示されました:
2020122603


そのまま作業を進めて、別の Windows7 機で動いていた PC-DOS の仮想ディスクをコピー&指定して作成した PC-DOS 仮想マシンを動かすことができるようになりました!
2020122604


OS/2 環境も同様に KVM 環境下の Windows7 内 Virtual PC で動作させることができるようになりました:
2020122605


2020122607


いやあ、ここまで長かった! とりあえず KVM 内の Windows 7 では Virtual PC を動かすこと自体ができないのではないかと半ば諦めていたのですが、なんとか解決することができました。 めでたし、めでたし。。


ちなみに、元々のエラーメッセージでは「少なくとも Pentium II」が必要と書かれていました:
2020122601


じゃあ、このプロセッサー情報を(ホストと同じではなく)"Pentium II" と指定して適用すればいいのではないか? と最初は考えていました。が、そのように設定すると Pentium II と同様のウェイトがかかってしまうようでした。その結果、Windows 7 の起動そのものにものすごく長い時間がかかるようになりました(下画面は通常環境だと一瞬だけ表示されるもので、ユーザーが目の当たりにすることはほぼないのですが、プログレスバーがゆっくり進む様子が見て取れました)。そしてその結果なのか、何度も起動と途中終了&強制リセットを繰り返す無限ループに入ってしまい、起動することはありませんでした:
2020122608

↑Windows 7 時代では貴重な起動画面のスクリーンショット

そろそろ、その時はやって来たかな?
時は来た!


これまでメインのプログラミング開発環境を Windows10 の WSL(Windows Subsystem for Linux)Ubuntu 18.04 にしていました。WSL2 のことはもちろん知っていましたが、メイン機のスペックが特別高いわけでもなく(メモリ 8GB)、WSL で困らないであろう範囲のプログラミングをメインにしていました(例えばコンテナ環境が必要になった場合は別環境に用意して、そこにアクセスする、など)。

一方で WSL2 をサポートする開発周辺環境も整ってきました。Docker Desktop for Windows もリリースされ、もう mac と比較しても「アプリ開発環境は Windows 機 + WSL2 でいいんじゃないか?」と思える状況になってきました。スペック面での不安がないわけじゃないけど、環境的な意味では「時は来た」かな、と。

というわけで、自分の WSL 環境を WSL2 環境へ移行することにしました。以下その手順を備忘録として残しておきます。


【Hyper-V を有効化】
まず Windows の Hyper-V を有効化する必要があります。既に Hyper-V が有効になっている環境であればこの手順は不要ですが、今回はここも含めて紹介します。

その手順で利用するため Windows で PowerShell を起動します。この際に管理者権限で起動しておくようにします(バージョン確認だけなら管理者権限は不要ですが、WSL を WSL2 に変更する際に管理者権限が必要になります)。

そして以下のコマンドを実行します:
> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

そしてこのコマンドを実行後に再起動をかけると Hyper-V が有効化されます。ここから以下の作業は再起動後に行ってください。


(↓2020/11/22 追記)
【Windows ハイパーバイザープラットフォームの有効化】
VirtualBox など、他のハイパーバイザー環境との共存のための機能を有効にします。

Windowsの機能の有効化または無効化から Windows ハイパーバイザープラットフォームを選択して、チェックを入れて OK をクリックします:
2020112201
(↑2020/11/22 追記)


【WSL のバージョンを確認】
ここから下の PowerShell での操作については(管理者権限の)コマンドプロンプトでも構いません。

Hyper-V を有効にして再起動後、まず現在利用中の WSL のバージョン(1のはず)を確認しておきます。PowerShell で以下のコマンドを実行します:
> wsl --list --verbose

すると以下のような結果になり、WSL(1) を使っていることが確認できます:
2020112101


【WSL の Linux カーネルを更新】
この WSL を WSL2 に変更するのですが、その前に WSL の Linux カーネルを最新版に更新しておきます。

まず以下へアクセスします:
https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-kernel


「最新の WSL2 Linux カーネル更新プログラムパッケージをダウンロード」と書かれたリンクから更新パッケージをダウンロードします:
2020112102


ダウンロード後に実行して、WSL の Linux カーネルを更新します:
2020112103


【WSL を WSL2 に変更】
ここまでの準備ができていれば WSL を WSL2 に変更する準備が整いました。管理者権限の PowerShell で以下を実行して、まずは WSL のデフォルトバージョンを 2 に変更します(一瞬で終わります):
> wsl --set-default-version 2

続けて以下のコマンドも実行し、現在 WSL で動作中の Ubuntu 18.04 を WSL2 に変更します(少し時間がかかります):
> wsl --set-version Ubuntu-18.04 2

2020112101


これで WSL2 になった、はず。。


【WSL のバージョンを再確認】
最後に WSL のバージョンが2になっていることを確認します。再度先程と同じコマンドを実行し、バージョンが更新されていることを確認します:
> wsl --list --verbose

2020112102


WSL1 から WSL2 への環境移行に成功しました。

普段、あまり Windows サーバーを使うことがない中でクラウド上の Windows サーバーにリモートデスクトップ接続をして作業する、という機会がありました。そこで遭遇したトラブルと、その解決方法の自分向け備忘録です。


まずは発生したトラブルの状況を説明します。某クラウド上に Windows サーバーインスタンスを作成・用意しました。ログイン時のクレデンシャル(ユーザー名&パスワード)も分かっていて、サーバー・ネットワークへの VPN も接続したのでプライベート IP アドレス宛で接続することができるはず、という状況です:
2020091501


いざリモートデスクトップ接続を試みます。コンピューター欄に IP アドレス、そしてユーザー名にはログイン用のクレデンシャルで確認したユーザー名(図では Administrator)を指定して「接続」します:
2020091502


するとログインパスワードを聞かれます、ここまでは想定通り。同様にしてクレデンシャルで確認ずみのログインパスワードを入力して「OK」をクリック。これでリモートデスクトップ接続できるはず・・・:
2020091503


・・・だったのですが、エラーが発生してログインに失敗してしまいました。入力ミスはしていないし、ネットワーク的に繋がっていない相手だとしたらパスワードを聞かれることもないし、、、原因はなんだろう?? と、よく見るとユーザー名が入力した "Administrator" ではなく "Administrator@xxx.xxx" となっていました。なお "@xxx.xxx" 部分は会社のドメイン名です。何度か同じ手順を実行したのですが、常にこのドメイン名部分が自動的に(というか勝手に)付加されてしまい、正しいログインユーザー名ではなくなっていました。ログインエラーの原因はおそらくこれでしょう:
2020091504


作業に使った Windows PC は会社貸与のもので、詳しくはわかりませんが会社の運用ポリシーに従って集中管理されているものです。おそらくですがその関係でリモートデスクトップ接続時のログインユーザー名に "@xxx.xxx" というドメイン名までが(自動的に)付与されてしまっているのだと思います。この辺りあまり詳しくないのですが、そう考えるとこの挙動自体は納得できるものではあります。

ただログインユーザー名が勝手に変更されてしまっては、いつまでたってもクラウドの Windows サーバーにログインすることができません。会社側の運用ポリシーに原因があるのだとすれば、その運用ポリシーを変更することでも解決できるかもしれませんが、残念ながら(多くのケースがそうであると想像しますが)自分は運用ポリシーを変更できるような立場ではありません。直接の原因の究明も去る事ながら、この状況を Windows ユーザー側の操作だけで解決する方法はないか? というのが今回のブログテーマでした。


で、その応急処置的な解決方法がわかりました。先程のエラー画面内の「その他」と書かれた箇所をクリックします:
2020091505


するとログインユーザーを選択する箇所が表示されるので、まずはここで「別のアカウントを使用する」を選択します:
2020091506


改めてログインユーザー名とパスワードを入力する画面に遷移します。ここでログインユーザー名の頭に .\ を付けたものを指定します(パスワードは本来のものをそのまま指定します)。そして「OK」を押します:
2020091507


環境によってはセキュリティ証明書に関する警告ダイアログが出ることがあるかもしれませんが、その場合は「はい」を選択します:
2020091508


すると無事にリモート先の Windows デスクトップが表示されました!:
2020091509


運用ポリシーによって会社ドメインが強制されてしまうようなケースでも、ログイン名の頭に .\ を付けることでログインユーザー名のドメインを強制指定して上書きすることでなんとかエラーが回避できるようでした。


Node.js で XML を扱うのは難しいので、いったん JSON に変換してから扱うことが多いと思っています。そんな場合に自分はよく xml2json というライブラリを使っていました。

xml2json はその名前の通り、XML を JSON に変換してくれるパーサーを実装したライブラリです。使い方は例えば以下のような感じで、XML 文字列をそのまま引数にして実行すると、結果が JSON 文字列となって戻してくれます(JSON の文字列ではなく JSON オブジェクトとして扱う場合は更に JSON.parse() を実行します)。挙動も速く、便利に使っていました:
  :
var parser = require( 'xml2json' );
  :

  :
var xmlStr = fs.readFileSync( xml_filename, 'utf-8' );   //. ファイル名を指定して XML 文字列を取得
var jsonStr = parser.toJson( xmlStr );                   //. XML 文字列を JSON 文字列に変換
var jsonObj = JSON.parse( jsonStr );                     //. JSON 文字列を JSON オブジェクトに変換
  :

ところが上述のような処理を記述した Node.js のソースコードを Windows 環境下で実行しようとした時に問題が発生しました。実行前のライブラリインストール(npm install)の段階でエラーが発生してしまうのでした。詳細なエラーメッセージ等は後述のリンク先を参照していただきたいのですが、node-expat という xml2json の依存ライブラリを node-gyp でビルドする際に何やらエラーが発生していました。

で、この現象を調べた所、どうやら Windows 環境下では xml2json ライブラリ自体がビルドできないという根本的な問題を抱えているようでした:
npm install xml2json error


※厳密には「ビルドできない」わけではないけど、別途 Python や Visual Studio C++ 2012 などの他にインストールする必要があるツールが多く存在しているようです。


↑リンク先でも回避策として「別の XML -> JSON 変換ライブラリを使う」ことが提案されています。というわけで Windows でも使える同機能のライブラリを探したところ、単純な変換であれば fast-xml-parser が使えそうでした。

fast-xml-parser を使う場合は、上述の内容は以下のようなコードになります:
  :
var parser = require( 'fast-xml-parser' );
  :

  :
var xmlStr = fs.readFileSync( xml_filename, 'utf-8' );   //. ファイル名を指定して XML 文字列を取得
var jsonObj = parser.parse( xmlStr );                    //. XML 文字列を JSON オブジェクトに変換
  :

現実問題として自分個人の開発環境として Windows がベースとなることは今のところ考えにくいのですが、(WSL とかではなく)Windows 環境下で開発しないといけない人との共同作業が発生するようなケースではこういったことも意識しないといけないこともでてくると感じています。


Windows 10 で kubernates の開発環境を構築する際の方法の1つとして、以下のケースで構築する場合のメモです:
・Kubernetes 本体は minikube を使って Windows 10 に導入
・kubectl は WSL から利用


Kubernetes 本体はローカルで動く minikube を使ってシングルノード環境を構築します。この部分は正しく導入できていさえすれば Windows だろうが、Linux だろうが、Mac だろうが、システム環境の違いを意識することはあまりないと思っています。 ただ実際に利用する段になって kubectl コマンドを実行する環境としては Windows よりもより実践に近い Linux を使いたくなります。というわけで、Windows 10 の WSL (今回は Ubuntu を想定)から利用できるようにしました。

なお、この環境構築をする場合のマシンスペックとして、メモリ 8GB だと構築して minikube start した時点でほぼメモリを使い尽くしてしまいます。動作確認するだけならいいのですが、本格的に開発して動作確認してテストして・・・という段階まで考えるとやはり 16GB くらいはほしいところです。


【前提条件】
- Windows 10
- WSL(Ubuntu 18.0.4) 導入済み


【VirtualBox のインストール】
Windows 10 で minikube を動かす場合、仮想環境のハイパーバイザーが必要です。今回は VirtualBoxを使います。VirtualBox 自体のインストールはごく普通に公式ページから Windows 版をダウンロードし、デフォルト設定のままインストールすればOKです。


【Windows 版 minikube のインストール】
minikube の Github ページから、Windows/amd64 版の minikube 単体をダウンロードします:
2019090801


ダウンロードしたファイルは minikube-windows-amd64.exe というファイル名になっていますが、これを minikube.exe とリネームしてファイルシステムの適当なフォルダに保存します(以下は C:\MyApps\minikube\ というフォルダを作成して、その中に C:\MyApps\minikube\minikube.exe という名前で保存しているものと仮定して以下を続けます)。

このフォルダに PATH を通します。Windows + S キーを押して検索ボックスに「システムの詳細設定」と入力すると「システムの詳細設定の表示」が見つかるので、これを選択します:
2019090802


システムのプロパティウィンドウが表示されたら、「詳細設定」タブを選択し、「環境変数」ボタンをクリック:
2019090803


ユーザー環境変数の Path を選択してから「編集」ボタンをクリック:
2019090804


そして「新規」に minikube.exe が保存されたフォルダ名を追加して、最後に OK ボタンをクリック。これで minikube.exe に PATH が通りました:
2019090805


念の為、動作確認してみます。コマンドプロンプトを起動して、 "minikube version" と入力して実行します。minikube のバージョン番号が表示されれば、ここまでの手順は OK です:
2019090801


【minikube の起動】
コマンドプロンプトから "minikube start" と入力して、minikube を起動します。自動的に必要な VM イメージを見つけて(初回はダウンロードして)自動構築します。通常は minikube が kubectl を見つけてくれるのですが、この方法だと(Windows 版 kubectl を使わない&インストールしていないので)見つからない、という警告が表示されますが、今回は WSL 側に kubectl を用意するので無視します:
2019090802


【WSL に kubectl をインストール】
WSL を起動し、以下のコマンドを入力して kubectl を(/usr/local/bin/ 以下に)導入します:
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl

$ chmod 755 kubectl

$ sudo mv kubectl /usr/local/bin

最後に "kubectl version" を実行して動作確認します(初回は Client Version が表示されれば OK です):
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.3", GitCommit:"2d3c76f9091b6bec110a5e63777c332469e0cba2", GitTreeState:"clean", BuildDate:"2019-08-19T11:13:54Z", GoVersion:"go1.12.9", Compiler:"gc", Platform:"linux/amd64"}

【minikube のエンドポイント情報の取得】
コマンドプロンプトに戻って、"minikube status" を実行し、minikube のエンドポイント情報を確認します。以下の例では 192.168.99.100 というアドレスが表示されていますが、これにポート番号 8443 を加えたもの(192.168.99.100:8443)がエンドポイントとなり、以下で利用することになります:
2019090803


【kubectl の設定】
上記で取得したエンドポイント情報を使って kubectl の設定を行います。WSL から以下のコマンドを順次実行します。なお以下で <コマンドプロンプト実行時のユーザー名> と表示されている部分にはコマンドプロンプト実行時のユーザー名がフォルダ名の一部になっているのでそれをそのまま指定します(上記の画像例の場合であれば、ここには KEIKIMURA が入ります)、また 192.168.99.100:8443 部分は上記で取得したエンドポイント情報です:
$ kubectl config set-credentials minikube --client-certificate=/mnt/c/Users/<コマンドプロンプト実行時のユーザー名>/.minikube/client.crt --client-key=/mnt/c/Users/<コマンドプロンプト実行時のユーザー名>/.minikube/client.key

$ kubectl config set-cluster minikube --server=https://192.168.99.100:8443 --certificate-authority=/mnt/c/Users/<コマンドプロンプト実行時のユーザー名>/.minikube/ca.crt

$ kubectl config set-context minikube --user=minikube --cluster=minikube

$ kubectl config use-context minikube

最後に WSL で "kubectl cluster-info" コマンドを実行して動作を確認し、エンドポイントで正しくクラスタ状態が取得できれば kubectl の設定完了です。シングルノードの kubernetes (kubectl) がローカルの WSL から使えるようになりました:
$ kubectl cluster-info

Kubernetes master is running at https://192.168.99.100:8443
KubeDNS is running at https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.



(参考)
https://dokupe.hatenablog.com/entry/20180408/1523116886

このページのトップヘ