筒井
前半ではCloudflare WorkersでPythonを使う方法について、後半ではCloudflare WorkersでPythonを動かす仕組みと技術的制限について解説します。
なお、Cloudflare WorkersのPythonサポートは本記事執筆時点
Cloudflare Workersとは
Cloudflare Workersは、Cloudflareが提供するサーバーレスアプリケーションを構築・
- プログラマーはサーバーの管理やスケーリングを意識せずに、アプリケーションの開発に集中できる
- エンドユーザーは物理的に最も近いサーバーにアクセスするため、高速なレスポンスを期待できる
- コールドスタート
(しばらく実行されていない関数を実行しなければならない状況) が排除されているため、高速な起動時間が期待できる - 無料枠があるため、気軽に試すことができる
類似のサービスとしてAWS Lambda@Edgeがありますが、Lambda@Edgeには無料枠がありません。また、Cloudflare WorkersにはJavaScript実行を高速化するための最適化が施されているため、Lambda@Edgeよりも高速なレスポンスが期待できます。
Cloudflare WorkersとLambda@Edgeの比較についての詳細は、以下の記事を参照してください。
Cloudflare Workersがサポートする言語
Cloudflare Workersがサポートする言語は以下の通りです。
- JavaScript
- TypeScript
- WebAssembly
(Wasm) のバイナリにビルドできる言語 (Rust、C、C++、Kotlin、Goなど) - Python
(オープンベータ版)
Cloudflare Workersの料金
Cloudflare Workersには無料のFreeプランと有料のStandardプラン、Enterpriseプランがあります。本記事ではFreeプランを使います。Freeプランでの制限は、以下の公式ドキュメントを参照してください。
また、リクエスト制限やアプリケーションのサイズ制限などについては、以下の公式ドキュメントを参照してください。
Cloudflare WorkersでPythonを使う方法
ここでは、Cloudflare WorkersでPythonを使う方法について解説します。
実際にローカル環境で本記事の内容を試すには、以下が必要です。
- Node.
js 16. 17. 0以上 - npx
また、本番環境にコードをデプロイする際には、Cloudflareアカウントが必要です。
まずはサンプルコードを動かしてみる
公式ドキュメントGet startedにあるサンプルコードをローカル環境で動かしてみましょう。
以下の手順でサンプルコードをダウンロードし、Cloudflare Workersの開発者ツールWranglerを使ってローカルサーバーを起動します。最新のWranglerをインストールするかどうか確認するためOk to proceed? (y)
と聞かれる場合がありますが、Enterキーを押して進めてください。
$ git clone https://github.com/cloudflare/python-workers-examples $ cd python-workers-examples/01-hello $ npx wrangler@latest dev ⛅️ wrangler 3.65.0 ------------------- ▲ [WARNING] The entrypoint src/entry.py defines a Python worker, support for Python workers is currently experimental. ⎔ Starting local server... [wrangler:inf] Ready on http://localhost:8787 ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ [b] open a browser, [d] open Devtools, [l] turn off local mode, [c] clear console, [x] to exit │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
[b] open a browser, [d] open Devtools, ...
と表示されたら、bキーを押してください。ブラウザが開いてアプリケーションの画面が表示されます。
xキーを押すとローカルサーバーが停止します。
サンプルコードの中身を見てみましょう。src/
リクエストはon_
という名前の関数で処理され、jsというモジュールを使ってレスポンスを返しています。このjsモジュールは、JavaScript APIを呼び出すためのものです。PythonなのになぜJavaScript?
次に、本番環境にデプロイしてみましょう。以下のコマンドを実行してください。Ok to proceed? (y)
と聞かれる場合がありますが、Enterキーを押して進めてください。デプロイしたアプリケーションに割り当てられるサブドメインが未設定の場合は、サブドメインの入力も求められます。全Cloudflareユーザーで一意な名前を入力してください
$ npx wrangler@latest deploy ⛅️ wrangler 3.65.0 ------------------- ▲ [WARNING] The entrypoint src/entry.py defines a Python worker, support for Python workers is currently experimental. Attempting to login via OAuth... Opening a link in your default browser:〈省略〉
コマンド実行後、以下のようなアプリケーションのデプロイを許可する画面が表示されます
以下の画面が表示されたらデプロイ成功です。画面はこのまま閉じても問題ありません。
CloudflareダッシュボードのWorkers & Pagesには、今デプロイしたアプリケーション
「hello-python」
または、npx wrangler@latest deploy
を実行した際に表示されるPublished hello-python
の下にあるURLをブラウザで開いても、同じ画面が表示されます。
環境変数を使ってみる
APIの認証情報やデータベースの接続情報などは、本番環境、ステージング環境によって異なる場合があります。そのような情報は環境変数としてソースコードの外に定義しておくと、環境ごとに異なる情報を簡単に切り替えることができます。
Cloudflare Workersでも環境変数を扱うことができます。前述のサンプルコードを使って、環境変数の値を取得してみましょう。
src/
上記のコードで参照している環境変数MY_
、SECRET_
を定義します。SECRET_
は秘密の情報という前提です。wrangler.MY_
を設定します。
秘密の情報をローカル環境で参照する場合は、プロジェクト直下の.dev.
ローカル環境で動作確認を行います。npx wrangler@latest dev
を実行すると、以下のようにwrangler.
次に、本番環境にデプロイするため、SECRET_npx wrangler secret put
コマンドを使います。****************
の部分には
$ npx wrangler secret put SECRET_KEY ⛅️ wrangler 3.65.0 ------------------- ✔ Enter a secret value: … **************** 🌀 Creating the secret for the Worker "hello-python" ✨ Success! Uploaded secret SECRET_KEY
npx wrangler@latest deploy
を実行してからブラウザでアプリケーションを表示すると、以下のように環境変数の値が表示されます。
環境変数の内容は、CloudflareダッシュボードのWorkers & Pagesからも確認できます
簡単なAPIを作成する
書籍の情報を登録・
- POSTメソッドの場合:書籍のtitleとdescriptionを受け取るとDBに登録する
- titleとdescriptionのいずれかがない場合は400エラーを返す
- GETメソッドの場合:DBに保存されている書籍情報
(titleとdescription) を取得する - POST、GET以外のメソッドの場合:405エラーを返す
データベースはCloudflare D1を使います。Cloudflare D1とは、SQLiteで構築されたサーバーレスSQLデータベースです。
src/
次に、以下のコマンドで本番環境にbookshelfデータベースを作成します。
$ npx wrangler d1 create bookshelf ⛅️ wrangler 3.65.0 ------------------- ✅ Successfully created DB 'bookshelf' in region APAC Created your new D1 database. [[d1_databases]] binding = "DB" # i.e. available in your Worker on env.DB database_name = "bookshelf" database_id = "***"
上記の出力内容から[[d1_
以下をコピーして、wrangler.
テーブルを作成するため、schema.
以下のコマンドで、schema.
$ npx wrangler d1 execute bookshelf --local --file=./schema.sql ⛅️ wrangler 3.65.0 ------------------- 🌀 Executing on local database bookshelf (***) from .wrangler/state/v3/d1: 🌀 To execute on your remote database, add a --remote flag to your wrangler command.
これで完成です。npx wrangler@latest dev
を実行してローカルサーバーを起動し、以下のコマンドでPOSTリクエストを送信してください。
$ curl -X POST "http://localhost:8787/" -d '{"title": "Python実践レシピ", "description": "Pythonでプログラムを作成するときに役立つ機能とライブラリを網羅した、実践的なレシピ集です。"}' {'message': 'ok'} $ curl -X POST "http://localhost:8787/" -d '{"title": "最短距離でゼロからしっかり学ぶ Python入門 必修編", "description": "プログラミング環境の用意,基本的なプログラムの書き方に始まり,リスト,辞書,クラス,関数といった基礎的な知識からエラー処理,テストコードの書き方までを演習問題を交えながら,わかりやすく解説します。"}' {'message': 'ok'} $ curl -X POST "http://localhost:8787/" -d '{"title": "最短距離でゼロからしっかり学ぶ Python入門 実践編", "description": "「エイリアン侵略ゲーム」「データの可視化」「Webアプリケーション」という3つのプロジェクトにチャレンジします。"}' {'message': 'ok'}
以下のコマンドでGETリクエストを送信すると、上記で登録した情報を確認できます。
$ curl "http://localhost:8787/" [{"id":1,"title":"Python実践レシピ","description":"Pythonでプログラムを作成するときに役立つ機能とライブラリを網羅した、実践的なレシピ集です。"},{"id":2,"title":"最短距離でゼロからしっかり学ぶ Python入門 必修編","description":"プログラミング環境の用意,基本的なプログラムの書き方に始まり,リスト,辞書,クラス,関数といった基礎的な知識からエラー処理,テストコードの書き方までを演習問題を交えながら,わかりやすく解説します。"},{"id":3,"title":"最短距離でゼロからしっかり学ぶ Python入門 実践編","description":"「エイリアン侵略ゲーム」「データの可視化」「Webアプリケーション」という3つのプロジェクトにチャレンジします。"}]
本番環境にデプロイする場合は、次のコマンドを実行してテーブルを作成してください。This process may take some time, during which your D1 database will be unavailable to serve queries. Ok to proceed?
と聞かれたらEnterキーを押して進めてください。
$ npx wrangler d1 execute bookshelf --remote --file=./schema.sql ⛅️ wrangler 3.65.0 ------------------- 〈省略〉 ┌────────────────────────┬───────────┬──────────────┬────────────────────┐ │ Total queries executed │ Rows read │ Rows written │ Database size (MB) │ ├────────────────────────┼───────────┼──────────────┼────────────────────┤ │ 2 │ 4 │ 2 │ 0.02 │ └────────────────────────┴───────────┴──────────────┴────────────────────┘
上記コマンドの実行後、npx wrangler@latest deploy
を実行してデプロイしてください。デプロイ後、ローカル環境と同じくデータの登録、取得ができます。デプロイしたアプリケーションのURLを確認する方法は、
$ export API_URL="https://****" # デプロイしたアプリケーションのURL $ curl -X POST $API_URL -d '{"title": "Python実践レシピ", "description": "Pythonでプログラムを作成するときに役立つ機能とライブラリを網羅した、実践的なレシピ集です。"}' {'message': 'ok'} $ curl -X POST $API_URL -d '{"title": "最短距離でゼロからしっかり学ぶ Python入門 必修編", "description": "プログラミング環境の用意,基本的なプログラムの書き方に始まり,リスト,辞書,クラス,関数といった基礎的な知識からエラー処理,テストコードの書き方までを演習問題を交えながら,わかりやすく解説します。"}' {'message': 'ok'} $ curl -X POST $API_URL -d '{"title": "最短距離でゼロからしっかり学ぶ Python入門 実践編", "description": "「エイリアン侵略ゲーム」「データの可視化」「Webアプリケーション」という3つのプロジェクトにチャレンジします。"}' {'message': 'ok'} $ curl $API_URL [{"id":1,"title":"Python実践レシピ","description":"Pythonでプログラムを作成するときに役立つ機能とライブラリを網羅した、実践的なレシピ集です。"},{"id":2,"title":"最短距離でゼロからしっかり学ぶ Python入門 必修編","description":"プログラミング環境の用意,基本的なプログラムの書き方に始まり,リスト,辞書,クラス,関数といった基礎的な知識からエラー処理,テストコードの書き方までを演習問題を交えながら,わかりやすく解説します。"},{"id":3,"title":"最短距離でゼロからしっかり学ぶ Python入門 実践編","description":"「エイリアン侵略ゲーム」「データの可視化」「Webアプリケーション」という3つのプロジェクトにチャレンジします。"}]
built-in packagesを使ってみる
built-in packagesとは、Cloudflare Workersで提供されているPythonパッケージです。利用できるパッケージは以下の公式ドキュメントを参照してください。
利用するには、requirements.
通常のPython開発では、requirements.fastapi==0.
のようにバージョンを指定することができますが、Cloudflare Workersではこの書き方ができません。Cloudflare Workersでは、wrangler.
実際に動かしてみる場合は、
$ git clone https://github.com/cloudflare/python-workers-examples # すでに実行済みなら省略 $ cd python-workers-examples/03-fastapi $ npx wrangler@latest dev
その他のサンプルコード
以下公式ドキュメントにケース別のサンプルコードがあります。興味がある方は試してみてください。
Cloudflare WorkersでPythonはどうやって動いているのか
Cloudflare WorkersではWebAssemblyをサポートしているため、WebAssemblyのバイナリを生成できる言語であれば、Cloudflare Workersで動作させることができます。ところが、Pythonに関してはコードをWebAssemblyバイナリに変換しているわけではありません。
Cloudflare Workersのランタイムであるworkerdには、CPythonのWebAssembly実装であるPyodideが組み込まれています。PythonコードはPyodideが解釈することで実行されます。
なお、Pyodideについては以下の過去記事でも紹介しています。興味がある方は読んでみてください。
また、現在のCloudflare WorkersワーカーのほとんどはJavaScriptで書かれていますが、Pythonで同様の機能を持つワーカーを1から実装するのはかなりの労力がかかります。そこで、JavaScriptの外部インターフェイス、つまりFFI
Cloudflare WorkersでPythonを動かす仕組みについては、以下のCloudflareのブログ記事でも詳しく解説しています。
Cloudflare WorkersでPythonを使う上での技術的制限
Cloudflare WorkersではPythonアプリケーションはPyodideで動作するため、いくつかの技術的制限があります[1]。
利用制限がある標準ライブラリ
Cloudflare Workersでは、以下の標準ライブラリは利用制限があります。
ライブラリ名 | 制限の内容 |
---|---|
hashlib | OpenSSLに依存するハッシュアルゴリズムはデフォルトで利用不可 |
decimal | C実装 |
pydoc | 組み込みのヘルプメッセージは利用不可 |
webbrowser | オリジナルのWebブラウザモジュールは利用不可 |
なお、hashlibの制限回避方法については、本記事執筆時点では公式ドキュメントに記載がありませんでした。
importできない標準ライブラリ
以下の標準ライブラリはランタイムから削除されているため、importできません。
curses、dbm、ensurepip、fcntl、grp、idlelib、lib2to3、msvcrt、pwd、resource、syslog、termios、tkinter、turtle.
py、turtledemo、venv、winreg、winsound
また、以下標準ライブラリはランタイムに含まれていますが、削除されたtermiosに依存しているため、importできません。
- pty
- tty
importできるが利用できない標準ライブラリ
以下の標準ライブラリはimportできますが、利用できません。
- multiprocessing
- threading
- sockets
最後に
Cloudflare WorkersでPythonを使う方法、内部の仕組み、技術的制限について解説しました。オープンベータ版ということもあり、まだ発展途上ではありますが、PythonプログラマーにとってCloudflare Workersが魅力的なプラットフォームになりつつあるのではないでしょうか。
筆者が使ってみた実感としては、JavaScriptのFFIがあることでWebアプリケーションに必要な機能は揃ってはいるものの、Pythonの流儀と少し異なるために戸惑う場面がいくつかありました。たとえば、リクエストボディのJSONを取得する際に書くコードrequest.
は、期待する挙動と実際の挙動が以下のように異なっていました。
期待する挙動 | 実際の挙動 |
---|---|
辞書型が返ってきてrequest. 、request. のように書ける |
request. 、getattr(request. のように属性を呼び出す |
リクエストボディがないと空の辞書を返す | リクエストボディがないと例外pyodide. が発生する |
この違和感は、built-in packagesが本番環境で使えるようになれば、ある程度解消されるのではないかと期待しています。
また、Pyodideを組み込んだ仕組みも面白いですね。これはあくまで筆者の想像ですが、Rubyのruby.