ちょっと触っただけので大した内容ではなくて、各部分の基本構成とロジックをまとめる文章です

何がうれしい

  • Dockerは、依頼関係をパッケージ化することができるもので、実行するデバイスを変えても環境設定は要らない(例えAIプログラムを実行するときに必要なモデルとInputも、パッケージ化されている)

  • WSLは、Windows Subsystem for Linuxで、windowsOSでLinuxを実行するように最適化された仮想マシンです。これでLinuxと同じように使える。

  • Flask:Python用のウェブアプリケーションフレームワークです。PythonだけでAPIを構築できる。

環境設定

一番苦労するところかも。。。

WSL2

https://learn.microsoft.com/ja-jp/windows/wsl/install#step-4---download-the-linux-kernel-update-package

ここは特に記憶はないから、多分難しくない

Ubuntu

普通のネットワークの下のならAppStoreから簡単に落とせるが、例えばセキュリティでStoreが使えない場合には下のリンクを参考すればいい

WSL2にUbuntuをインストール | ソフトウェア Tech Tips (softtechtips.net)

Docker

windowsにWSL2+Docker環境を構築する手順 #Windows - Qiita

整理してみて。。。

  1. Flask+Pythonの実行プログラム完成
  2. Dockerfileで依頼関係を定義して、必要なInputを一つのフォルダにまとめる
  3. ローカルのポートをWSL上にForwardingして、WSLのIPアドレスを固定する
  4. 必要な外部ファイルをマウントして、DockerContainerを実行する

Flask

基本構成

from flask import Flask, request, jsonify
import your_model # モデルをインポート

app = Flask(__name__)

@app.route('/predict', methods=['POST'])
def predict():
# 情報を受け取る
file_path = request.json['file_path']
file = open(file_path)

# ここでファイルをAIモデルに渡して予測を行う
result = your_model.predict(file) # モデルによる処理

if error_condition :
return jsonify({'error': 500}), 500

return jsonify({'result': result}) # 結果をJSON形式で返す

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000) # ポート5000で実行
  • @ マーク:デコレーターです。下の関数を引数として受け取る。

    ここの@app.route はFlaskのルーティングデコレーターで、ユーザの関数と特定のURLをマッピングしていて、/predictにPOSTリクエストが来ると、Flaskは自動的にpredict関数を呼び出す。

    • Note:”/predict”と“/predict/”は異なるルート
  • request.<extract_method>[Info]

    クライアントのリクエストは、一般的にはURL情報だけではなくて、Inputの情報もある。(E.g.例えば天気APIに請求を送るときにも、いつDayの情報が欲しいかも伝える必要がある)。そのような追加情報を抽出するために、Flaskにはrequestというツールを用意している。書き方によっていろんな抽出方法があるので、具体的には:flask.request 自分用チートシート #Python - Qiita

  • app.run(host='0.0.0.0', port=5000)

    指定されたポートに送られた情報だけを受け取る。0.0.0.0はすべてのアドレスをリッセンすることを示す。一台のPCは基本的は

    • ホストアドレス(ipconfigを打って出たIP、外部からアクセス可能)
    • ローカルアドレス(localhostやほかのプライベートアドレス、外部アクセス不可)

      のように、複数のIPアドレスを保有します。

テスト方法

cURL:さまざまなプロトコルを利用してデータ転送するコマンドラインツール

これがあればコマンドラインだけでFlaskの動作を確認できる

curl -X POST http://localhost:5000/predict -H "Content-Type: application/json" -d '{"path": "example.jpg"}'

  • -X POST/GET <URL:port> : POSTまたはGETメソッドで指定したURLに情報を送る
    • ポートを一致しないと受け取れない

Dockerfile

Dockerの流れは以上のように、実際に動くコンテナは全く独立している容器だ。その中にあらかじめ、必要とする依頼関係(Python、pytorch…)、作業用のフォルダ(/app)、外部のファイルを作業用フォルダにコピーする(model…)

Containerで動くプログラムは外部に一切アクセスできないと考えてもいいかな

# ベースとなるイメージの指定
FROM python:3.8

# 依存関係をインストール
RUN apt-get
RUN pip install -r requirements.txt

# イメージ内で作業するディレクトリを指定
RUN mkdir /app
WORKDIR /app

# 必要なファイルをホストからコンテナにコピー
COPY requirements.txt /app/
COPY . /app/

# アプリケーションを実行するコマンドを指定
CMD ["python", "app.py"]
  • ベース:

    Pythonだけを使って軽量なAPPならPythonをベースとしたDockerは十分

    でも実際に使うときにUbuntuをベースとするケースが一番普通のらしい。区別はGPT先生に聞いた:

    • python イメージは、Python アプリケーションに特化した環境であり、すぐに開発を開始できる軽量なベースイメージです。
    • ubuntu イメージは、汎用的な Linux システムで、環境を細かくカスタマイズしたい場合に適していますが、セットアップに手間がかかる場合があります。

      FROM ubuntu:20.04
      RUN apt-get update && apt-get install -y python3 python3-pip

    っと、自分もまだ理解していないです。。。

