在 Debian 或 Ubuntu 上使用 systemd 启动简单的 Go/Golang 服务器

在 Debian 或 Ubuntu 上使用 systemd 启动简单的 Go/Golang 服务器

我想要使​​用 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- 第二个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

您遇到的问题是,您正在使用非 root 用户 ( User=andrei) 运行应用程序,但应用程序尝试侦听端口 80 ( http.ListenAndServe(":80", nil)),这是一个特权端口,通常只有 root 用户可以侦听。

当你说:

当我从终端运行应用程序时,一切正常。

无论如何,你是否将其运行为?因为那时,我希望它能正常工作。

如果您可以使用不同的端口(端口号高于 1024,这将是无特权的),那么这将是让您的服务以非 root 身份运行的最简单的解决方案。


另外,您的单元文件中的此片段:

[Socket]
ListenStream=80
NoDelay=true

这实际上不适用于服务单元,它仅适用于插座单元,所以要使套接字激活工作时,您需要一个MyApp.socket具有这些设置的单独单元。

但是套接字激活比仅仅创建一个单独的单元更复杂,因为应用程序本身需要支持从 systemd 接收侦听套接字。例如,C 应用程序会调用sd_listend_fds()并链接到 libsystemd 来实现这一点。 Go 中可能有执行相同操作的绑定,请查找coreos/go-systemd例如,那里可能有一些。

套接字激活的优点是您可以使用端口 80 和非 root 用户,但如上所述,需要更改您的应用程序。

相关内容