Table of Contents
Windows Server 2016のTechnical Preview 5(TP5)が公開されていたので、 TP4でバグに阻まれて挫折した、Windows ContainersでPcap4Jを使ってパケットキャプチャする試みにリトライした話。
OSセットアップ
TP4のときと同じ環境。
以降はWindows Server Containersのクイックスタートガイドに沿ってセットアップを進める。 TP4からは大分変わっていて、単一のPowershellスクリプトを実行する形式から、Powershellのコマンドレットを逐次手動実行する形式になっている。 面倒だけど何やってるかわかりやすくて好き。
コンテナ機能のインストール
管理者権限のパワーシェルウィンドウを開く
コマンドプロンプトから以下のコマンドを実行。
powershell start-process powershell -Verb runas
コンテナ機能のインストール
開いた青いパワーシェルウィンドウで以下のコマンドを実行するとコンテナ機能がインストールされる。
Install-WindowsFeature containers
数分で終わる。
インストールされたのはHyper-V ContainersじゃなくてWindows Server Containersの方。 クイックスタートガイドをみると、前者がWindows 10向け、後者がWindows Server向けというように住み分けされているっぽい。TP4では両方ともWindows Serverで使えたんだけど。
再起動
変更を有効にするために再起動が必要。
Restart-Computer -Force
Dockerインストール
Dockerは、コンテナイメージの管理やコンテナの起動などもろもろの機能を提供するDockerデーモンと、その機能を利用するためのCLIを提供するDockerクライアントからなる。この節ではそれら両方をインストールする。
Dockerインストールフォルダ作成
管理者権限のパワーシェルウィンドウを開いて、以下のコマンドでDockerインストールフォルダを作成。
New-Item -Type Directory -Path 'C:\Program Files\docker\'
Dockerデーモンインストール
まずはデーモンの方をインストール。
Invoke-WebRequest https://aka.ms/tp5/b/dockerd -OutFile $env:ProgramFiles\docker\dockerd.exe -UseBasicParsing
数分。
Dockerクライアントインストール
次にクライアント。
Invoke-WebRequest https://aka.ms/tp5/b/docker -OutFile $env:ProgramFiles\docker\docker.exe -UseBasicParsing
数十秒。
パスの設定
さっき作ったDockerインストールフォルダにパスを通す。
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files\Docker", [EnvironmentVariableTarget]::Machine)
Dockerデーモンをサービスに登録
パスの設定を反映するためにいったんパワーシェルウィンドウとコマンドプロンプトを閉じて、 また管理者権限でパワーシェルウィンドウ開いて、以下のコマンドでDockerデーモンをサービスに登録する。
dockerd --register-service
Dockerデーモン起動
Dockerデーモンは以下のコマンドで起動できる。
Start-Service docker
数秒で立ち上がる。 デフォルトではOS再起動時にはDockerデーモンは自動起動しないので、そのつどこのコマンドを実行する必要がある。
これでDockerインストール完了。 この時点ではコンテナイメージは何もない。
C:\Users\Administrator>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
因みにインストールされたDockerのバージョンは1.12開発版。現時点での最新版だ。
C:\Users\Administrator>docker -v
Docker version 1.12.0-dev, build 8e92415
コンテナイメージのインストール
次に、コンテナイメージをインストールする。
コンテナイメージのパッケージプロバイダをインストール
いまいち何なのかはよくわからないが、 コンテナイメージのパッケージプロバイダというのをインストールする。
Install-PackageProvider ContainerImage -Force
数十秒。
Windows Server Coreのイメージをインストール
Install-ContainerImage -Name WindowsServerCore
9GB以上もあるファイルをダウンロードして処理するのでかなり時間がかかる。 50分くらいかかった。
Dockerデーモン再起動
Restart-Service docker
無事Windows Server Coreイメージがインストールされた。
PS C:\Users\Administrator> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
windowsservercore 10.0.14300.1000 5bc36a335344 8 weeks ago 9.354 GB
Pcap4Jコンテナイメージのビルド
以下をC:\Users\Administrator\Desktop\pcap4j\Dockerfile
に書いて、cd C:\Users\Administrator\Desktop\pcap4j
して、docker build -t pcap4j .
を実行。
(Notepad使ったので、拡張子を表示する設定にしてDockerfile
の.txt
を消さないといけない罠があった。)
#
# Dockerfile for Pcap4J on Windows
#
FROM windowsservercore:10.0.14300.1000
MAINTAINER Kaito Yamada <[email protected]>
# Install Chocolatey.
RUN mkdir C:\pcap4j
WORKDIR c:\\pcap4j
ADD https://chocolatey.org/install.ps1 install.ps1
RUN powershell .\install.ps1
# Install dependencies.
RUN choco install -y nmap jdk7 && \
choco install -y maven -version 3.2.5
# Build Pcap4J.
RUN powershell -Command Invoke-WebRequest https://github.com/kaitoy/pcap4j/archive/v1.zip -OutFile pcap4j.zip && \
powershell -Command Expand-Archive -Path pcap4j.zip -DestinationPath .
WORKDIR pcap4j-1
RUN powershell -Command "mvn -P distribution-assembly install 2>&1 | Add-Content -Path build.log -PassThru"
# Collect libraries.
RUN mkdir bin && \
cd pcap4j-packetfactory-static && \
mvn -DoutputDirectory=..\bin -Dmdep.stripVersion=true -DincludeScope=compile dependency:copy-dependencies && \
mvn -DoutputDirectory=..\bin -Dmdep.stripVersion=true -DincludeGroupIds=ch.qos.logback dependency:copy-dependencies && \
cd ../pcap4j-distribution && \
mvn -DoutputDirectory=..\bin -Dmdep.stripVersion=true -DincludeArtifactIds=pcap4j-packetfactory-static,pcap4j-sample dependency:copy-dependencies
# Generate sample script. (C:\pcap4j\pcap4j-1\bin\capture.bat)
RUN echo @echo off > bin\capture.bat && \
echo "%JAVA_HOME%\bin\java" -cp C:\pcap4j\pcap4j-1\bin\pcap4j-core.jar;C:\pcap4j\pcap4j-1\bin\pcap4j-packetfactory-static.jar;C:\pcap4j\pcap4j-1\bin\pcap4j-sample.jar;C:\pcap4j\pcap4j-1\bin\jna.jar;C:\pcap4j\pcap4j-1\bin\slf4j-api.jar;C:\pcap4j\pcap4j-1\bin\logback-classic.jar;C:\pcap4j\pcap4j-1\bin\logback-core.jar org.pcap4j.sample.GetNextPacketEx >> bin\capture.bat
Dockerfileに書いた処理内容はTP4のときとだいたい同じ。 以下、Dockerfile書いているときに気付いたこと。
TP4からのアップデート
WORKDIR や ENV や COPY でパスの区切りは \ 一つだと消えちゃうので \ か / を使わないといけない。
引用元: TP4のときのエントリ
このページの各コマンドのWindows Considerationsに、WORKDIR
のパスの区切りのバックスラッシュはエスケープしないといけないとか、ADD
のパスの区切りはスラッシュじゃないといけないとか書いてある。
TP4のときはなかったような。
WORKDIR や COPY のコンテナ内のパスに絶対パスを指定したい場合、C:\hoge、C:/hoge、C:\hoge、いずれもダメ。 以下の様なエラーが出る。
引用元: TP4のときのエントリ
これは直った。WORKDIR c:\\pcap4j
で行ける。
install.ps1の中でChocolateyのインストーラをHTTPSで取ってこようとしてエラー
引用元: TP4のときのエントリ
普通にchoco install
できたので、HTTPSが使えない制限は消えた模様。
ビルドしてみると、各ステップの実行(多分レイヤの作成)がすごく遅い。
引用元: TP4のときのエントリ
各ステップの実行は相変わらず重い。特にファイル変更が多いときはすごく重い。
コンテナの起動は非常に遅い。30秒以上かかる。
引用元: TP4のときのエントリ
コンテナ起動は早くなったけどまだ5秒くらいかかる。
WORKDIR や ENV で環境変数が展開されない。
引用元: TP4のときのエントリ
これはまだ直っていない。%tmp%
、%TMP%
、$TMP
、${TMP}
、どれもだめ。
コンテナ内で C:\ 直下に . で始まる名前のフォルダ作ると次のステップで消えてる。
引用元: TP4のときのエントリ
これは再現しなかった。以前のも勘違いだったのかもしれない。
なんにせよデフォルトの.m2フォルダのパスがC:\Users\ContainerAdministrator\.m2
になったので気にしなくてよくなった。
ビルドエラー: hcsshim::ImportLayer failed in Win32: The filename or extension is too long. (0xce)
choco install
の後で以下のエラーが出た。
re-exec error: exit status 1: output: time="2016-07-09T19:57:22-07:00" level=error msg="hcsshim::ImportLayer failed in Win32: The filename or extension is too long. (0xce) layerId=\\\\?\\C:\\ProgramData\\docker\\windowsfilter\\103de6bf1358c506510ad67990f09ec3e2f10f9e866e846df5a88c04f5edf7aa flavour=1 folder=C:\\Windows\\TEMP\\hcs719016711"
hcsshim::ImportLayer failed in Win32: The filename or extension is too long. (0xce) layerId=\\?\C:\ProgramData\docker\windowsfilter\103de6bf1358c506510ad67990f09ec3e2f10f9e866e846df5a88c04f5edf7aa flavour=1 folder=C:\Windows\TEMP\hcs719016711
調べたらDockerのGitHub Issuesに登録されていた。 ここのコメントを参考に以下のコマンドでコンテナホストのアップデートをしたら発生しなくなった。
Invoke-WebRequest https://aka.ms/tp5/Update-Container-Host -OutFile update-containerhost.ps1
.\update-containerhost.ps1
Restart-Computer -Force
git cloneできない
Pcap4Jのソースをダウンロードしたかったんだけど、なぜかgit clone
がHTTPSでもGITプロトコルでもエラーを返す。
原因を調べるのが面倒で結局zipでダウンロードするようにした。
未実装の機能
Dockerfileのリファレンスに載っていて、Windows向けのサンプルも書いてあるのに、escapeディレクティブとSHELLコマンド が使えなかった。
コンテナ起動
とりあえず上記DockerfileでPcap4Jコンテナイメージのビルドはできた。
以下のコマンドでそのイメージからコンテナを起動。
C:\Users\Administrator>docker run -it pcap4j cmd
コンテナ内でipconfig
するとvEthernet (Temp Nic Name)
という名のネットワークインターフェースがあることがわかる。
C:\pcap4j\pcap4j-1\bin>ipconfig
Windows IP Configuration
Ethernet adapter vEthernet (Temp Nic Name):
Connection-specific DNS Suffix . : localdomain
Link-local IPv6 Address . . . . . : fe80::59cf:1491:6f8e:30c8%18
IPv4 Address. . . . . . . . . . . : 172.23.71.6
Subnet Mask . . . . . . . . . . . : 255.240.0.0
Default Gateway . . . . . . . . . : 172.16.0.1
けどPcap4Jからは見えなかった。
C:\pcap4j\pcap4j-1\bin>capture.bat
org.pcap4j.sample.GetNextPacketEx.count: 5
org.pcap4j.sample.GetNextPacketEx.readTimeout: 10
org.pcap4j.sample.GetNextPacketEx.snaplen: 65536
18:49:00.582 [main] INFO org.pcap4j.core.Pcaps - No NIF was found.
java.io.IOException: No NIF to capture.
at org.pcap4j.sample.GetNextPacketEx.main(GetNextPacketEx.java:45)java:44)
コンテナにはContainerAdministrator
というユーザでログインしていて、これの権限が弱いせいなんじゃないかと。
コンテナ内にもAdministrator
というユーザがあるようだったので、こっちでコマンド実行するよう奮闘した。
コンテナ内でAdministratorでコマンド実行したい
USERコマンド
DockerfileのコマンドにUSERというのがあるので、USER Administrator
をDockerfileの末尾に追加してみたら以下のエラー。
The daemon on this platform does not support the command 'user'
–userオプション
docker runコマンドに–userというオプションがあるので以下のように試してみたところ、オプションは無視されてContainerAdministrator
でコンテナに入った。
docker run -it --user Administrator pcap4j cmd
runas
ちょっと発想の転換をして、ContainerAdministrator
でコンテナに入った後sudoみたいなことをすればいいかと思い、runasコマンドを試したけどだめだった。
よく分からないエラーがでるし、そもそもAdministrator
のパスワードがわからない。
C:\pcap4j\pcap4j-1\bin>runas /user:Administrator cmd
Enter the password for Administrator:
Attempting to start cmd as user "92EC7B3B09B4\Administrator" ...
RUNAS ERROR: Unable to run - cmd
1326: The user name or password is incorrect.
C:\pcap4j\pcap4j-1\bin>runas /user:"User Manager\Administrator" capture.bat
Enter the password for User Manager\Administrator:
RUNAS ERROR: Unable to acquire user password
Enter-PSSession
フォーラムに行ったらEnter-PSSessionを使う方法が書いてあった。
Enter-PSSessionはリモートシステムに接続するコマンドレットで、-ContainerName
オプションを使えばコンテナにも接続できる。
試したら、コンテナが見つからないというエラーが出た。
C:\Users\Administrator>powershell -command Enter-PSSession -ContainerName amazing_archimedes -RunAsAdministrator
Enter-PSSession : The input ContainerName amazing_archimedes does not exist, or the corresponding container is not running.
At line:1 char:1
+ Enter-PSSession -ContainerName amazing_archimedes -RunAsAdministrator
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Enter-PSSession], PSInvalidOperationException
+ FullyQualifiedErrorId : CreateRemoteRunspaceForContainerFailed,Microsoft.PowerShell.Commands.EnterPSSessionCommand
Invoke-Commandもコンテナをターゲットにできるので試してみたけど、同様のエラー。
どうもパワーシェルで扱うコンテナやコンテナイメージが、dockerコマンドが扱うものとは別になっているせいっぽい。 そんなことがTP4のときに見たドキュメントに書いてあったのを思い出した。(このドキュメントは消えてた。)
実際、docker ps
では見えているコンテナが、
C:\Users\Administrator>docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a711497f29d8 pcap4j "cmd" 13 minutes ago Up 12 minutes amazing_archimedes
コマンドレットからだと見えない。
C:\Users\Administrator>powershell -command Get-Container
WARNING: Based on customer feedback, we are updating the Containers PowerShell module to better align with Docker. As part of that some cmdlet and parameter names may change in future releases. To learn more about these changes as well as to join in the design process or provide usage feedback please refer to http://aka.ms/windowscontainers/powershell
そうなると、パワーシェルのコマンドレットにはdocker build
にあたるものがないのでもうどうしようもない。
そもそも、TP4の頃のコマンドレットは廃止になって、新しいコマンドレットを開発中らしい。やはりdockerコマンドとコマンドレットでコンテナの相互運用ができない仕様にユーザから相当つっこみがあったようだ。
Enter-PSSession
やInvoke-Command
の-ContainerName
オプションもその内修正されるであろう。
それまで待つか。