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-serviceDockerデーモン起動
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 WindowsServerCore9GB以上もあるファイルをダウンロードして処理するのでかなり時間がかかる。 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 GBPcap4Jコンテナイメージのビルド
以下を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.batDockerfileに書いた処理内容は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 -Forcegit 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 cmdrunas
ちょっと発想の転換をして、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 passwordEnter-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.EnterPSSessionCommandInvoke-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オプションもその内修正されるであろう。
それまで待つか。