For busy person(忙しい君に)
この記事のスライド by Manus.ai↓
https://manus.im/share/file/9163c190-86d5-4eec-949d-c7f1e4d0a35c
はじめに
こんなこと、思ったこと無い?
Tkinterでデスクトップアプリ、作ってもみんなに確認してもらえん。
一般的に、デスクトップアプリの確認というのは、Webアプリの確認よりも面倒です。
Tkinterとなると、pyinstallerを使って実行ファイルにして、それをdriveにあげて共有して、ダウンロードしてもらって警告が出て...といった感じでしょうか?
対して、WebアプリはSlackにリンクを貼ればいいだけです。
イージーです。
そこで
こんなこと、思ったこと無い?
Tkinterをwebページとしてブラウザから見られないのか!!?
>> できるヨ!
筆者のあーだこーだ
今回の記事を書くに当たり、以下のFreeCodeCampの記事を参考にしました。
https://www.freecodecamp.org/news/run-python-gui-in-github-codespaces/
筆者もTkitnerアプリをブラウザで確認するのは初なので、至らぬ点があるかもしれません。
ご了承ください。
また、Tkinterに限らず、「デスクトップで動くGUIアプリをブラウザから見たいね」という話です。
ToolBox(道具箱)
今回使うモノ:
- なんかゲーム
- GitHub Codespace
Problem(問題提起)
GitHub Codespacesは、開発者がどこからでもコードを記述、実行、デバッグできるクラウドベースの開発環境を提供します。便利!
しかし、この強力なツールには、PythonのGUI(ボタンをポチポチするやつのこと)アプリケーションを直接実行できないという一つの大きな制約があります。
Codespacesが「ヘッドレス環境」で動作するため、物理的なディスプレイが存在しないためです。
これにより、Tkinter、PyQt、PygameといったGUIライブラリを使用するアプリケーションは、画面を表示できずにエラーとなってしまいます。😱😱😱
この記事では、Webブラウザ経由でのGUIアプリの公開手法を、Xvfb、VNCプロトコル、noVNCといった主要技術がどのように連携して機能するのかを踏まえて紹介したいと思います。
GitHub codespaceとGUIアプリの不整合
GitHub codespace(以下、codespace)のようなクラウド開発環境は、通常、サーバ上で動作します。
これらのサーバはコスト効率とスケーラビリティのために、物理的なモニターやキーボードなどの入力デバイスを持たない「ヘッドレス」構成で運用されます。
PythonのGUIアプリケーションが起動されると、OSに対してウィンドウの作成を表示をリクエストしますが、ヘッドレス環境ではこのリクエストに応える物理的なディスプレイがありません。よって、エラーが発生するのです。
この根本的な問題を解決するためには、GUIアプリケーションが画面を描画できる仮想的な環境を提供し、その仮想画面の内容をユーザのWebブラウザにストリーミングする仕組みが必要となります。
次のセクションでは、この仕組みを構成する主要な技術要素について掘り下げます。
技術的な仕組み:Xvfb、VNC、noVNCの連携
GitHub CodespacesでPython GUIアプリケーションをWebページとして公開する技術は、主に以下の3つのコンポーネントが連携することで実現されます。
1. Xvfb (X virtual framebuffer) による仮想ディスプレイの提供
GUIアプリケーションが動作するためには、画面を描画するためのディスプレイが必要です。しかし、GitHub Codespacesのようなクラウド環境には物理的なディスプレイがありません。ここで登場するのが Xvfb (X virtual framebuffer) です。Xvfbは、X Window Systemのサーバーの一種で、物理的なディスプレイハードウェアなしに、メモリ上に仮想的なディスプレイ(フレームバッファ)を作成します。GUIアプリケーションは、この仮想ディスプレイをあたかも実際のディスプレイであるかのように認識し、描画処理を行います。
FreeCodeCampの記事で示されているstart-gui.shスクリプトでは、以下のコマンドでXvfbを起動しています。
Xvfb :1 -screen 0 1024x768x24 &
export DISPLAY=:1
-
Xvfb :1 -screen 0 1024x768x24 &
これは、ディスプレイ番号:1として、解像度1024x768ピクセル、24ビットカラーの仮想ディスプレイを起動するコマンドです。&を付けることでバックグラウンドで実行されます。 -
export DISPLAY=:1
この環境変数を設定することで、以降に起動されるすべてのXクライアント(GUIアプリケーション)は、物理ディスプレイではなく、この仮想ディスプレイ:1に対して描画を行うようになります。
これにより、PythonのTkinterやPygameなどのGUIアプリケーションは、物理的なディスプレイがなくても、仮想的な画面上にウィンドウや要素を描画できるようになります。
2.VNC (Virtual Network Computing) プロトコルと x11vnc
Xvfbによって仮想ディスプレイが作成されても、その画面はサーバーのメモリ上に存在するだけで、ユーザーがブラウザから直接見ることはできません。そこで、この仮想ディスプレイの内容をネットワーク経由でユーザーに送信するために、VNC (Virtual Network Computing) プロトコルと、その実装である x11vnc が利用されます。
VNCは、リモートコンピュータのグラフィカルデスクトップ環境をネットワーク経由で共有するためのプロトコルです。VNCサーバーはリモートの画面イメージをキャプチャし、それをVNCクライアントに送信します。クライアントは受信した画面イメージを表示し、クライアントからのマウスやキーボードの操作をサーバーに送り返すことで、リモート操作を実現します。
x11vncは、既存のXサーバー(この場合はXvfbが提供する仮想ディスプレイ)の内容をVNCプロトコルで共有するためのツールです。スクリプトでは、以下のコマンドでx11vncを起動しています。
x11vnc -display :1 -nopw -forever -shared -rfbport 5900 &
-
x11vnc -display :1
Xvfbが作成した仮想ディスプレイ:1の内容を共有対象とします。 -
-nopw
接続時にパスワードを要求しない設定です。これはCodespacesのような一時的な環境で手軽に利用するための設定ですが、セキュリティ上の理由から、インターネットに直接公開する場合には推奨されません。 -
-forever
VNCクライアントが切断されても、VNCサーバーを停止せずに動作し続けます。 -
-shared
複数のVNCクライアントからの同時接続を許可します。 -
-rfbport 5900
VNCサーバーがポート5900で接続を待ち受けます。RFB (Remote FrameBuffer) はVNCプロトコルの基盤となるプロトコルです。
これにより、Xvfbが描画した仮想画面の内容が、VNCプロトコルを通じてポート5900で利用可能になります。
3. noVNC と websockify によるWebブラウザからのアクセス
VNCプロトコルは通常、専用のVNCクライアントソフトウェアを必要としますが、ユーザーはWebブラウザから直接GUIアプリケーションにアクセスしたいと考えています。このギャップを埋めるのがnoVNCとwebsockifyです。
-
websockify
これは、VNCプロトコルのトラフィックをWebブラウザが理解できるWebSocketプロトコルに変換するプロキシ(ブリッジ)ツールです。WebブラウザはVNCプロトコルを直接扱うことはできませんが、WebSocketはWeb標準技術であるため、ブラウザとの間でリアルタイムの双方向通信が可能です。スクリプトでは、以下のコマンドでwebsockifyを起動しています。-
--web=/usr/share/novnc
noVNCのWebクライアントファイル(HTML、JavaScript、CSSなど)が配置されているディレクトリを指定します。websockifyはこのディレクトリのファイルをWebサーバーとして提供します。 -
6080
websockifyがWebブラウザからのWebSocket接続を待ち受けるポート番号です。GitHub Codespacesでは、このポートを「公開 (Public)」に設定することで、インターネット経由でアクセスできるようになります。 -
localhost:5900
websockifyがVNCプロトコルに変換したデータを転送する先のVNCサーバー(x11vnc)のアドレスとポートです。
-
-
noVNC
これは、HTML5とJavaScriptで完全に実装されたVNCクライアントです。websockifyによってWebSocketに変換されたVNCストリームをWebブラウザ内で受信し、HTML5のCanvas要素などを使って仮想ディスプレイの内容をレンダリングします。ユーザーは、Webブラウザを開き、Codespacesが提供する公開URLにアクセスするだけで、Codespaces上で動作しているPython GUIアプリケーションの画面をリアルタイムで確認し、マウスやキーボードで操作できるようになります。
セキュリティに関する重要な考慮事項
ポート5900(生のVNCプロトコル)を直接公開してはならない
この設定ではパスワード保護がなく、トラフィックも暗号化されていないため、悪意のあるユーザーが直接接続してCodespaces環境を操作できてしまうリスクがあります。
代わりに、ポート6080(noVNC)のみを公開するべきです。
noVNCはWebSocketとHTTPS上で動作するため、GitHub Codespacesの安全な接続を通じてトラフィックが暗号化され、より安全にGUIにアクセスできます。
Exampel(例)
以下に、Tkinterで作成したヘビゲームの例を置きます。
開いて。「CONNECT」をクリックしたら接続されるはずです。
最後に
以上のような技術要素が連携することで、GitHub Codespacesというヘッドレスなクラウド環境においても、Python GUIアプリケーションをWebブラウザ上でインタラクティブに利用できる環境が構築されます。GUIアプリケーションはXvfbの仮想ディスプレイに描画し、その内容はx11vncによってVNCストリームとして提供され、websockifyがそれをWebSocketに変換し、最終的にnoVNCがWebブラウザ上でレンダリングするという流れです。これにより、複雑なローカルセットアップなしに、GUIアプリケーションの開発、テスト、デモンストレーションが容易になります。
最後まで読んでくれてありがとう!
余談
別にFlatで作ればいいじゃんとか言わないでね。
