【Docker】ftpで手動アップロードしたファイルをWebブラウザで表示させる

Dockerに関する情報は色々とあります。
- ①DockerでPHPを表示させる。
- ②Dockerでftpを使って、ファイルアップロードする

ここまでは、世の中のサイトに色々と情報があったので、実現できました。ですが、今回やりたかったことは①と②の合せ技、つまり
- ③Dockerで構築したftpでPHPファイルをアップロードし、Webブラウザで表示させる

この方法がどこを調べても載っていなかったので、調べて備忘録として置いておきます。ちなみに自分はDockerについては勉強開始中の初心者なので、説明はかなり端折っています。

# 使用環境
今回の環境は以下の通りです
- Windows10 64bit
- Docker Desktop
- HyperV
- Ubuntu22
- WSL2
- PHP8.1
- Apache2
- ffftp3

# PHPを表示する
今回PHPはApacheを使って表示させます。DockerでPHPを表示させるには２つの基本を押さえておけば大丈夫です。
- webサーバーの選択（Apache、Nginx）し、PHPの使用バージョンを選択する
- ブラウザ表示用のパスを設定する

特に今回大事なポイントはブラウザ表示用のパスとそれに対するポートの指定で、ここを勘違いするとハマります。

```
任意のDockerコンテナ - ■docker - ■php - Dockerfile 
                    　　　    - ■ftp - ■home
                   - ■src - index.php #このディレクトリをルートパスとする
                   - docker-compose.yml #設定ファイル
```

## docker-compose.ymlの設定
まずはコンテナの設定ファイルを見ていきます。appというのはWebサーバーの定義ファイル名で、そのcontext（従属）はdocker/phpパスの中、つまり直下のDockerfileを見ることになります。

また、volumesはパスを指定しています。ざっくばらんに言えば

**ホスト上のパス:各コンテナ上のパス**

となるので、Webサーバで/var/www/html（これはApacheの標準ルートパスとなります）を紐づけているのはdockerコンテナ上のsrcディレクトリ直下となります。またポートに対しApacheは80番ポートが標準になりますが、今回80番は他のシステムが占拠していたので8000番に振り分けています（ポートフォワーディング）。

```yml:docker-compose.yml
services:
  app:
    build:
      context: ./docker/php
      dockerfile: Dockerfile 
    volumes:
      - ./src:/var/www/html #今回ブラウザで表示させたいWebサーバのルートパス
    ports:
      - "8000:80" #フォワーディングさせたいポート
```

## PHP定義のDockerfile
ではdocker-composeに紐づいたPHPの定義ファイルを見に行きますが、このようになっています。まずはどのPHPのバージョンを使用するかを定義し、引き続き追加で必要なライブラリを追加します。WORKDIRはルートパスの位置となり、EXPOSEはブラウザで表示させたいポート番号と一致させます。

```docker/php/Dockerfile
FROM php:8.1-apache
RUN apt-get update \
    && docker-php-ext-install mbstring

WORKDIR /var/www/html

EXPOSE 8000 #一致させる
```

### PHPファイルの作成
テスト用ファイルは以下のように書き込んでおきます。

```php:src/index.php
<?php
    echo phpinfo();
```

これで一旦docker-composeを起動させます。

```
$docker compose up -d
```

これで以下のようにPHPファイルが見えれば成功です。ブラウザでは8000番を見ていることになります。

![path.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272191/4994951b-ac73-a510-f673-b7c982c23da3.jpeg)



# ftpを設定する
続いてftpを設定します。Dockerでftpを利用する場合は**pure-ftpd**を利用します。ここはそこまで難しくはないです。先程のdocker-compose.ymlに追記していきます。

```yml:docker-compose.yml
services:
  #中略
  #先程のWebサーバー設定（app）のあとに追記する
  ftp-server:
    image: stilliard/pure-ftpd:latest
    ports:
      - "21:21"
      - "30000-30009:30000-30009"
    environment:
      PUBLICHOST: "localhost"
      FTP_USER_NAME: test
      FTP_USER_PASS: hoge
      FTP_USER_HOME: /home/test
```

設定が終わったらffftpにアクセスしてみましょう。ホスト名もlocalhostで大丈夫です。うまくつながれば準備完了です。ですが、試しにtest_doc.phpというファイルを転送してみても、Dockerコンテナのどこにもファイルは存在していません。

```php:test_doc.php
<?php
    echo "hogehoge";
```

```
$sudo find /home -name 'test_doc.php' #Ubuntu内で探しても見つからない
```

なぜなら、**ホストへの転送パスを指定していない**からです。なので、コンテナの中に入って、ftpサーバのどこに転送されたか調べてみます。
```
$ docker ps  //ftpサーバのnameを調べる
$ docker exec -it hoge-ftp-server-1 bash //調べたftpサーバでコンテナに入る
# find / -name 'test_doc.php'
/home/test/test_doc.php
```

このようにftpサーバ内の/home/testディレクトリ直下にファイルが転送されていたようです。これはFTP_USER_HOMEで設定したパスと一致しています。

## 転送先を制御する
そこでftpサーバに対するdocker-composeでのホストの転送場所を設定し、Dockerコンテナと紐づけます。パスの紐づけはvolumesで行えます。よく見る開発系ブログなら以下のように記述したりしていますが、まずは以下のように書き換えて、もう一度dockerを再起動します。

```yml:docoker-compose.yml
  ftp-server:
    image: stilliard/pure-ftpd:latest
    ports:
      - "21:21"
      - "30000-30009:30000-30009"
    volumes:
      - ./docker/ftp/home:/home/test #パスを作る
    environment:
      PUBLICHOST: "localhost"
      FTP_USER_NAME: test
      FTP_USER_PASS: hoge
      FTP_USER_HOME: /home/test
```

では、同じように探してみましょう。Dockerコンテナ内のdocker/ftp/home直下にアップロードされていました。

```
# exit //一旦、コンテナの外に出る
$ find /home -name 'test_doc.php' //転送したあとにファイルを探す
/home/…/docker/ftp/home/test.doc.php //以下のように表示される
```

### ftpサーバとWebサーバの転送先を一致させる
ここで勘のいい人ならピンと来たと思います。volumesでサーバの転送先を紐付けることができたので、この**docker-composeでのftpサーバの転送先を、先程のwebサーバのルートパスと一致**させます。

```
ftp-server:
    volumes:
      - ./src:/home/test #ftpサーバのパスをwebサーバと一致させる
```

これでもう一度サーバを再起動して、ffftpにアクセスしてみましょう。

![lookftp.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272191/aeb36571-dddc-e9ec-b7d6-c92e78eb0642.jpeg)

PHPのテスト用に設定したindex.phpが見えています。つまり、Webサーバとftpサーバのルートパスが一致しています。index.phpはデフォルトなので、ここにtest_doc.phpを表示させたい場合はブラウザに明示的に記述すれば大丈夫です。

![hogehoge.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272191/92591645-d957-fb88-10f4-065d3067a4df.jpeg)

今回はPHPだけでしたが、これを応用すればDjango、Rails、LaravelなどでもDockerで組み立てた環境に対して、自由自在にftpでアップロードさせていくことができます。あとは愛用エディタのftpプラグインと連動させたりすることも可能です。