ノート:Ubuntuを利用する場合には、Python3.9は一番最後にサポートされるバージョンで、3.10以上をインストールしたいなら別のコードを追加する必要がある

WSL2

WSL2は、windowsOSと完全に異なる別のOSとして存在する仮想マシン。

なので、独立したIPアドレス、ファイルシステムを保有する。これでwindows側で書いたコードはここで動けない可能性がある。

IPアドレスの処理

参考:Windowsでwsl2(Ubuntu)上のDockerに外部から接続する #Windows10 - Qiita

  1. ローカルのIPアドレス上のポートを転送する
  2. WSL2のIPアドレスを自動で取得する(自動化しないと再起動するたびに転送する用のコマンドが変わる)

WSLのIPアドレスを確認

hostname -I

手動で転送を設定する

# ローカルPCのポートXXXXに来たパケットをwsl2のポートXXXXに転送(XXXXはDockerで使用するポート番号)
netsh.exe interface portproxy add v4tov4 listenaddress=<ローカルPCのIPアドレス> listenport=<ポート番号> connectaddress=<WSLのIPアドレス> connectport=<ポート番号>

# 設定を確認する場合
netsh.exe interface portproxy show v4tov4

# 設定を削除する場合
netsh.exe interface portproxy delete v4tov4 listenport=<ポート番号> listenaddress=<ローカルPCのIPアドレス>

自動化

#rootで実行
wsl -d Ubuntu -u root exec sudo service docker start

### WSLのIPアドレス取得
$hostname = wsl -d Ubuntu exec hostname -I
$wslIP,$dummy = $hostname.Split(" ")

### ホストPCのIPアドレス取得
$HostIP = (
Get-NetIPConfiguration |
Where-Object {
$_.IPv4DefaultGateway -ne $null -and
$_.NetAdapter.Status -ne "Disconnected"
}
).IPv4Address.IPAddress

##########################
# ポートフォーワード設定 #
##########################
# 22だけ2022から繋ぐ(22はホストPC自体に接続したいので)
netsh interface portproxy add v4tov4 listenaddress=$HostIP listenport=65176 connectaddress=$wslIP connectport=8000

これで自動化したスクリプトはできたが、毎回管理者としてPSを実行して、スクリプトを開くのもめんどくさいし、さらに自動化した:

  1. ショットカートを作成する
  2. パス=powershell -ExecutionPolicy Bypass -File "path_to_your_script.ps1"
  3. プロパティ➝ショットカート➝詳細➝管理者として実行☑

これで、ショットカートをクリックするだけでポート転送の設定は完了

ファイルシステム

ローカルに保存されている内容は/mnt/で確認できる。(GUIによるアクセスできない)

アクセスするために

  1. DockerfileにCOPYを用いて作業フォルダにコピーしておくか
  2. docker containerを動かすときにファイルをマウントする:docker run -v <local_file_path>:<workplace_path>

Dockerの実行

いよいよ最後だ。いくつかのDockerコマンドを知っておくべき。

Dockerサービスの開始、停止、再開(デフォルトは停止の状態)

sudo service docker status

sudo service docker start

sudo service docker restart

Dockerイメージをビルトする

build -t <image_name> <path_to_docker_folder>

イメージの一覧と削除

docker images

docekr rmi <images_id>

イメージでコンテナーを起動

docker run <options> <image_name>

  • --rm: automatically remove the container when it stop
  • -it: interact with container
  • -d: detach mode (run in background)
  • -p <host_port>:<container_port> :ホストのポートをコンテナ内のポートに転送する(コンテナと外部は分離している
  • --gpus <numbers/all>: use gpu to runshrconta

コンテナーの操作:一覧、停止、削除

docker ps -a

docker stop <container_id>

docker rm <container_id>

起動して、テストコマンドをローカル環境で実行して、responseが届いたら成功

以上。

追記

興味でAPIの動き方をもう少し調べた。FlaskAPIは確かにウェブアプリケーションとして動けるが、多数のリクエストが殺到すると対応できなくなる。また、セキュリティー問題もあります。

そのため、ウェブサーバーソフトを追加する必要がある(Apache、IIS)。それらとFlaskを合わせて利用するのは一般です。

あと、基本的には外部から内部アドレスにアクセスするのはできない(会社からHomePC)。それを実現したいなら、ルータのポートフォワーディングを設定するか、VPNを構築するか、が必要です。