目次
- 画面を表示する
- 画面左のtextareaにシェルを入力する
- 画面左のRunボタンを押す
- 結果が画面右のtextareaにセットされる
- やりたかったらTweetボタンでつぶやく
実体はフロントエンドのHTMLからAPIリクエストして実行結果を受け取ってるだけです。 なので普通にcurlでPOSTリクエスト送れば画面がなくても動きます。
以下のようなリクエストを送ればコマンドラインからwebshを使用できます。
curl -X POST -d '{"code":"echo hello", "images":[]}' 'https://websh.jiro4989.com/api/shellgei'
images にbase64エンコードした画像ファイルを含めるとwebsh上の /media 配下にア ップロードしたファイルがbase64デコードされて配置されます。
シェル芸Bot のWeb移植の SGWeb というWebアプリがある。
最新のシェル芸botに追従してなかったので、試しに自分が最新のシェル芸botに追従する Webアプリ作って公開してみるか、と思ったから。 あとWebアプリを作る勉強もかねて。
アプリはすべてDockerコンテナ上で動作する。
ブラウザの画面からシェルを実行するとコンテナ上のNginxへリクエストが流れる。 Nginxはリバースプロキシし、コンテナ上のAPIサーバがリクエストを受ける。
APIサーバはホストネットワーク上のDockerAPIを使用して、 シェル芸Botコンテナを操作する。
画像ファイルなどを配置する一時ディレクトリの後始末は APIサーバからは行わず、removerコンテナが非同期に削除する。
Infrastructure as Code (Ansible) している。 ソースコードは infra リポジトリ(非公開)で管理。
監視系はローカルPCのDockerコンテナ上で動作するGrafanaとPrometheusで実施。 nimbot はSlack用のBotで、 websh用のサーバに後乗せで一緒に稼働している。
ログは一旦ローカルに書き出したファイルをFluentdが拾ってJSON形式に変換して保存。 GrafanaLokiがログを拾って、Grafanaからログを取得してログ監視をしている。
ブラウザからPOSTリクエストを受け、POSTの内容を取得し、Dockerコンテナ内でシェルを実行する。
コンテナは状態を保持しないようにする。 一度リクエストをしたあと、再度コンテナにリクエストをしても、前回実行した結果はコンテナ内に残らないようにする。 リクエストの都度、コンテナを破棄して生成するようにする。
ただしコンテナの破棄と生成はAPIサーバプロセス自体は実施しない。 コンテナの破棄と起動には時間がかかり、合計で約2秒ほどかかってしまう。 レスポンスタイム向上のため、コンテナの破棄と生成は別プロセスが引き受けるようにする。 APIサーバはコンテナの破棄のトリガーを生成するのみに留める。
コンテナの起動はインフラ側のsupervisorが引受ける。 コンテナや画像ファイルの破棄は別APIサーバとは別プロセスが引き受ける。
以上を踏まえて、Webからのリクエストを受けてレスポンスを返すまでの一連の処理フローは以下の通り。
以下のツールがインストールされている必要があります。
- Nim
- Docker
- Docker-compose
Path | Description |
---|---|
docs | READMEの画像ファイルなど |
nginx | ローカル開発用のnginxの設定 |
websh_front | フロントエンドのプログラム |
websh_server | バックエンドのAPIサーバのプログラム |
websh_remover | バックエンドの後始末を行うプログラム |
Dockerfile | アプリのDockerイメージ |
docker-compose.yml | ローカル開発でのみ使用する開発環境設定 |
DockerをAPIで操作できるようにする必要がある。 Linux環境ではSystemdでDockerを起動しているはず。 docker.serviceを以下のように修正する。
/lib/systemd/system/docker.service
# ここを
ExecStart=/usr/bin/dockerd -H fd:https:// --containerd=/run/containerd/containerd.sock
# こう修正
ExecStart=/usr/bin/dockerd -H tcp:https://0.0.0.0:2376 -H fd:https:// --containerd=/run/containerd/containerd.sock
以下のコマンドをリポジトリディレクトリ配下で実行する。
# シェル芸botのイメージを取得 (巨大なので注意)
docker pull theoldmoon0602/shellgeibot
docker-compose build
docker-compose up
サーバを起動して待機状態になったら、ブラウザで以下のページにアクセスする。
以下の5種類のブランチを使う。
Branch name | Description |
---|---|
master | 本番用 |
feature/#xx-desc | 新機能、UI改善 |
hotfix/#xx-desc | バグ修正 |
chore/#xx-desc | CIやローカル開発環境の整備など、アプリに影響しない雑多なもの |
feature, hotfix, choreのブランチ名のプレフィックスは、PR作成時のラベル自動付与にも使用している。 よって、必ずブランチ命名規則を守ること。
1つずつリリースしたいので各ブランチからmasterにPRを出す。 複数の改修をまとめてリリースしたい時だけdevelopブランチを使う。
ドキュメントの更新だけの場合はmasterブランチから直接pushする。 この時は必ずコミットログに [skip ci] を含めなければならない。 masterブランチのCIが走るとリリースドラフトが生成されてしまうため。 詳細は CI のセクションを参照。
websh_frontディレクトリ配下のREADME を参照。
websh_serverディレクトリ配下のREADME を参照。
.github ディレクトリ配下にワークフローを定義している。 ビルド、テスト、デプロイのフローは .github/workflows/main.yml に定義している。
CIのジョブフローは以下。
masterブランチでのpush、margeの場合は create-tag-draft が実行される。
create-tag-draft ではタグのドラフトを作成する。 タグのドラフトは、PRの説明から自動でセットされる。 Feature/BugFixなどの分類は、 PR時のラベルでカテゴライズされる。
PR時のラベルはブランチのプレフィックスから自動でセットされる。 ブランチ命名規則については <<開発,ブランチ運用>> を参照。
タグドラフトをpublishすると deploy が実行され、サーバ上にmasterのビルド成果物をデプロイする。
前述のCIの通り、リリースを作成すると自動でデプロイされる。
リリースの下書きはGitHub Actionsが下書きを作成する。 下書きをpublishすると、GitHub Actionが起動して、デプロイされる。 以下はデプロイのフロー。
デザインとか超手抜きですので、プルリクエストお待ちしてます。
Apache License