コンテンツにスキップ

ConoHa WINGでPython (FastAPI + SQLAlchemy)を使う

当ブログはConoHa WINGを使って公開していますが、せっかくWebサーバー(Apache + nginx)とデータベース(MySQL)が提供されているのにそれを利用しないのは勿体ないので、ConoHa WING上で自作Webアプリを動かせないかと考えていました。

ConoHa WINGは共用サーバーでサービスを提供しており、WordPressの運用に強いサーバー環境が整っています。そのため、PHP(Laravelも使用可能)で開発したWebアプリは動かしやすいのですが、PythonでFastAPIやSQLAlchemyを使って開発したWebアプリを動かすにはいくつか課題がありました。

本記事では、FastAPIとSQLAlchemyを使ったWebアプリをConoHa WING上で動くようにしたときの手順について説明します。

ConoHa WINGで利用できるPythonのバージョン

Section titled “ConoHa WINGで利用できるPythonのバージョン”

ConoHa WINGは、PHPの他にもプログラミング言語をいくつか用意しています。

sshでログインして、インストールされているPythonのバージョンを確認してみると、以下のバージョンが用意されていることが分かりました。

ConoHa WING
[c********@web**** ~]$ ls /opt/alt/|grep python
python-internal
python27
python311
python36
python37
python38

この記事を書いている時点でPython 3.11が用意されていますので、これを使って環境を構築します。

サンプルプログラムのダウンロードと環境構築

Section titled “サンプルプログラムのダウンロードと環境構築”

FastAPISQLModelを使った練習用Webアプリ(location-logger-fastapi)を開発してGitHubに公開していますので、これをConoHa WINGのサーバーにcloneします。

ConoHa WING
mkdir -p ~/workdir/
cd ~/workdir/
git clone https://github.com/yamakox/location-logger-fastapi.git

さらに、Pythonのソースコードの入ったフォルダー(backend)に移動して、Python 3.11の仮想環境を作成します。

ConoHa WING
cd location-logger-fastapi/backend
/opt/alt/python311/bin/python3 -m venv .venv

ConoHa WINGのコントロールパネル → サーバー管理ドメインの画面を開き、+ドメインボタンでWebアプリ用のサブドメインを追加しておいてください。

補足: location-logger-fastapiについて

location-logger-fastapiは、以下の構成でWebアプリを実装しています。

