「systemd」ターゲットの単位リストを動的に生成する方法は?

「systemd」ターゲットの単位リストを動的に生成する方法は?

初心者systemdのユーザーです。この質問が「とても基本的」なので、StackOverflowエコシステムの他の場所で質問する方が良いと思われる場合はお詫び申し上げます。

私はinit約12年前に書いたいくつかの古代のサービスファイルを変換していますsystemd。そのうちのいくつかは、一連のサービスを構成する方法を見つけるためにかなり奇妙な方法を使用しました。経験豊富システムプログラマーである私は、概念証明で作業を実行するための迅速で汚いハッキングが大好きです。これらのハッキングは後でいつでも改善される可能性があります。

つまり、私が達成しようとしているのは次のとおりです。私は同じバイナリの複数のインスタンスを実行しますが、異なるパラメータを使用するオンライン仮想世界プラットフォーム(いいえ、Minecraftではありません...)をホストしています(シャーディングしたいと思います)。 。事前に起動するインスタンスの数(起動時など)を知っている場合、または少なくともどのパラメータセットを使用するかを知っている場合、またはその情報の実際のリスト(おそらく事前に生成されたもの)がある場合でも、これを簡単に実行できます。 。

実際、次のようなことが起こります。特別な「設定」ディレクトリがあります(最小はい事前に知っておいてください! )複数のサブディレクトリがあります(番号は次のとおりです)。いいえ事前に知っておいてください! )、それぞれは特定のインスタンスにちなんで命名されました。名前はい重要なのは、(つまり、連続した名前を使用すると作業を簡単にすることができないことです。これにより、いくつかのトリックを適用するのが簡単になります。さらに、サブディレクトリがいくつあるかを事前に知っていると仮定しても同じです。そうではありません!)。サブディレクトリ名が都市名(例、、、NewYorkなどChicago)であるとしますLAKansasCity

簡単に言えば、ディレクトリツリー全体を次のように考えることができます。

game-root-folder 
|
\___ bin
|     \___________ myapp (the actual game engine for each instance)
|     \___________ myapp-single-instance.sh (explained below)
|
\___ config-folder
       \__________ NewYork
       |              \______ config.ini
       |          
       \__________ Chicago
       |              \______ config.ini
       |          
       \__________ LA
       |              \______ config.ini
       |          
       \__________ KansasCity
       :              \______ config.ini

(申し訳ありませんが、私はASCIIチャートをうまく扱っていません...)

各座標はconfig.iniその都市のGPS座標のセットであると仮定します(実際にはそうではありません)。たくさんそれよりも複雑ですが、重要なのは、このファイルに人が書いたものではなく、「管理アプリケーション」で自動的に生成された項目が十分であるということです。難しい環境変数のすべての項目をエンコードします。つまり、ユニークで都市によって異なり、その都市のリリース構成にハードコードされている項目です。

実際、実際のレイアウトははるかに複雑ですが、これは私の問題を説明するのに十分です。

いついいえシェルからすべてを手動で起動するのではなく、systemd操作は簡単です。各インスタンスを起動するコマンドは次のとおりです。

# Call this script with `myapp-single-instance.sh start <city name>`
case "$1" in
    start)
        cd /full/path/to/game-root-folder/bin
        /usr/bin/screen -S $2 -d -m -l myapp \
          --config=/path/to/game-root-folder/config-folder/$2/config.ini
        ;;
    stop)
        # discussed below
        ;;
    *)
        # show usage
        exit 1
        ;;
esac
        

非構成systemdファイルには、その構成ディレクトリの内容をリストし、サブディレクトリの名前を抽出して各都市名に対して開始/停止スクリプトを実行する追加のスクリプトがあります。たとえば、次のようになります。

cd /full/path/to/game-root-folder/bin
for CITY_NAME in `ls /path/to/game-root-folder/config-folder`
do
    myapp-single-instance.sh start $CITY_NAME
done

参考までに、止めるこのような場合、人々は次のようにすることができます。

/usr/bin/screen -S $CITY_NAME -X eval 'stuff "quit"\015'

(インスタンスを終了するためのコンソールコマンドであると仮定quit)、または何らかの理由で上記の方法が機能しない場合(インスタンスがコマンドを受け入れず、無限ループにある場合):

/usr/bin/screen -X -S $CITY_NAME kill

この場合はkillそれ自体に対するコマンドでありscreen、それ自体とその中にあるすべてをエレガントに終了します。SIGKILLもちろん、最後のオプションは1つを送信することです(現在の既存のスクリプトを介しても行われます)。

