Docker コンテナでのサービスの実行#
最近、私が書いているあるコンテナのアーキテクチャをアップグレードしました。コンテナを起動する際には、frps サービスを同時に実行する必要があります。私の習慣に従って、最初は systemctl を使用して frps サービスを追加し、起動時に自動起動するように enable しようと考えました。しかし、実際に使用してみると、サービスが起動しないことがわかりました。ログを調べてみると、次のエラーメッセージが表示されました:
ERROR:systemctl: frps.service: 実行可能なパスが絶対パスではないため、無視されました: ./frps -c /frps.ini
ERROR:systemctl: Exec は絶対パスではありません: ExecStart=./frps -c /frps.ini
ERROR:systemctl: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ERROR:systemctl: /etc/systemd/system/frps.service に 1 つの問題が見つかりました
ERROR:systemctl: SystemD コマンドは定義上常に絶対パスである必要があります
ERROR:systemctl: 以前のバージョンの systemctl.py はサブシェルを使用していたため、$PATH を使用していました
ERROR:systemctl: ただし、新しいバージョンでは実際の SystemD デーモンと同様に execve を使用しているため、Docker 専用のサービススクリプトが突然失敗する可能性があります
ERROR:systemctl: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
公式ウェブサイトを少し調べてみると、次の説明が見つかりました:
これは設計上のものです。Docker は、コンテナ内の前景プロセスを実行し、それはコンテナの pid 名前空間内で PID 1 として生成されます。Docker はプロセスの分離のために設計されており、systemd、cron、syslog などの他の OS プロセスやデーモンはコンテナ内で実行されていません。代わりに、エントリーポイントまたは実行するコマンドのみが存在します。
もし systemd コマンドが含まれていたら、エントリーポイントが init を置き換えるため、多くのことがうまく動作しなくなるでしょう。Systemd はまた、cgroups を使用しており、Docker はコンテナ内で cgroups の変更を制限しているため、cgroups を変更する能力があればプロセスがコンテナの分離を抜け出す可能性があります。コンテナ内で init として systemd を実行していない限り、開始および停止コマンドを処理するデーモンはありません。
要するに、Docker はプロセスの分離を提供するだけであり、OS の仮想化ではないため、systemd を実行することはできないということです。
2 つのサービスを同時に実行したい場合、どのようにすればよいでしょうか?実は非常に簡単です:Dockerfile の CMD 内で start.sh を実行し、その後、nohup を使用して frps サービスをバックグラウンドで実行するだけです:
nohup ./frps -c /frps.ini &
python3 /main.py
frps サービスが正常に実行されます。