この記事の目的
Windows Server 2019環境で、とにかくてっとり早くdockerコンテナを使えるようにするための手順をお伝えします。
MSDNの公式ページにもチュートリアルがあり、こちらも併せて参照いただくと理解が深まるかと思います。1
https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/quick-start/quick-start-windows-server
Windows Server 2019のインストール~dockerが使えるまでの手順
インストール手順
-
Windows Server 2019をインストール (下記はすべてデスクトップエクスペリエンスで動作を確認)
-
管理者モードでPowerShell起動 (以降すべてのPowerShellコマンドは管理者モードで実行)
-
コンテナ機能の有効化
Install-WindowsFeature containers
-
サーバーの再起動
Restart-Computer -Force
-
Dockerのインストール
# パッケージ管理のプロバイダを追加 Install-Module -Name DockerMsftProvider -Repository PSGallery -Force # dockerをインストール Install-Package -Name docker -ProviderName DockerMsftProvider
-
サーバーの再起動
Restart-Computer -Force
-
Proxyの設定
setx HTTP_PROXY http://proxy.example.com:8888/ /M setx HTTPS_PROXY http://proxy.example.com:8888/ /M
動作確認
-
dockerのバージョン確認コマンドを実行
docker version
-
下記のように結果が返ってくればOK
Client: Docker Engine - Enterprise Version: 18.09.5 API version: 1.39 Go version: go1.10.8 Git commit: be4553c277 Built: 04/11/2019 06:44:52 OS/Arch: windows/amd64 Experimental: false Server: Docker Engine - Enterprise Engine: Version: 18.09.5 API version: 1.39 (minimum version 1.24) Go version: go1.10.8 Git commit: be4553c277 Built: 04/11/2019 06:43:04 OS/Arch: windows/amd64 Experimental: false
-
使ってみよう
docker container run hello-world:nanoserver
hello-world:nanoserverという名前のイメージをコンテナとして起動する命令です。
ただし、初回は当該の環境にhello-world:nanoserverという名前のイメージがまだ無いので、最初にDocker Hubからのダウンロードが行われます。
Unable to find image 'hello-world:nanoserver' locally
nanoserver: Pulling from library/hello-world
b22999bfb02f: Pull complete
c8353a1aacae: Pull complete
8c51178a6c10: Pull complete
Digest: sha256:347e0c5e55751d2ee2470f1a57463c26e81515583838286b67ae7d140d0480da
Status: Downloaded newer image for hello-world:nanoserver
```
上記の後、コンテナが起動し、コンソールに下記の文字列を返します。
```cmd
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(windows-amd64, nanoserver-1809)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run a Windows Server container with:
PS C:\> docker run -it mcr.microsoft.com/windows/servercore powershell
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```
ちょっと解説
-
コンテナのライフサイクル
上記のDockerイメージは、起動すると文字列を上記のようにコンソールに印字するプロセスが立ち上がり、このプロセスが終わるとコンテナそのものも停止します。Dockerでは、コンテナ化したときにコンテナ内で開始されるプロセスとライフサイクルを共にしています。
-
イメージの取得
上記では、イメージのダウンロードが暗黙的に実行されましたが、docker image pull
コマンドを実行すると、イメージのダウンロードのみを実行することも可能です。イメージは、Docker Hub上のものだけではなく、これらのイメージをベースにして自分で独自のイメージを作成することができます。この作業をBuildと呼びます。(作り方は後述)
-
イメージの名前
イメージの名前には命名規則があります。先ほどの例では、
hello-world:nanoserver
という名前でしたが、これはイメージ名:タグ名
という2つの要素で一意にイメージを特定しています。
タグの役割は、イメージのバージョンを明示したり、ベースとなるOSを区別する目的などで使われています。 -
LinuxコンテナとWindowsコンテナ
コンテナ技術は、OSの仮想化と表現されます。1つしかないOSを、まるで独立した複数のOSが存在しているかのように振舞わせることで分離された環境でコンテナのプロセスを立ち上げています。
このとき、コンテナ上のカーネルのプロセスはホスト側となるOSのカーネルを共有します。このため、Windows Serverをコンテナのホストとした場合、基本的にはWindows Serverのイメージしかコンテナとして実行することができません。加えて、Windows Server 20191は、OSのメジャー・マイナー・ビルドの3つのバージョンまでがホスト側と一致している必要があります(参照:コンテナのバージョンの互換性)
自分のイメージを作ってみよう
一般的なイメージの作成について
開発したアプリケーションおよび依存モジュールをまとめて一つのDockerイメージを作成することができます。
アプリケーションおよび依存モジュールを一つにパッキングできるため、アプリケーションはコンテナのホスト側の環境に依存せずに動作することができます。
イメージをビルドするためにはDockerfileというdockerに対するイメージ作成の指示書のようなものを作成します。
概ね次のような手順でDockerfileを記述していきます。
- 空のテキストファイルを作成しDockerfileという名前で保存。
- ベースとなるイメージを決定する。
補足)Windows Server 2019をコンテナホストにする場合、純粋にOSのみをベースにしたいときは下記が選択肢になります。- Windows Server 2019 Server Coreイメージ (mcr.microsoft.com/windows/servercore:ltsc2019)
- Windows Server 2019 Nano Serverイメージ (mcr.microsoft.com/windows/nanoserver:1809)
- ベースとなるイメージに、アプリケーションやその依存モジュールなどを配置。
- ソフトウェアのインストール、ファイルとディレクトリの作成、環境構成の作成など必要に応じて実施。
Dockerfileの作成
本チュートリアルでは、MSDNのドキュメント(前述)に倣って、IISで静的なページを返すイメージを作成します。
-
空のテキストファイルを作成しDockerfileという名前で保存。
-
同じフォルダにindex.htmlという名前のファイルを作成し、HellowWorldと記述して保存する。
-
Dockerfileに次のように記述。
FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019 ADD index.html c:/inetpub/wwwroot
Dockerfileのビルドとコンテナ化
Dockerfileができたらビルドを行いイメージを作成します。
-
Dockerfileと同じディレクトリに移動。
-
下記のコマンドを実行しビルド実行。
下記の例では、
tutorial:latest
という名前でイメージが生成される。docker build -t tutorial:latest .
-
ビルドが成功したイメージをコンテナとして実行する。
先の例と同じように、イメージ名として
tutorial
を指定して実行する。(コンテナの実行を指示する時は、どのディレクトリからでも可能)docker container run -d -p 8888:80 tutorial:latest
上記は、コンテナホスト側のポート8888番をコンテナ側のポート80にフォワードするように指定しています。
-
コンテナホストで、
docker container ls
を実行し、コンテナが実行されていることを確認してみる。
C:\Users\Administrator\Desktop\tutorial>docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d2527cb41c15 tutorial:latest "C:\ServiceMonitor.e…" 11 minutes ago Up 11 minutes 0.0.0.0:8888->80/tcp hopeful_yalow
```
このとき、上記のCONTAINER IDとNAMESは勝手に付与されます。(NAMESについては明示的に指定することも可能)
はじめに起動させた`hello-world:nanoserver`は、コンソールに文字を打刻してすぐに停止してしまいました。しかし、上記のコンテナは、ずっと起動したままになっています。
この理由は、コンテナ化したときに起動するプロセスが、停止しないようなプロセス(`ping /t localhost`のように)であるためです。
今回の例では、ServiceMoniter.exeというプロセスが生存し続けているために、コンテナが起動したままになっています。
-
docker exec
で動いているコンテナに入ってみる。docker exec -it %実際のCONTAINER ID値% cmd
コンテナでシェルが起動し、次のような画面が返ってくる。
Microsoft Windows [Version 10.0.17763.503] (c) 2018 Microsoft Corporation. All rights reserved. C:\>
色々、打ち込んでみる。試しにdirコマンドを実行すると、コンテナのシステムドライブ(C:)直下のファイル・ディレクトリが返ってくる。
C:\>dir Volume in drive C has no label. Volume Serial Number is 4084-DF79 Directory of C:\ 05/16/2019 06:20 AM <DIR> inetpub 09/15/2018 06:42 PM 5,510 License.txt 05/13/2019 01:25 PM <DIR> Program Files 05/13/2019 01:24 PM <DIR> Program Files (x86) 05/16/2019 06:21 AM 172,328 ServiceMonitor.exe 05/13/2019 01:26 PM <DIR> Users 05/16/2019 06:20 AM <DIR> Windows 2 File(s) 177,838 bytes 5 Dir(s) 21,092,855,808 bytes free
inetpub\wwwrootに移動し、index.htmlを見てみると、、あたりまえだがDockerfileで格納(ADD)したindex.htmlがちゃんと入っている。
C:\>cd inetpub\wwwroot C:\inetpub\wwwroot>dir Volume in drive C has no label. Volume Serial Number is 4084-DF79 Directory of C:\inetpub\wwwroot 06/06/2019 02:39 PM <DIR> . 06/06/2019 02:39 PM <DIR> .. 05/16/2019 06:20 AM 703 iisstart.htm 05/16/2019 06:20 AM 99,710 iisstart.png 06/06/2019 02:38 PM 11 index.html 3 File(s) 100,424 bytes 2 Dir(s) 21,092,855,808 bytes free C:\inetpub\wwwroot>type index.html Hello World C:\inetpub\wwwroot>
-
コンテナの状態を変更してみる。
docker exec
コマンドの続きで、下記のように実行。C:\inetpub\wwwroot>echo %COMPUTERNAME% D2527CB41C15 C:\inetpub\wwwroot>echo %COMPUTERNAME% > index.html
この状態で、もう一度ブラウザでlocalhost:8888にアクセスしてみると、次のようにコンピュータ名が表示されるようになります。
-
コンテナを止めてみる。
docker exec
コマンドを一旦終了するため、exitを入力します。C:\inetpub\wwwroot>exit C:\Users\Administrator\Desktop\tutorial>
ホスト側のシェルに戻ってきました。ここで
docker container stop %実際のCONTAINER ID値%
と入力すると、起動していたコンテナが停止します。(ブラウザでlocalhost:8888にアクセスし、ページが返ってこないことを確認します。)この後、
docker container start %実際のCONTAINER ID値%
と入力すると、停止したコンテナが再び起動します。(ブラウザでlocalhost:8888にアクセスし、再びページが表示されることを確認します。)この状態で、次のコマンドを実行してみます。
docker container run -d -p 8889:80 tutorial:latest
今度は、別のコンテナがイメージから新たに生成されます。ブラウザでlocalhost:8889にアクセスすると「Hello World」と表示されるはずです。先ほどindex.htmlをCOMPUTERNAMEで置き換えた変更は、当該のコンテナのみに反映されますが、イメージとしては「Hello World」のままなので、新たにコンテナを立ち上げるとこのようになります。
docker container run -d -p 8890:80 tutorial:latest docker container run -d -p 8891:80 tutorial:latest docker container run -d -p 8892:80 tutorial:latest docker container run -d -p 8893:80 tutorial:latest docker container run -d -p 8894:80 tutorial:latest ... docker container run -d -p 8899:80 tutorial:latest
調子に乗っていくつもコンテナを立ち上げることができます。上記のように実行すると10台のコンテナが立ち上がります。
それぞれのコンテナのリソース消費量は、
docker stats %実際のCONTAINER ID%
コマンドで確認できます。docker stat 32755b73a12c CONTAINER ID NAME CPU % PRIV WORKING SET NET I/O BLOCK I/O 32755b73a12c silly_mestorf 0.00% 58.06MiB 12.7kB / 5.09kB 17MB / 5.84MB
上記の通り、このコンテナの例では、1台あたり60MB程度のメモリーしか消費していないことがわかります。10台立ち上げても600MB程度で済みます。
また、環境にもよりますが、上記のコマンドを実行してコンテナが起動するのに掛かる時間は1秒~数秒程度です。
ESXiやHyper-Vで仮想マシンを立ち上げる際に必要となるリソースや起動時間と比較して、少ないメモリー量かつ高速に起動することを体感することができます。
ここまでできた方へ
まとまった規模のシステムになると、複数のコンテナ(DB/Web/Cache/SearchEngine...etc)を組み合わせて一つのシステムを作り上げたくなります。このようなときにもDocker-Composeというツールを使うと、複数のコンテナをまとめて立ち上げたり、落としたりすることができ、コンテナ間の名前解決もよろしくしてくれますので、Docker-Composeについて慣れていくと良いかと思います。
詳しい手順は下記が参考になります。
https://docs.docker.com/compose/install/#install-compose
かなりざっくりしていますが、ざあっと、下記のコマンドでDocker-Composeが使えるようになります。(Powershell)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-Windows-x86_64.exe" -UseBasicParsing -OutFile $Env:ProgramFiles\docker\docker-compose.exe
# docker Serviceの再起動
Restart-Service Docker