ご覧のとおり、誰かが追加したい場合新しいたとえば、新しい都市の場合、必要なのは新しいサブディレクトリを作成し、1行のBoston開始/停止スクリプトを使用して開始することです。必要に応じて、個々のインスタンスを手動で停止または開始できます。新しいいずれにせよ、インスタンスには手動介入(所定の位置に配置)が必要な場合があるため、config.iniインスタンスを設定するには追加のコマンドが必要です。新しいインスタンス - 各インスタンスが本質的に他のインスタンスとは独立しており、直接対話しない限り、インスタンスにシグナルを送信する必要はありません。既存の追加する場合の例新しい1(または既存のアイテムを削除)。繰り返しますが、実際には後でいくつかの管理タスクを実行するサーバーを監視する「マスター」インスタンスがありますが、この質問の目的のために今はその存在を無視します。

上記の例は、initシナリオに適用するのは簡単です。

それでは、次に何をすべきですかsystemd?まあ、2階層アプローチが使用に適しているようです。systemd ターゲット、1つから複数のインスタンスを起動する金型。これは私の無邪気な試みでした、緩やかにこの答えに基づいて(ポイント3)、他の場所にも適用されます。

; [email protected]

[Unit]
Description=Game city name %I
After=syslog.target
After=network.target
Requires=mariadb.service mysqld.service
PartOf=myapp.target

[Service]
Type=forking
User=myappuser
Group=myappgroup
WorkingDirectory=/full/path/to/game-root-folder/bin
ExecStart=myapp-single-instance.sh start "%I"
ExecStop=myapp-single-instance.sh stop "%I"
ExecStop=/bin/sleep 5
KillSignal=SIGCONT
Restart=always
RestartSec=30s
Environment=USER=myappuser HOME=/full/path/to/game-root-folder/bin
RemainAfterExit=false
SuccessExitStatus=1

[Install]
WantedBy=multi-user.target

これまでは素晴らしかったです。基本的には、既存のスクリプトsystemdを構成にラップするだけです。

しかし、今目標をどのようにすべきですか?

; myapp.target
[Unit]
Description=Launch all game instances
[email protected] [email protected] [email protected]

[Install]
WantedBy=multi-user.target

こんな、シカゴを点滅しました!見て、設定を手動で編集すると、これが起こります。

基本的に私動的これを行う方法は、私が素晴らしいコマンドを使用したのと`ls /path/to/game-root-folder/config-folder`同じです。非常にシンプルですが、非常に強力です!しかし、トピックについて私が読んだところでは、シェルコマンドの出力を対応する行にパイプすることは不可能です。Wants=...実際に唯一の行は次のとおりです。できるシェル実行コマンドは次のとおりですExec...=(明らかな理由から)。私には本当に不運があります!

他の人も同様の問題を経験しました。解決策は、実行するインスタンスを選択するためのロジックを環境変数にプッシュすることです。これにより、環境変数が「マッサージ」され、実行可能ファイル自体に転送されます。私の場合、これらのソリューションを実装する方法は少し混乱していますが、私の要件に合わないようです。実際、これらの「明白な」ユースケースは、ターゲットからサービスユニットを動的に呼び出すのが奇妙であることがわかりました。ここで、「動的」とは、「サイズが不明な単一の実行可能ファイルのサービス単位セット」を意味します。各要素は異なるパラメータ範囲を持つことができ、あらかじめ知られていませんsystemd

systemdソリューションに別のファイルが含まれている(つまり、ファイルをその中に入れて/etc/systemd/myapp.service.d/)、これらの追加の構成検索を開始したり、systemdスクリプトから呼び出すことができるすべてのインスタンスをリストした2つの例を見ました。.targetファイルに保存するか、環境変数に保存することもできます。誰かが追加するたびに追加たとえば、バックグラウンドタイマープロセスは各インスタンスのサブディレクトリを確認し、収集されたデータの各ビットを含む環境変数を返すか、それを特殊ファイルに書き込みます(ファイルがよく知られている場所で共有されると仮定します)。起動時に各インスタンスを起動する方法については、こちらをご覧ください。これらのソリューションは、利用可能なファイルを確認し、リロードを介してターゲットデバイスを呼び出す前にそのファイルをフラッシュするバックグラウンドデーモンを実行することを意味します。ただし、これらのソリューションは、Wants=..行を変更しようとするとRequire=..機能しないようです。Exec...=この方法で解決できるのはほとんどのパラメータです(いくつかの競合するガイドラインを見ましたが、一部のsystemdコードバージョンでは「動的」を使用していると言われています)。フィールドを埋める方法...)。

また、インスタンスを起動/停止/再ロードする機能を維持したいと思います。個別に、起動時にすべて起動することもできます(または強制的に再起動する前に正常に停止するなど)。

上記のすべてを考慮して、どのソリューションをお勧めしますか?

事前に感謝し、このコミュニティで絶えず素晴らしい活動を続けてください!

乾杯、

  • グウェン

答え1

もし部分サービスの一部です[単位]これにより、ターゲットは必要ありません。〜したい; systemd は、ターゲットでどのテンプレートが有効になっているかを自動的に把握します。

systemctl enable myapp@Chicago(等)は、説明に明記された内容と併用してください。

ターゲットからWants =を削除それでは…何がsystemctl enable myapp起こりますかsystemctl start myapp

関連情報