Windows HomeにDockerを入れてPythonで簡易ウェブサーバーを動かす

## はじめに
Dockerを勉強しようと思い、Windows10 HOME環境（←重要）でDocker InstallからDockerコンテナー内でPythonで簡易ウェブサーバーを動かすところまでやったのでまとめておく。
手順は抜け漏れがあるかもなので、何かうまくいかないところがあったらコメント貰えると嬉しいです。

<!-- toc -->

- [Windows OSにおけるDocker](#Windows-OSにおけるDocker)
- [Docker使うにあたりWindows10 ProとHomeで違うところ](#Docker使うにあたりWindows10-ProとHomeで違うところ)
- [Dockerコンテナー内で簡易ウェブサーバーを動かす手順](#Dockerコンテナー内で簡易ウェブサーバーを動かす手順)
  * [Dockerのインストール](#Dockerのインストール)
  * [Virtual Boxで動いているVMのなかを覗いてみる](#Virtual-Boxで動いているVMのなかを覗いてみる)
  * [フォルダ・ファイルの構成を用意](#フォルダ・ファイルの構成を用意)
  * [Dockerファイルを記述する](#Dockerファイルを記述する)
  * [ウェブページを公開するpythonスクリプトを作成](#ウェブページを公開するpythonスクリプトを作成)
  * [Dockerイメージのビルド](#Dockerイメージのビルド)
  * [ビルドしたDockerイメージを実行](#ビルドしたDockerイメージを実行)
  * [Dockerコンテナー内で動いているウェブサーバーにアクセスする](#Dockerコンテナー内で動いているウェブサーバーにアクセスする)
- [参考にしたサイト](#参考にしたサイト)

<!-- tocstop -->



## Windows OSにおけるDocker
　まず前提として、DockerはLINUX OS上で動く。そのため、Windows上でDockerを動かすにはLINUXの仮想マシンを立てて、その上にでDockerエンジンを動かすみたいにする。これはWindows 10 Proでも、Windows 10 Homeでも共通。
　図にすると以下。左がLinux、右がWindowsでDokcerを動かすとき。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391281/2332f58a-6960-4b7a-3982-886c92b5a17b.png)

(<https://www.researchgate.net/figure/A-comparison-of-the-architecture-of-virtual-machines-and-Docker-software_fig4_299771559>)」より引用



## Docker使うにあたりWindows10 ProとHomeで違うところ
　
　結論としては、Windows 10 Proは「Docker Desktop for Windows」を使い、WIndows 10 Homeでは「Docker Toolbox」を使うという点が違い。
　使い分ける理由は、「Docker Desktop for Windows」は上図のハイパーバイザーとしてHyper-Vを使うことが前提になっているが、Windows 10 HomeではHyper-Vは使えないため。
　そこで、Windows 10 Homeでは「Docker Toolbox」をインストールする。「Docker Toolbox」は、ハイパーバイザーとしてOracleの「Virtual Box」をつかう。
  　まとめると、下図のとおり。

| | Windows 10 Pro | Windows 10 Home |
|:-- | :-- | :-- |
|ハイパーバイザ| Hyper-V | Virtual Box（など） |
| Doker| Docker Desktop for Windows | Docker Toolbox |



## Dockerコンテナー内で簡易ウェブサーバーを動かす手順

　上記を踏まえて、Windows 10 Home環境で以下のようなページを表示をする簡易ウェブサーバーをDockerコンテナー内で動かす手順を記載する。（抜け漏れがあるかも）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391281/2dee9803-3ac9-170a-4f63-fa80a3c7f566.png)


### Dockerのインストール
 まずはDocker Toolboxをインストールする、が、手順については[windows 10 home で docker を導入するメモ - Qiita](https://qiita.com/idani/items/fb7681d79eeb48c05144)にすべて記載されているので、いきなり省略する。

### Virtual Boxで動いているVMのなかを覗いてみる
つぎに、Dockerコンテナーを動かすVMのなかがどうなっているかを確認する。
　※ 理解を助けるための手順で、必要な作業というわけではないので飛ばしてもよい。でもDockerほぼ初めてな人はやっておいたほうがいいかかも
 　コマンド```docker-machine ssh default```を実行してVMに入る

```shell:
C:\Users\hogehoge\workspace\pythondocker>docker-machine ssh default
   ( '>')
  /) TC (\   Core is distributed with ABSOLUTELY NO WARRANTY.
 (/-_--_-\)           www.tinycorelinux.net

docker@default:~$ 
```
これで、defaultという名前のVMに入った。

VMのルートディレクトリに移動し、ルートフォルダに格納されているフォルダ/ファイルを表示

```sh:VMのルートに移動して表示
docker@default:~$ cd /
docker@default:/$ ls
home          mnt           run           tmp
bin           init          opt           sbin          usr
c             lib           proc          squashfs.tgz  var
dev           lib64         sys           etc           linuxrc
root 
```

上記の「c」フォルダに、実際のWindows OSにおけるCドライブがマウントされている。
なので、VM上でC直下にアクセスするときには```cd /c/```みたいにする。

```sh:VMにマウントされたCドライブに移動して表示
docker@default:/$ cd /c/ 
docker@default:/c$ ls
Users
```

VMから出るときは```exit```コマンド

```sh:VMから出る
docker@default:/c$ exit
logout
exit status 127
```

### フォルダ・ファイルの構成を用意

適当な作業ディレクトリに、以下のような構成でフォルダ・ファイルを用意する

```
pythondocker/  : Windows側のワーキング・ディレクトリ
 ├ cgi-bin/    : Dockerコンテナ内で実行されるpythonスクリプトが格納されるフォルダ
 │ └ index.py  : 簡易ウェブサーバー立ててページを公開する
 └ Dockerfile  : Dockerファイル
```

### Dockerファイルを記述する
Dockerファイルは以下のように作る。

```python:pythondocker/Dockerfile
# python3.6.9のDockerイメージを取得してくる
# Dockerイメージにpythonをインストールしていると思えばおｋ
FROM python:3.6.9
# Dockerコンテナ内のワーキングディレクトリを指定する
WORKDIR /app
# Windowsの./cgi-binフォルダを、Dokcerコンテナ内のapp/cgi-binにコピーする
# こうすることで、cgi-bin以下のファイルにDocker内でアクセスできる
COPY ./cgi-bin /app/cgi-bin
# Docker内部で「python cgi-bin/index.py」というコマンドを実行する
CMD ["python", "cgi-bin/index.py"]
```
このDockerfileに記載されたコマンドは、Dockerイメージをビルドするときに上から実行されていく。


### ウェブページを公開するpythonスクリプトを作成

「pythondocker/cgi-bin」フォルダに「index.py」ファイルを作成する。
これは、Dockerコンテナー内に、簡易ウェブサーバーを立ててページを8080ポートで公開するためのPythonスクリプト。
　公開されたウェブサーバーにアクセスすると「Hello Python Docker on Widows 10 Home!」と表示する。
 　※なお、スクリプトは[Pythonで簡易Webサーバーを作る - Qiita](https://qiita.com/satken2/items/9969a6e69ecfbe8da823)を参考にした

```python:pythondocker/cgi-bin/index.py
import http.server
import socketserver

LISTEN_PORT = 8080

class ServerHandler(http.server.SimpleHTTPRequestHandler):

    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b"<h1>Hello Python Docker on Widows 10 Home!</h1>")

if __name__ == "__main__":
    HOST, PORT = '', LISTEN_PORT

    with socketserver.TCPServer((HOST, PORT), ServerHandler) as server:
        server.serve_forever()

```

### Dockerイメージのビルド

つづいて、作成したDockerファイルに基づいてDockerイメージをビルドする。
適当なコンソール（コマンドプロンプトなど）を立ち上げてpythondockerフォルダに移動し、

```shell
# 移動
C:\Users\hogehoge\workspace>cd pythondocker
# ついでにdirで確認
C:\Users\hogehoge\workspace\pythondocker>dir
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は 1273-2EFA です

 C:\Users\hogehoge\workspace\pythondocker のディレクトリ

2020/05/05  17:03    <DIR>          .
2020/05/05  17:03    <DIR>          ..
2020/05/05  17:00    <DIR>          cgi-bin
2020/05/06  16:05               581 Dockerfile
               1 個のファイル                 581 バイト
               3 個のディレクトリ  151,054,426,112 バイトの空き領域
```

docker buildコマンドを実行してDockerイメージをビルドする

```sh:Dockerイメージのビルドコマンド
C:\Users\hogehoge\workspace\pythondocker>docker build --tag=hellopython .
# --tag : イメージのタグ
# .     : Dockerファイルが置かれているフォルダへのパスを示している
```

以下のような出力がされれば成功

```sh:buildコマンドの出力
Sending build context to Docker daemon  4.608kB
Step 1/4 : FROM python:3.6.9
3.6.9: Pulling from library/python
16ea0e8c8879: Pull complete
50024b0106d5: Pull complete
ff95660c6937: Pull complete
9c7d0e5c0bc2: Pull complete
29c4fb388fdf: Pull complete
49a8841b38a3: Pull complete
c4a74b0ecce5: Pull complete
3e19e7d95a0c: Pull complete
c6c6b4054fe6: Pull complete
Digest: sha256:47e547af7ffcc2f5d1e5c76a96f4122943c4631d10bb3a0375e870fd95799107
Status: Downloaded newer image for python:3.6.9
 ---> 5bf410ee7bb2
Step 2/4 : WORKDIR /app
 ---> Running in 79bc620b5bcb
Removing intermediate container 79bc620b5bcb
 ---> 253f4f561100
Step 3/4 : COPY ./cgi-bin /app/cgi-bin
 ---> 2a4c59e6f250
Step 4/4 : CMD ["python", "cgi-bin/index.py"]
 ---> Running in f85f3c374389
Removing intermediate container f85f3c374389
 ---> 9f8b8e3b53d2
Successfully built 9f8b8e3b53d2
Successfully tagged hellopython:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
```

セキュリティのWarningが出てるがとりあえず無視。

ビルドしたDockerイメージがちゃんと作成されているか確認

```sh:dockerイメージの確認
C:\Users\hogehoge\workspace\pythondocker>docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hellopython         latest              8a31f9eb38e3        33 minutes ago      913MB
```

### ビルドしたDockerイメージを実行

いまビルドしたDockerイメージを実行し、ウェブサーバーをDockerコンテナー内で動かす。
コマンド```docker run```でビルドしたDockerイメージ hellopythonを実行。

```shell:Dockerイメージを実行
docker run --rm -p 4000:8080 -v /c/Cドライブからpythondockerフォルダまでのパス/cgi-bin/:/app/cgi-bin/ -d hellopython
```

```docker run```コマンドのオプションの説明は以下のとおり

- --rm : 停止＝削除になるオプション
  - コンテナを停止したらコンテナが自動で削除されるオプション
- -p : ポートフォワードのオプション
  - ポートフォワード。Docker上では8080ポートで公開しているウェブサーバーを、VM上では4000ポートからアクセスできるようにしていうｒ
- -v : ボリュームマウントのオプション
  - <VM上のパス>:<Dockerコンテナ内のパス>という形式
  - VM上のパスは、私の場合は「/c/Users/hogehoge/workspace/pythondocker/cgi-bin/」となる。（ちなみにWindows OS上では「C:\Users\hogehoge\workspace\pythondocker\cgi-bin」となっている）
  - VM上のパスが良くわからなくなったらこのページの[Virtual Boxで動いているVMのなかを覗いてみる](#Virtual-Boxで動いているVMのなかを覗いてみる)を参照。
- -d : 実行するDockerイメージを指定
  - 特にかくことなし

動いているDocker Containerを一応確認しておく

```shell:Dockerコンテナー確認
C:\Users\hogehoge\workspace\pythondocker>docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES 
eb3bf047d160        9f8b8e3b53d2        "python cgi-bin/inde…"   About an hour ago   Up About an hour    0.0.0.0:4000->8080/tcp   epic_jang
```

### Dockerコンテナー内で動いているウェブサーバーにアクセスする

最後に、Dockerコンテナー内で動いてるウェブサーバーにアクセスし、ブラウザ上に表示させる。
まず、Dockerコンテナーが動いているVMのIPを確認する。

```sh:VMのIP確認
C:\Users\hogehoge\workspace\pythondocker>docker-machine ip
192.168.99.100
```

あとは、ブラウザ上で「http://<IPアドレス>:4000」にアクセスすると、以下のようにウェブページが表示されるはず。
（私の場合は<http://192.168.99.100:4000/>）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391281/33847c6b-51aa-1301-43a0-8b5ac9695921.png)


## 参考にしたサイト
以下のサイトを参考にさせていただきました。
* [DockerでPythonを実行するコンテナを作る](https://gray-code.com/blog/python-on-docker/)
* [windows 10 home で docker を導入するメモ - Qiita](https://qiita.com/idani/items/fb7681d79eeb48c05144)
* [windows10のhomeだけどdocker使う \| ベンキョーベヤダベヤ](https://qooga.jb-jk.net/wp/use-docker-on-windows-10/)
* [Pythonで簡易Webサーバーを作る - Qiita](https://qiita.com/satken2/items/9969a6e69ecfbe8da823)