flowchart LR
  ui["`**Vueアプリ**
     地図・地名表示、
     現在位置の取得`"]
  www["`**WWWサーバー**
      Vueアプリ配信`"]
  api["`**FastAPI**
      REST APIの実装
      +
      **SQLModel**
      SQLAlchemy経由でDB操作`"]
  db["`**MySQL**
     位置情報の記録`"]

  subgraph client [Webブラウザ]
    direction TB
    ui
  end

  subgraph server [サーバー]
    direction TB
    www
    api
  end

  subgraph database [データベース]
    direction TB
    db
  end

  ui <--> www
  ui <--> api
  api <--> db

Vueアプリのスクリーンショットは以下のとおりです。

課題: ConoHa WINGでFastAPIアプリを動かす方法

Section titled “課題: ConoHa WINGでFastAPIアプリを動かす方法”

FastAPIで開発したアプリはuvicornなどのASGI Webサーバーを使って動かすことが一般的と思いますが、共用サーバーのConoHa WINGでは、独自のWebサーバーを動かす方法は提供されていないと思います。

そのため、ConoHa WINGが用意しているApache経由でFastAPIのアプリを呼び出せるようにします。

location-logger-fastapiでは./public/index.cgiを作って、ApacheからCGIとしてFastAPIのアプリを呼び出せるようにしています。具体的には、CGIスクリプトの中でASGIMiddlewareCGIHandlerを使ってFastAPIアプリを実行します。

./public/index.cgi
#!/home/c*******/workdir/location-logger-fastapi/backend/.venv/bin/python3
from dotenv import load_dotenv
from pathlib import Path
# index.cgiと同じ場所に置いてある.envファイルを読み込む
env_path = Path(__file__).parent.resolve() / '.env'
load_dotenv(str(env_path))
from a2wsgi import ASGIMiddleware
from wsgiref.handlers import CGIHandler
from location_logger import create_app
# FastAPIには`/index.cgi/パス`が渡される
app = create_app(base_url='/index.cgi')
app = ASGIMiddleware(app)
CGIHandler().run(app)

create_app関数は./backend/location_logger/__init__.pyで実装しており、base_url引数の値をFastAPIクラスの初期化時にroot_pathパラメータに渡しています。

./backend/location_logger/__init__.py(一部抜粋)
from fastapi import FastAPI
from . import api
def create_app(base_url: str = '') -> FastAPI:
app = FastAPI(root_path=base_url) # `/index.cgi`をroot_pathとする
app.include_router(api.v1.create_router()) # `api`モジュールの中でAPIエンドポイントを作成する
return app

課題: 依存関係のあるPythonパッケージのインストール

Section titled “課題: 依存関係のあるPythonパッケージのインストール”

sshでログインして、ConoHa WINGのPython仮想環境に依存関係のあるPythonパッケージをインストールするときに問題が発生しました。

ConoHa WING
[c********@web**** backend]$ source .venv/bin/activate
(.venv) [c********@web**** backend]$ pip3 install .
(中略)
コンパイルを停止しました。
error: command '/usr/bin/g++' failed with exit code 1
----------------------------------------
ERROR: Failed building wheel for greenlet
Successfully built location-logger
Failed to build greenlet
ERROR: Could not build wheels for greenlet, which is required to install pyproject.toml-based projects

greenletはSQLAlchemyに依存関係のあるパッケージですが、greenletのインストール時にソースコードからのビルドが動いてしまい、コンパイルエラーが発生してインストールに失敗します。

そこで、ソースコードからビルドしないように、greenletを--no-buildオプション付きでインストールします。

ConoHa WING
(.venv) [c********@web**** backend]$ pip3 install --no-build greenlet
(中略)
Downloading greenlet-3.2.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (643 kB)
|████████████████████████████████| 643 kB 65.9 MB/s
Installing collected packages: greenlet
Successfully installed greenlet-3.2.5

(中略)の部分では、新しいバージョンから順にインストールしようとしてエラーが発生し、段々と古いバージョンのパッケージを試している様子が伺えます。

greenlet 3.2.5がインストールできたので、残りのパッケージをインストールします。

ConoHa WING
(.venv) [c********@web**** backend]$ pip3 install .
(中略)
Successfully built location-logger
Installing collected packages: (以下略)

FastAPIアプリのインストールは無事成功しました。

ConoHa WING
(.venv) [c********@web**** backend]$ python3 -m location_logger.db init
# テーブルができていることを確認する
(.venv) [c********@web**** backend]$ source .env
(.venv) [c********@web**** backend]$ mysql -h${DB_HOST} -P${DB_PORT} -u${DB_USER} -p${DB_PASSWORD} ${DB_NAME}
mysql> SHOW TABLES;
+----------------------+
| Tables_in_*****_**** |
+----------------------+
| clients |
| locations |
+----------------------+
2 rows in set (0.00 sec)

.envファイルを作成してデータベースの初期化コマンドを実行すると、正常にテーブルが作成できましたので、これでFastAPIとSQLAlchemyを使ったアプリが動く環境を整えることができたと判断します。

課題: Node.jsはConoHa WINGに用意されていない

Section titled “課題: Node.jsはConoHa WINGに用意されていない”

ConoHa WINGではプログラミング言語をいくつか用意されていますが、Node.jsやnpmは提供されていません。

そのため、ローカル環境でVueアプリのビルドを行い、scprsyncを使ってサーバーのpublic_html/<サブドメイン名>フォルダーに転送します。 ./public/index.cgiもローカル環境で作成して、Vueアプリのビルド成果物の中に含めます。

ローカル環境
# Vueアプリのビルド
npm i
npm run build
# dist配下のファイルをコピーする
scp -P <ポート番号> -r ./dist/* ./dist/.[!.]* <レンタルサーバのユーザ名>@<レンタルサーバ名>:/home/<ユーザー名>/public_html/<サブドメイン名>

これで、Vueアプリの配信とFastAPIで実装したAPIエンドポイントの公開を、ConoHa WINGのApache経由でできるようになりました。ブラウザでVueアプリを表示して、FastAPIで実装したAPIを使って取得した値(CIDVersion)が表示されていれば、正常に動作しています。

Python(FastAPI+SQLAlchemy)を使ったWebアプリは、index.cgiを作成してConoHa WINGで動かすことができました。 ConoHa WINGのCloudLinux環境では、Pythonパッケージのインストールに失敗することもありますが、--no-buildオプションで回避できる可能性があります。

flowchart LR
  ui["`**Vueアプリ**
     地図・地名表示、
     現在位置の取得`"]
  www["`**index.htmlなど**
      Vueアプリ配信`"]
  api["`**index.cgi**
      FastAPI + SQLAlchemy`"]
  db["`**MySQL**
     位置情報の記録`"]

  subgraph client [Webブラウザ]
    direction TB
    ui
  end

  subgraph public_html [public_html/ドメイン名]
    www
    api
  end

  subgraph server [ConoHa WING]
    direction LR
    public_html
    db
  end

  ui <--> www
  ui <--> api
  api <---> db

APIを呼び出すたびにindex.cgiが動くのでuvicornを使った場合と比べるとレスポンスが良くありませんが、それでも自作Webアプリを公開できる可能性が広がったことは意義があると思います。