nohup 以外で bot を稼働させる方法


発端のツイート

先日、仮想通貨 botter 界隈内においてこちらのツイートを発端にあるワードが一時トレンド入りしそうな雰囲気になっていました。

nohup

このワードに対して、界隈ではそれぞれの立場から様々な意見が発信されていました。

下記リンクでご自身の TL からこの話題を検索 (filter:follows nohup since:2023-07-25) できます。

https://twitter.com/search?q=filter%3Afollows%20nohup%20since%3A2023-07-25&src=typed_query&f=live

nohup とは

nohupコマンドとは?
 コマンドを実行している際に、仮想端末(Terminal)の画面を閉じたりログアウトしたりすると、実行中のコマンドも終了してしまいます(コマンドをバックグラウンド実行していても終了する)。

【 nohup 】コマンド――端末を閉じてもログアウトしても処理を続ける:Linux基本コマンドTips(137) - @IT (itmedia.co.jp)

botter が使う nohup とは、つまり bot をバックグラウンドで起動させることです。

例えばターミナル (例の黒画面) から `python bot.py` というように bot のプログラムファイルを起動したとします。 しかし、そのターミナルのウィンドウを閉じてしまうと起動した bot は終了してしまいます

# nohup なし、閉じると終了してしまう
python bot.py

何ならよく分からん黒い画面で実行したのはずっと動き続けそうな気がしますが、終了してしまうのでは通常の動作です。 ターミナルを抜けるとプログラム (プロセス) に HUP シグナルというのが送られてそれによってプログラムが終了します。

そこで nohup を利用することで HUP シグナルを無視するようになり、 bot をバックグラウンドで起動させ続けることができるのです (クラウド環境の場合) 。

# nohup あり、閉じても終了しない
nohup python bot.py &

HUP シグナル を送らない命令なので nohup なんですね。

bot のロジックを実装しても PC を付けている間しか bot が起動していないようなら意味がありません (*)。 botter に入門するには、ロジックを実装し終わった次のステップとして nohup が必要になる訳です。

(*) クラウドなし PC 付けっぱなし botter も一定数いるかもしれません。

nohup 以外の方法

ここから以下は本題の件を紹介します。

しかしながら発端のツイートの発言にあるように、botter は「技術力がなくても稼げれば正解」という立ち振る舞いがかなり正しいと思います。 実際 nohup は実装した bot を最も手っ取り早く稼働させる方法だと思います。

なので以降はそこまで稼げてない本業エンジニアの botter が書くうんちくとして、暇つぶし程度に見るのが正解です。 しかしながらに以下の手法によって解決できる事柄があるのも事実です。 詳しく調べたり実践する場合は用法用量を守ってください。 (知的好奇心を優先すると沼にハマります 🫠)

tmux / screen

tmux とは、Unixライクなオペレーティングシステム用の端末多重接続ソフトウェアである。単一のウィンドウで複数の端末セッションにアクセスできる。同時に複数のコマンドラインプログラムを実行する際に有用である。tmux は制御端末からプロセスを切断することもでき、SSH セッションを SSH 接続をしていない状態でも維持することができる。

tmux - Wikipedia

簡単に言うと nohup 上位互換版です。 取っつきやすさとしても手っ取り早い方です。

nohup のデメリットとしては、稼働中の bot が分かりづらいです。 nuhup だと基本的には `ps` コマンドでプロセスを確認するかと思います。 bot を止めるには以下で確認したプロセス ID を `kill` コマンドで停止する必要があると思います。

# nohup で起動した bot のプロセス確認
$ ps -aux | grep "python bot.py"
ec2-user     15943  0.0  0.0   6816  1036 pts/5    S+   21:59   0:00 python bot.py

# プロセスを止める
$ kill 15943

tmux / screen であれば「閉じても終了しない仮想ターミナル」が作成できます。 さらにその仮想ターミナルはキーボード操作でインタラクティブに管理できます。 なので、nohup が不要になり bot 管理が視覚的にも分かりやすく。

tmux の参考画像

tmux と screen は似たような機能を持つソフトウェアで、tmux の方が新しくて高性能、screen は基本的に Linux に付属しているが tmux は別途インストールがは実用なのが主な違いかと思います (要検証)。 私は以前 bot を稼働させるには tmux を利用していました。

tmux をインストールしたら、コマンド的にはこれだけで新しい仮想ターミナル (閉じても消えない) が作成されます。 

$ tmux

あとはその仮想ターミナルで nohup なしで `python bot.py` のように bot を起動させることができます。 そして `Ctrl+B -> d` を入力して仮想ターミナルを「デタッチ」できこれで裏で動き続けます。 bot を確認・終了したいときは `tmux a` で再度「アタッチ」することができます。

tmux の botter 的なユースケースはこんな感じです。 詳しい操作方法などは検索してみてください!

systemd

systemdとはLinuxなどのUnix系のコンピューターのシステムを起動するときに様々なプログラムを動かす元のプログラムのことである。また、systemdのような元のプログラムのことをinitプロセスと呼ぶ。

systemdとは | OSSのデージーネット (designet.co.jp)

ちょっと分からなくなってきましたね。

少し言い換えると、「システムレベル」でプログラムの起動を管理する方法です。 例えるならば、nohup なしでターミナルを閉じるとプログラムが終わっていたのは「ユーザーレベル」でプログラムを起動していたからと言えます。 「ユーザー」はログイン/ログアウトがあるのに対して「システム」はそれがありませんよね? ユーザーレベルだけどログアウトしないように設定して実行するのが nohup で、システムレベルで実行するのが systemd といった感じです。 (例えなので正確性は保証しません)

systemd はユニットファイルというもを作成して、実行するプログラムや失敗時の再起動方法の指定を定義できます。 そして `systemctl` コマンドで bot のプログラムをバックグラウンドで起動できるようになります。ただ私個人として systemd は概念的には少しかじったのですが直接使ったことがないのであまり詳しく紹介は出来ません。。

tmux / screen から進化することは、インスタンスや OS を再起動しても自動起動してくれる、ログが取りやすい、サービスの状況を確認しやすいなどがあるかと思います。

systemd で起動されているサービスの参考画像

ユニットファイルは、以下のサイトを使うと簡単に作成できそうです。

ちなみにですが systemd はシステムの根幹なので、上で紹介した tmux も次に紹介する Docker も cron も実は systemd 上で動いています。 Linux システムの裏で動いているものは全て systemd によるお陰らしいです。 例えばデータベースをインストールして動かしているのであれば、それも systemd です。

Docker

Docker は覚えたらかなり便利ですが多分コスパは悪いかもしれません。 結構奥が深い技術なので本業エンジニア向きです。 私は Docker を覚えたので tmux をやめて Docker でやってます。

多分 Wikipedia を引用しても意味不明なのでかなり簡単に言うと、プログラムを「コンテナ」という形式に包んで実行できるようになります。 なので bot のプログラムファイルを「コンテナ」化することができます。 そうすると botter 目線では以下のようなメリットがあります。

  • 「コンテナエンジン」が「コンテナ」をバックグラウンドで実行してくれる (nohup 不要)

  • 実行している「コンテナ」を分かりやすく表示できる (起動中の bot が管理しやすい)

  • 「コンテナ」が落ちても自動再起動してくれる (bot が短期的なエラーで落ちても再起動される、OS を再起動しても再実行してくれる)

  • 「コンテナ」は自動環境構築されるので、例えばクラウド環境を変えたとき Linux の apt / yum install や Python の pip install をし直さなくてよい。

  • 「コンテナ」のログを管理してくれる (bot のログが分かりやすい)

Docker は覚えることこそが多いですが、上記のような botter をしていると割と起こりえる問題に対して対応することができます。

もし使ってみたい場合は、まずは Docker Desktop をインストールしましょう。 Docker Desktop は普通に PC にインストールするものなので勿論 PC を落としたらコンテナは終了しますが、作ったコンテナは簡単にクラウドにデプロイすることができます。

あとは botter でも利用者が多そうな AWS の Cloud9 環境を持っている方であれば、既に Cloud9 環境に Docker がインストールされているので試すことができます。

取り敢えず最も簡単な例でコンテナをバックグラウンド起動させてみます。  ここでは手間を省く為に「Ubuntu で毎秒 UTC 時刻を表示する」だけのコマンドをコンテナにします。 この例は「コンテナがバックグラウンドで起動できてるよ」ということを示しています。 プログラム的には全く bot と呼べるものではないですが、bot のプログラムファイルをコンテナに入れてそれを実行する形にすればそれが bot のコンテナになります。

# コンテナを実行
$ docker run --rm -d ubuntu sh -c 'while true; do date; sleep 1; done'

# 起動中コンテナを確認
$ docker ps
CONTAINER ID   IMAGE     COMMAND                   CREATED         STATUS         PORTS     NAMES
b5dbbd977dda   ubuntu    "sh -c 'while true; …"   4 seconds ago   Up 2 seconds             nervous_lamarr

# ログを表示
$ docker logs nervous_lamarr
Thu Jul 27 15:07:36 UTC 2023
Thu Jul 27 15:07:37 UTC 2023
Thu Jul 27 15:07:38 UTC 2023
Thu Jul 27 15:07:39 UTC 2023

# コンテナを削除
$  docker rm -f nervous_lamarr

最も簡単なユースケースはこんな感じです。 docker コマンドオプションの説明は省きます。 さらに実際にはこのコマンドだけではなく Dockerfile という環境構築を定義するファイルを書く必要があります。

気軽に Docker に入門しようとすると docker コマンドオプションDockerfile で十中八九することになると思います。 入門書で勉強が必要なレベルだと思います。 私が最初に読んだ本を参考に貼っておきます。

docker コマンドオプションと Dockerfile から基礎を覚えたあとにも、まだコンテナを実行させるインフラを考える必要があります。 自前で AWS EC2 でやるのか(手っ取り早い)、AWS ECS に任せるのか (そこそこ難関)、Kubernets などに任せるのか(最難関) … など。 いばらの道ですね。

私はこのインフラの選定を自動デプロイの観点から Zenn スクラップにまとめている最中なので興味がある方は参考にしてみてください。

最後に、もし Kubernets (最難関) にデプロイできればこんなダッシュボードを使ってコンテナ (bot) を管理できます。 超カッコよくないですか? (エンジニアマインド)

* botter はカッコいいより稼ぐことを重視してください

cron / クラウド関数

N 分足 bot に最も適した方法です。

cron は簡単に言うとプログラムを定期実行してくれるものです (スケジューラー)。 なので nohup が不要になります。

cron は `crontab` コマンドでスケジュール設定を行い、以下のような構文を設定をすることで bot のプログラムをスケジュール起動することができます。

# 例 5 分間隔のスケジュール

*/5 * * * * /usr/bin/python3 /home/ec2-user/bot.py

ただし cron を直接使うのではなく、クラウド関数として使うことをおすすめします。 クラウド関数は cron のクラウド版みたいなもので AWS だと Lamda というサービス (と CloudWatch Events) です。 cron コマンドでやるよりクラウド関数でやる方がスケジュールを cron 構文ではなく Web 画面上から操作して設定出来たりするので簡単で分かりやすいと思います。

そしてこの方法はこれまで紹介したものとは、そもそも bot の起動方式が異なります

ここまで紹介した bot の例 (Python)

def main():
    while True:
        ohlc = get_ohlc()
        cond = judge_cond(ohlc)
        if cond:
            send_order()

        time.sleep(60.0)

クラウド関数型 bot の例 (AWS Lamba + Python)

def lambda_handler(event, context):
    ohlc = get_ohlc()
    cond = judge_cond(ohlc)
    if cond:
        send_order()

上の例は基本形が while True の無限ループで実装しており、time.sleep で一定間隔にて注文アルゴリズムを執行します。 下のクラウド関数の例は、1 度のみの注文アルゴリズムを実装しています。

つまり上の例はプログラムが常時稼働してその内部で一定間隔で注文アルゴリズムが執行されるのに対し、クラウド関数型はスケジューラーが一定間隔でプログラムを起動して注文アルゴリズムが執行されそれが終わればプログラムも終了します。 これが起動方式が異なると書いた理由です。

クラウド関数なら、スケジューラーとプログラムはクラウドサービス側に管理してくれるのが一番のメリットです。 AWS EC2 インスタンスのようなものも要りません。 他のメリットとしては、スケジューラーが定期起動するので一度 bot が落ちても次のサイクルで起動してくれるし、常駐型と違ってメモリリークの危険性も少ないです。 あと bot のログもクラウドサービス側に保管されるので監視しやすいです。 さらに料金も安い。

最大のデメリットとしては、スケジューラーと呼んでいるものは cron と呼ばれるソフトウェアがベースなので基本的には 1 分以上の間隔でしかクラウド関数のプログラムを実行できません。 なので所謂高頻度 bot と呼ばれ WebSocket を利用するマーケットメイクやアビトラ、ノードを建てる必要がある DEX bot などをクラウド関数で実行させるのは難しいと言えます。 その他のデメリットといえば、クラウド関数独自のお作法 (プログラムの書き方) が少しあるぐらいでしょうか。

なので 1 分間隔以上で駆動するタイプの bot を稼働させるには最も優れた手法であると言えます。

私は主に高頻度系を好むのでクラウド関数はあまり使いませんが、逆に bot ではなくて一定間隔で価格や FR などを REST API から取得してデータベースに格納するのにたまに使ったりしています。 bot では WebSocket を好んで使うのですが、リアルタイムじゃなくていい情報であれはクラウド関数が圧倒的に料金的は安いです。

まとめ

N 分足タイプの bot のみ最適解
クラウド関数

その他タイプ bot は …

手っ取り早さ
nohup > tmux / screen >> systemd >> Docker

便利さ (逆にしただけ)
nohup < tmux / screen << systemd << Docker

本質
これらの方法を勉強するより早く稼ぐ >> 技術を勉強する


bot を稼働させる他の手法があれば Twitter でリプか引用で教えて頂けると助かります! またこの note 参考になった or 面白かったと思った方は note をスキ or Twitter フォローして貰えると嬉しいです 🥰

最後に私は Python 向けのトレーディングライブラリ pybotters を開発していますので気になる方は是非ご利用ください!


この記事が気に入ったらサポートをしてみませんか?