本記事は、 docker Advent Calendar 2021 2日目 の記事だ。
昨日は、 @subretu氏 の DockerfileにおけるCMDとRUNの挙動 だった。
docker のコンテナやボリュームの中身を見る際に、 ホスト PC から SMB ファイル共有で参照できると都合が良い。
と言うことで以前、以下のような記事を作成したが、 Docker Desktop では利用できない問題があった。
無認証 SMB を samba で秒で立ち上げる Dockerfile (& docker-compose) | Aqua Ware つぶやきブログ
今回は、それを解消する手段について紹介したい。
先に断っておくが、私自身でいくつかの PC で試したところ、上手くいく PC とダメな PC がハッキリと分かれてしまい、現時点ではどのような条件だとダメなのかハッキリわかっていない。
Windows の SMB over TCP/IP アクセス機能は、接続先が 445 番ポートでないと利用できない制限がある。
ところが、 Docker Desktop で 445 番ポートをリッスンしようとしても、 ホスト OS 側の LanmanServer
サービス ("Server" と言う表示名のもの) が常に localhost の 445 番ポートを占有しているため、ポートをリッスンできずに失敗してしまう。
さらに、この LanmanServer
サービスは、 Docker Desktop サービスがこれに依存しているため、 このサービスを止めることもできない。
このため、なんとか localhost の 445 番ポート以外をリッスンさせてる方法を考えなくてはならない。
結論から言うと、 "ループバックアダプター" と "portproxy" という Windows 組み込みの機能を利用する。
ループバックアダプターとは、一言で言うと 仮想的なネットワークアダプタ (NIC) だ。
この 仮想NIC に 適当なIPアドレス を割り当てて、 その 445 番ポートにアクセスすると、 localhost の 445 番以外 のアドレスに portproxy させる ことができる。
Docker Desktop 側で その 445 番以外 のアドレスをリッスンしておけば、問題を回避できるはずだ。
hdwwiz.exe
を実行するncpa.cpl
を実行) を開き、 今作成した 仮想NIC のプロパティを開く。192.168.254.2
) を設定するこれで準備完了だ。
冒頭に紹介した、以前の記事の Dockerfile を使って、 SMB を立ちあげてみる。
この Dockerfile のあるディレクトリをカレントディレクトリにして、以下を実行する。
docker build -t simple-samba .
docker run --rm -p 38445:445 simple-samba
実用的には、 docker run の -v
オプションなどで、適当なボリュームをマウントする感じになるだろう。
そして、コンテナを起動した状態で ループバックアダプター の 仮想NIC に設定したアドレス (上記の例だと \\192.168.254.2\
) に Windows エクスプローラー からアクセスできれば成功だ。
うまく動かない場合、 portproxy を提供する iphlpsvc
(IP Helper) サービス が、 445 ポートをリッスンできているか調べてみよう。
netstat
コマンドで、 192.168.254.2:445 をリッスンしているプロセスID を調べる。
そして、その プロセスID が何のサービスなのか、 Windows PowerShell v5.11 Get-WmiObject Win32_Service から確認してみよう。
うまく動作していれば、以下のように iphlpsvc
サービス であることが確認できるだろう。
PS > netstat -ano | findstr 445
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:8445 0.0.0.0:0 LISTENING 13944
TCP 192.168.254.2:445 0.0.0.0:0 LISTENING 4016
TCP 192.168.254.2:60665 192.168.254.2:445 ESTABLISHED 4
PS > Get-WmiObject Win32_Service | ? ProcessId -EQ 4016;
ExitCode : 0
Name : iphlpsvc
ProcessId : 4016
StartMode : Auto
State : Running
Status : OK
もし、 192.168.254.2:445 をリッスンしているプロセスID が 4 だった場合、 OS の LanmanServer
サービスに関係するカーネルプロセスがこのポートをふさいでしまっているため、 portproxy が正しく動作していないと言うことになる。
PS > netstat -ano | findstr 445
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:8445 0.0.0.0:0 LISTENING 13944
TCP 192.168.254.2:445 192.168.254.2:60665 ESTABLISHED 4
TCP 192.168.254.2:60665 192.168.254.2:445 ESTABLISHED 4
これは、おそらく portproxy を機能させる iphlpsvc
サービスが機能する前に、 LanmanServer
サービスが 445 ポートを塞いでしまっているからだと考えられる。
確実ではないと思われるものの、 iphlpsvc
サービスが先に機能するかもしれない対策を、いくつか紹介する。
いずれも、設定後 PC の再起動が望ましい。
services.msc
を実行して、 「サービス」 の管理コンソールを立ちあげ、 "IP Helper" (iphlpsvc
) のスタートアップが「自動」 になっていることを確認する。
Set-Service iphlpsvc -StartupType Automatic;
netsh interface ipv6 install
LanmanServer
サービスの起動を遅延させる:
LanmanServer
サービスの起動を「手動」にして起動を遅延させる。Set-Service LanmanServer -StartupType Manual;
どうしても 仮想NIC の 445 ポートが PID 4 に奪われる場合、 iphlpsvc
サービスと LanmanServer
サービスの起動順とかを見てみると良いかもしれないが…
確認したところで何か具体的な対策があるわけでは無いが…
$procs = Get-WmiObject Win32_Service -Filter "Name='iphlpsvc' or Name='LanmanServer'";
Get-WmiObject win32_process -Filter (($procs.ProcessId | %{ "ProcessId='$_'" }) -join ' or ') | select Name,CreationDate,ProcessId,@{Name='Service'; Exp={$procs | ? ProcessId -eq $_.ProcessId | select -exp Name}};
後半、動作しない場合の対策についてつらつらと書いてしまったが、ちゃんと動きさえすればなかなか便利なはずだ。
明日、 docker Advent Calendar 2021 の 3日目 は… 今のところ空いているようだ。
どなたか書いてみてはいかがだろう?
2021年現在、 PowerShell v7 系列だと Get-WmiObject
コマンドが動かないため。 ↩︎
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント