systemdを使って次のGolangコードを実行したいと思います。
...
func main() {
// main routes
http.HandleFunc("/", hello)
log.Fatalln(http.ListenAndServe(":80", nil))
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello")
}
このコードが使用されますgo build
生成されたバイナリ名: MyApp
パス:/home/andrei/MyApp/MyApp
- 2番目のファイルMyApp
はバイナリファイルです。
/lib/systemd/system
その中に内容の入ったファイルを入れました。MyApp.service
[Unit]
Description=MyApp service
After=network.target
[Socket]
ListenStream=80
NoDelay=true
[Service]
Type=simple
Restart=on-failure
RestartSec=3
User=andrei
Group=andrei
WorkingDirectory=/home/andrei/MyApp
ExecStart=/home/andrei/MyApp/MyApp
[Install]
WantedBy=multi-user.target
Ubuntuは次のコマンドを実行します(Debianではsudoを使用)。
sistemctl start MyApp.service
sistemctl status MyApp.service
私は出力を取得します:
● MyApp.service - MyApp service
Loaded: loaded (/lib/systemd/system/MyApp.service; disabled; vendor preset: enabled)
Active: activating (auto-restart) (Result: exit-code) since Wed 2018-11-14 11:30:45 UTC; 1s ago
Process: 14883 ExecStart=/home/andrei/MyApp/MyApp (code=exited, status=1/FAILURE)
Main PID: 14883 (code=exited, status=1/FAILURE)
Nov 14 11:30:45 andrei systemd[1]: MyApp.service: Main process exited, code=exited, status=1/FAILURE
Nov 14 11:30:45 andrei systemd[1]: MyApp.service: Failed with result 'exit-code'.
NOTE:
端末でアプリケーションを実行すると、すべてがうまく機能します。
systemdを使用してアプリケーションを起動するには?
Update:
次の操作で動作します。
sudo setcap CAP_NET_BIND_SERVICE=+eip /home/andrei/MyApp/MyApp
より良いユニットファイルが役に立ちます。動作させる必要はありません。
[Unit]
Description=MyApp service
After=network.target
[Service]
Type=simple
Restart=always
User=andrei
Group=andrei
WorkingDirectory=/home/andrei/MyApp
ExecStart=/home/andrei/MyApp/MyApp
# make sure log directory exists and owned by syslog
PermissionsStartOnly=true
ExecStartPre=/bin/mkdir -p /var/log/sleepservice
ExecStartPre=/bin/chown syslog:adm /var/log/sleepservice
ExecStartPre=/bin/chmod 755 /var/log/sleepservice
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=sleepservice
[Install]
WantedBy=multi-user.target
それでは、次のように動作させます。
sudo systemctl daemon-reload
sudo systemctl start MyApp.service
sudo systemctl enable MyApp.service # app will start on OS restart
sudo journalctl -f -u MyApp.service # provide information about the app
答え1
現在遭遇している問題は、User=andrei
rootではなくユーザー()でアプリケーションを実行していますが、アプリケーションが通常roothttp.ListenAndServe(":80", nil)
ユーザーだけをリッスンできる特権ポートであるポート80()でリッスンしようとしていることです。
あなたが言うとき:
端末でアプリケーションを実行すると、すべてがうまく機能します。
とにかく、あなたはそれを次のように実行しますか?根?なぜなら、それがうまくいきたいからです。
別のポート(許可なしで1024より大きいポート番号)が利用可能な場合、これはroot以外のユーザーとしてサービスを実行する最も簡単なソリューションです。
また、ユニットファイルのこのスニペットは次のとおりです。
[Socket]
ListenStream=80
NoDelay=true
これは実際にはサービスユニットには適用されず、次にのみ適用されます。ソケットユニットだから、ソケットの有効化機能するには、これらの設定を備えた別々のデバイスが必要ですMyApp.socket
。
しかし、ソケットの起動は、別々のデバイスを作成するよりも複雑です。なぜなら、アプリケーション自体がsystemdで受信ソケット受信をサポートする必要があるからです。たとえば、C アプリケーションは次を呼び出します。sd_listend_fds()これを達成するためにlibsystemdに接続します。 Goには同じことを行うバインディングがあるかもしれません。コアロス/go-systemdたとえば、そこにいくつかあるかもしれません。
ソケットを有効にする利点は、ポート80とroot以外のユーザーを使用できることですが、上記のようにアプリケーションを変更する必要があります。