Upgrade to Pro — share decks privately, control downloads, hide ads and more …

プログラミング&実行できるWEBアプリを手作り

 プログラミング&実行できるWEBアプリを手作り

PyCon Kyushu 2024 KAGOSHIMA
https://kyushu.pycon.jp/2024/?param=TimeTable

uutan1108

May 23, 2024
Tweet

More Decks by uutan1108

Other Decks in Programming

Transcript

  1. #PyConK #PyConK_A 自己紹介 • うーたん ◦ X:@uutan1108 • 株式会社ゆめみ ◦

    新卒2年目 ◦ サーバーサイドエンジニア • 趣味 ◦ アニメを観ること • お仕事 ◦ サーバーサイド Kotlin 3
  2. #PyConK #PyConK_A 目標 14 Python でバックエンドを書いて Ruby, Rust のコードの 実行結果をフロントエンドで表示する

    ※ Ruby, Rust なのは動的型付けと静的型付けの両方動くように作りたかったため
  3. #PyConK #PyConK_A 試作品1号 1. FastAPI でフロントエンドからコードを受け取る 2. 受け取ったコードをファイルに書き込む 3. FastAPI

    から ファイルを実行する Shell を実行 4. Ruby, Rust がファイルを実行する 5. Shell の実行結果をフロントエンドに返す 23 ※ FastAPI は Python の Web フレームワーク
  4. #PyConK #PyConK_A Python から Shell を実行する # dateコマンドを実行して文字列として結果を得る import subprocess

    from subprocess import PIPE proc = subprocess.run("ruby main.rb", shell=True, stdout=PIPE, stderr=PIPE, text=True) date = proc.stdout print(data) # Hello World! 29
  5. #PyConK #PyConK_A Rust も動作した 33 $ rustc main.rs && ./main

    < input.txt Python から実行したコマンド
  6. #PyConK #PyConK_A Docker Compose とは Docker Compose によって、複数の コンテナを1度に操作できるように なる。

    あらかじめ compose.yaml 上に複数 の Docker コンテナを起動させる定 義をする。 60 【入門】Docker Composeとは?インストールと使い方 https://www.kagoya.jp/howto/cloud/container/dockercompose/
  7. #PyConK #PyConK_A 試作品2号 1. FastAPI でフロントエンドからコードを受け取る 2. 受け取ったコードをファイルに書き込む 3. FastAPI

    から ファイルを実行する Shell を実行 4. Ruby, Rust がファイルを実行する 5. Shell の実行結果をフロントエンドに返す 61
  8. #PyConK #PyConK_A 68 services: web: build: ./server container_name: playground-web volumes:

    - ./server/app:/app - /var/run/docker.sock:/var/run/docker.sock ports: - 80:8000 ruby: build: ./docker/ruby container_name: playground-ruby volumes: - ./server/app/share:/user/share tty: true compose.yaml
  9. #PyConK #PyConK_A 69 services: web: build: ./server container_name: playground-web volumes:

    - ./server/app:/app - /var/run/docker.sock:/var/run/docker.sock ports: - 80:8000 ruby: build: ./docker/ruby container_name: playground-ruby volumes: - ./server/app/share:/user/share tty: true compose.yaml コンテナ間でボリュームを 共有している
  10. #PyConK #PyConK_A Docker outside of Docker とは[図解] 76 Docker ソケットをホスト

    OS とコンテナで 共有することでホスト OS を介して命令可能
  11. #PyConK #PyConK_A Docker ソケットを共有しているコンテナ version: "3" services: web: build: ./server

    volumes: - ./server/app:/app - /var/run/docker.sock:/var/run/docker.sock ports: - 80:8000 77 compose.yaml
  12. #PyConK #PyConK_A Docker ソケットを共有しているコンテナ version: "3" services: web: build: ./server

    volumes: - ./server/app:/app - /var/run/docker.sock:/var/run/docker.sock ports: - 80:8000 78 compose.yaml volumes に Docker ソケットを 共有していることを書く
  13. #PyConK #PyConK_A 別コンテナに Selenium を分ける • Python のコンテナから Selenium を切り出して

    テストすることができる • コンテナを分けることで コンテナの起動の時間を 短縮 80 自動テストの実行環境を Dockerでお気軽引っ越し https://techblog.zozo.com/entry/testauto_env_rebuild
  14. #PyConK #PyConK_A Docker SDK for Python Docker Engine API用のPythonライブラリです。コンテナの 実行、コンテナの管理、Swarmsの管理など、dockerコマン

    ドでできることは何でもPythonアプリの中でできるように なります。 A Python library for the Docker Engine API. It lets you do anything the docker command does, but from within Python apps – run containers, manage containers, manage Swarms, etc. 93 Docker SDK for Python https://docker-py.readthedocs.io/en/stable/
  15. #PyConK #PyConK_A 97 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 Python アプリのコード
  16. #PyConK #PyConK_A 98 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 インポート
  17. #PyConK #PyConK_A 99 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 クライアントをインスタンス化 DockerソケットをホストOSと 共有しているので他のコンテナを操作可能
  18. #PyConK #PyConK_A 100 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 コンテナ名を指定してコンテナを取得 フロントエンドからの入力で動的に language 変数が変化
  19. #PyConK #PyConK_A 103 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 language 変数を元に実行する コマンドを変化させる
  20. #PyConK #PyConK_A 104 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 指定されたコンテナに対して コマンドを実行
  21. #PyConK #PyConK_A 105 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 コマンドの実行結果を取得
  22. #PyConK #PyConK_A 106 import docker def run_code(code, language): client =

    docker.from_env() result = client.containers.get(f"playground-{language}").exec_run(cmd=get_cmd(language)) output = result.output.decode('utf-8') exit_code = result.exit_code return { "result": output, "exit_code": exit_code } def get_cmd(language): if language == "ruby": return ["sh", "-c", "ruby main.rb"] elif language == "rust": return ["sh", "-c", "rustc main.rs && ./main"] ※ Docker SDK for Python に関係がないコードは省略 フロントエンドに実行結果と Exit コードを返す