Windows 10 のWSL2でDocker CEを使ってHello PHP

# 概要

Windows 10でWSL2環境を用意する。
WSL2環境でDocker CEを使用して、PHPの（開発用）動作環境を作る。

# 動機

近い将来にDocker Desktopが個人・中小企業を除いて有料化される[^1]ので、一応、代替策を検討しておく。

[^1]: Docker Desktopが有料化へ、ただし250人未満かつ年間売り上げ1000万ドル（約11億円）以下の組織や個人やオープンソースプロジェクトでは引き続き無料で利用可能( https://www.publickey1.jp/blog/21/docker_desktop250100011.html )(公式 https://www.docker.com/blog/updating-product-subscriptions/ )

- 下記の方法で正しくライセンス問題を回避できているかどうかは保証しません。
- 運営元の経営のためにも、支払える方は支払うことをお勧めします。


# 動作環境
- Windows 10
- WSL2環境

# 基本的なWSL操作

後述の手順で使うかもしれない。

### WSLシェルの起動

シェルの起動方法はいくつかある。

1. Windowアプリ


WindowsのアプリにUbuntuがあるので、実行する。
　Microsoft Storeから取得した直後や、リセットの直後はこの方法で開始して、インストールを続行する。
![win-app-ubuntu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368897/1e742042-d8f4-3b58-06f0-fa1a1ef6c981.png)
2. コマンドプロンプト／Powershell
`ubuntu` を入力するとUbuntu (WSL)のシェルが開始する。
3. Visual Studio Code

ターミナルで＋ボタンを押して `Ubuntu (WSL)` を追加すると、WSLのシェルが開始する。
![vscode-wsl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368897/75432027-8e8e-0b33-bc0e-b98421a535e0.png)

### WSLの再起動

WSLの設定を変更しても反映されていない、と感じたら場合は、再起動すると解決することがある。

```winbatch:cmd
REM WSLを停止する
wsl --shutdown
REM シェルを開始しようとすると再度起動する
ubuntu
```

### WSLのリセット

　Ubuntu(WSL)の設定をどう変えたか分からなくなった場合は、リセットした方が早いかもしれない。Windowsアプリの「アプリの設定」→「リセット」で初期化できる。

![win-app-ubuntu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368897/1e742042-d8f4-3b58-06f0-fa1a1ef6c981.png)
![reset-ubuntu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368897/20ce4ae0-e073-8dca-8438-c6d4dcfb6999.png)



# 手順

## (Win) WSL2をインストールする

　おおむね公式インストールガイド[^2]に準じる。

[^2]: Windows 10 用 Windows Subsystem for Linux のインストール ガイド( https://docs.microsoft.com/ja-jp/windows/wsl/install-win10 )

補足

- ここではLinuxディストリビューションとして"Ubuntu" をMicrosoft Storeで取得する。
- バージョン 2 に変換した後、WSLを再起動する必要があるかもしれない。
- 最初のUbuntu起動時に、ユーザーを追加せずに閉じている。そのため、以降のWSL Ubuntuコマンドは root ユーザーで実行している。

## (WSL) Dockerをインストールする

基本的には公式ガイド[^3]に準じる。

[^3]: Install Docker Engine on Ubuntu ( https://docs.docker.com/engine/install/ubuntu/ )

```winbatch:cmd
REM WSLシェルを開始する
ubuntu
```

```bash:bash
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
sudo apt-get install \
  apt-transport-https \
  ca-certificates \
  curl \
  gnupg \
  lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```

architectureとUbuntuのバージョンを確認する。

```bash:bash
uname -a
# ここでは amd64
lsb_release -cs
# ここでは focal
```

公式ガイドでは次のコマンドが下記のようになっている。しかし実行しても "E: Unable to locate package docker-ce" のエラーが発生して続行できない。

```bash:bash
# 公式ガイドのコマンド（機能しない？）

#echo \
#    "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
#    $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
#sudo apt-get update
#sudo apt-get install docker-ce docker-ce-cli containerd.io
```

筆者の場合は対象のリポジトリ追加の処理を変更して解決した。なお上述の architecture
とUbuntuバージョンでコマンドが変わるので注意。

Unable to locate package `docker-ce` on a 64bit ubuntu
https://unix.stackexchange.com/a/363058

　他にも発生原因は何種類かあるらしい[^4]。

[^4]: 本文で挙げていない例は、シェルでy/Nの確認を受けた時に y を入力していない ( https://stackoverflow.com/a/61430137 )、ディストリビューションが Linux Mintだと`$(lsb_release -cs)` 部分が適切でない、など。


```bash:bash
# 上の代替策
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt update
sudo apt-get install docker-ce docker-ce-cli containerd.io
```

dockerサービスを起動するとイメージのビルドやコンテナの起動ができるようになる。

```bash:bash
service docker start
docker run hello-world

# メッセージが出たらOK
# Hello from Docker!
# This message shows that your installation appears to be working correctly.
```

## (Win) ソースコードとDockerfileを用意する

```winbatch:cmd
mkdir C:\projects\hellophp\docker
mkdir C:\projects\hellophp\src
```

Dockerfileを作る。

```dockerfile:C\projects\hellophp\docker\Dockerfile
FROM php:8.0.10-apache
# 本稿では最小限で動作確認する。
# 慣れたら php.ini の変更など、色々とここに書く。
```

hello.phpを配置する。
https://www.php.net/manual/ja/tutorial.firstpage.php

```php:C\projects\hellophp\src\html\hello.php
<html>
<head>
<title>PHP Test</title>
</head>
<body>
<?php echo '<p>Hello World</p>'; ?>
</body>
</html>
```


## (WSL) 開発用のイメージをビルドする

```bash:bash
cd /mnt/c/projects/hellophp/docker
docker build -t hphp .
```

上記のDockerfileは空フォルダに入れておくと処理が速い[^5]。
[^5]: Dockerfile のベストプラクティス：.dockerignore ファイルを使う( https://docs.docker.jp/engine/articles/dockerfile_best-practice.html#dockerignore )


## (WSL) コンテナを作成する

```bash:bash
docker create --name chphp --publish 80:80 --mount source=/mnt/c/projects/hellophp/src,target=/var/www,type=bind,consistency=cached hphp
# コンテナ起動
docker start chphp
# curlでhtmlファイルらしきものが取得できるはず。
curl http://localhost/hello.php
```

```bash:bash
# コンテナ停止
docker stop chphp
# 停止中にcurlするとエラーになるはず。
curl http://localhost/hello.php
# curl: (7) Failed to connect to localhost port 80: Connection refused
```

## (Win) WSLをホストするWindowsからアクセスする

`.wslconfig` を作成する、または次の設定を追記する。

```txt:%USERPROFILE%\.wslconfig
[wsl2]
localhostForwarding=true
```

http://localhost/hello.php にアクセスできるようになるはず。設定後にWSLの再起動が必要かもしれない。

## 完成

以降はWSLでdockerサービスを起動してコンテナを起動すると、最低限の開発はWindowsで可能なはず。

```bash:bash
service docker start
docker start chphp

# コンテナ内でシェルを開始する
docker exec -it chphp bash
# コンテナ内のシェルを終了する
exit

# コンテナ停止
docker stop chphp
```

# その他

比較的よく使うDockerコマンド

```bash:bash
# 停止したコンテナを削除
docker container prune
# コンテナ一覧
docker container list
# コンテナ内のディレクトリ・ファイルをホストにコピー
# 下記はコンテナ内の /tmp/hellophp/logs を
# ホストWSLの /mnt/c/tmp/hellophp/ に
#（つまりWindowsの C:¥tmp¥hellophp に）コピーする
docker cp CONTAINER_ID:/tmp/hellophp/logs /mnt/c/tmp/hellophp/

# イメージ一覧
docker image list
# イメージを削除
docker rmi IMAGE [IMAGE...]
# タグがないイメージを削除
docker image prune
```