Neuron開発チームの木村です。
Neuronは、ほとんどの場合Windowsにインストールされるため、テスト環境をWindows上に構築しています。 このテスト環境構築を効率化するため、docker上でのWindows利用を模索しています。
前回に引き続き、 Windows上のdockerでイメージをビルドする際・コンテナを動かす際に慣れないことを紹介します。
前回検討した導入方法から、dockerは「Hyper-Vコンテナ + LCOW」の形態で利用しています。 (そのため、Docker for Windowsを利用する場合とは異なる状況であることに注意ください。)
Windowsのバージョンは、
Windows 10 Pro バージョン 1803 (Version 10.0.17134.165
)、
dockerのバージョンは、
Client: Version: master-dockerproject-2018-07-18 API version: 1.38 Go version: go1.10.3 Git commit: 48fbb12b Built: Wed Jul 18 23:51:23 2018 OS/Arch: windows/amd64 Experimental: false Server: Engine: Version: master-dockerproject-2018-07-18 API version: 1.38 (minimum version 1.24) Go version: go1.10.3 Git commit: 7f91801 Built: Thu Jul 19 00:00:43 2018 OS/Arch: windows/amd64 Experimental: true
LCOWのバージョンは、4.14.29-0aea33bc
です。
以下、OSがWindowsであるコンテナを「WindowsOSコンテナ」、OSがLinuxであるコンテナを「LinuxOSコンテナ」と呼びます。
目次
イメージビルド編
multi-stage buildsで、名前に半角スペースを含むファイルをCOPY
できない
multi-stage buildsでイメージビルドする際、名前に半角スペースを含むファイル(または、それを含むディレクトリ)を、WindowsのイメージにCOPY
しようとすると、ビルドが以下のエラーで止まります。
COPY failed: file does not exist
よくある半角スペースの問題と考え、"
で括るために
COPY --from=builder ["src/sample file", "."]
のJSON形式で指定しても、今度は別のエラーで止まります。
COPY failed: Forbidden path outside the build context
昔からあるファイル・ディレクトリ名の半角スペース問題に、久しぶりに遭遇しました。(厳密には別の問題のようですが…)
RUN
/CMD
で使われるシェルを意識する
RUN
/CMD
にシェル形式でコマンドを指定する際、コマンド実行に使われるシェルがcmd
(コマンドプロンプト)なのかpowershell
なのかを意識することが重要です。powershell
特有のコマンドを使う際は自然と意識すると思いますが、このふたつは環境変数の取得方法がだいぶ異なるため、java
のような自分でパスを通すコマンドを使う時に注意が必要です。
cmd |
powershell |
|
---|---|---|
環境変数VAR の取得方法 |
%VAR% |
$env:VAR |
存在しない環境変数NONE から取得される値 |
%NONE% という文字列 |
空文字列 |
シェル形式で書かれたRUN
/CMD
のコマンド実行に使われるシェルは、デフォルトがcmd
(cmd /S /C
)ですが、SHELL
で変更することができます。
使用するイメージのDockerfileを読むか、docker inspect
でイメージのCmd
プロパティからシェルを特定するとよいでしょう。たとえば、openjdk:8u171-jdk-nanoserver
はpowershell
をシェルに指定しています。
コンテナ実行編
[LinuxOSコンテナ] メモリ割り当てが変更できない
LinuxOSコンテナに対して、docker run
時に--memory
オプションから割当メモリを指定しても無視され、
以下のように、約1GBのメモリが割り当てられます。
PS C:\> docker run --rm --memory 2g alpine:3.8 cat /proc/meminfo MemTotal: 985568 kB MemFree: 870932 kB MemAvailable: 805808 kB ...
WindowsOSコンテナに対しては、以下のように、指定通り約2GBのメモリが割当たります。
PS C:\> docker run --rm --memory 2g microsoft/windowsservercore:1803 systeminfo ... Total Physical Memory: 2,559 MB Available Physical Memory: 2,194 MB ...
mobyのissueを読む感じでは、 LCOWを使用しているために起きる問題のようです…
[LinuxOSコンテナ] user指定が効かない
LinuxOSコンテナに対して、docker run
時に--user
オプションを指定しても無視され、
以下のように、rootユーザで実行されます。
PS C:\> docker run --rm --user guest alpine:3.8 whoami root
LCOW使用時の既知のバグのようです。
イメージビルド時のUSER
指定も効かないため、LinuxOSコンテナは常にroot
で動くことになります。
そして、この影響なのか、コンテナ内のディレクトリ・ファイルの所有者とグループが大体root:root
になってしまいます。
[LinuxOSコンテナ] mountされたvolumeに対してchmod
/chown
が効かない
「イメージビルド時のVOLUME
」や「docker run
時の--volume
オプション」でvolumeに指定されたディレクトリ以下に対して、chmod
/chown
が効きません。
以下の例のように、chmod
を行っても、終了コードが0であるにも関わらずパーミッションが変更されません(例ではjenkins/jenkins:2.134
イメージを使用)。
root@fcdd7ae24179:/var/jenkins_home# ls -la total 0 -r-xr-xr-x 1 root root 102 Jul 30 05:02 copy_reference_file.log drwxrwxrwx 1 root root 4096 Jul 30 05:02 init.groovy.d root@fcdd7ae24179:/var/jenkins_home# chmod 755 copy_reference_file.log root@fcdd7ae24179:/var/jenkins_home# echo $? 0 root@fcdd7ae24179:/var/jenkins_home# ls -la total 0 -r-xr-xr-x 1 root root 102 Jul 30 05:02 copy_reference_file.log drwxrwxrwx 1 root root 4096 Jul 30 05:02 init.groovy.d
既知の問題ではあるようですが、回避策は特にない状況です。
このことが起因する問題には色々当たりましたが、大きかったのはjenkinsでリポジトリをダウンロードする際にエラーが起きることでした。
volume指定を使わないことでエラーを回避しましたが、docker cp
でjenkins設定の永続化を行うことになってしまいました…
稼働中のコンテナに対してdocker cp
できない
稼働中のコンテナに対してdocker cp
を実行すると、以下のエラーが発生してコピーができません。
PS C:\Users\user\Documents> docker cp 7961ee45d606:/var . Error response from daemon: filesystem operations against a running Hyper-V container are not supported
なお、停止中のコンテナに対しては正常にコピーできます。
おわりに
Windows上のdockerにて、イメージビルドやコンテナ実行の際に慣れないことを紹介しました。 LinuxOSコンテナについて、「volume周りの問題」と「メモリが最大1GB」がかなり厄介な問題です。
上記の他にも以下のようなことがありました。
- コンテナ自体を作成できないイメージがある
- 例えば、
openjdk:8u171-jdk-nanoserver
- しかし、
openjdk:8u171-jdk-windowsservercore
はコンテナ実行可能
- 例えば、
- LinuxOSコンテナ用のDockerfileを、WindowsOS用に書き換えるには細かいところも気にしないとならない
- javaのclasspath区切りは、Windowsでは
:
ではなく;
、など
- javaのclasspath区切りは、Windowsでは
- dockerdを再起動すると、元々稼働していたコンテナがstartできなくなる
やはり、experimentalなLCOWを使ってLinuxOSコンテナを扱うのは、まだ早いのでしょうか。 WindowsOSコンテナのみに絞ればよいかもしれませんが、そうするとLCOWを使う理由もないですし…
docker上でのWindows利用について、LCOWは引き続き試してゆきますが、 現状では、Docker for Windowsが可能な範囲で模索してゆくほうがよさそうです。
ブレインズテクノロジーではエンジニアを募集中です
採用ページはこちら