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
현재 겪고 있는 문제는 User=andrei
루트가 아닌 사용자( )로 응용 프로그램을 실행하고 있지만 응용 프로그램이 http.ListenAndServe(":80", nil)
일반적으로 루트 사용자만 수신할 수 있는 권한 있는 포트인 포트 80( )에서 수신을 시도하고 있다는 것입니다.
네가 말할 때:
터미널에서 애플리케이션을 실행하면 모든 것이 잘 작동합니다.
어쨌든, 당신은 그것을 다음과 같이 실행합니까?뿌리? 왜냐하면 나는 그것이 작동하기를 원하기 때문입니다.
다른 포트(권한이 없는 1024보다 큰 포트 번호)를 사용할 수 있는 경우 이것이 루트가 아닌 사용자로 서비스를 실행하는 가장 쉬운 솔루션이 될 것입니다.
또한 유닛 파일의 이 스니펫은 다음과 같습니다.
[Socket]
ListenStream=80
NoDelay=true
이는 실제로 서비스 단위에는 적용되지 않으며 다음에만 적용됩니다.소켓 유닛, 그래서 만들어소켓 활성화작동하려면 이러한 설정을 갖춘 별도의 장치가 필요합니다 MyApp.socket
.
그러나 소켓 활성화는 별도의 장치를 만드는 것보다 더 복잡합니다. 왜냐하면 응용 프로그램 자체가 systemd에서 수신 소켓 수신을 지원해야 하기 때문입니다. 예를 들어, C 애플리케이션은 다음을 호출합니다.sd_listend_fds()이를 달성하기 위해 libsystemd에 연결합니다. Go에는 동일한 작업을 수행하는 바인딩이 있을 수 있습니다.코어로스/go-systemd예를 들어, 거기에 일부가 있을 수 있습니다.
소켓 활성화의 장점은 포트 80과 루트가 아닌 사용자를 사용할 수 있다는 점이지만 위에서 언급한 것처럼 애플리케이션을 변경해야 합니다.