利用 systemd 部署 golang 專案

qinhan發表於2019-09-16

 centos7 上 systemd 詳解

 簡介

- CentOS 7繼承了RHEL 7的新的特性,例如強大的systemd, 而systemd的使用也使得以往系統服務的/etc/init.d的啟動指令碼的方式就此改變, 也大幅提高了系統服務的執行效率。但服務的配置和以往也發生了極大的不同,同時變的簡單而易用了許多。

- CentOS 7的服務systemctl指令碼存放在:/usr/lib/systemd/,有系統 system 和使用者 user 之分, 即:/usr/lib/systemd/system 和 /usr/lib/systemd/user

 配置檔案

- 這裡我們先要說明一下unit的檔案位置,一般主要有三個目錄:

/lib/systemd/system
/run/systemd/system
/etc/systemd/system

- 這三個目錄的配置檔案優先順序依次從低到高,如果同一選項三個地方都配置了,優先順序高的會覆蓋優先順序低的。 系統安裝時,預設會將unit檔案放在/lib/systemd/system目錄。如果我們想要修改系統預設的配置,比如nginx.service,一般有兩種方法:

    - 在/etc/systemd/system目錄下建立nginx.service檔案,裡面寫上我們自己的配置。

    - 在/etc/systemd/system下面建立nginx.service.d目錄,在這個目錄裡面新建任何以.conf結尾的檔案,然後寫入我們自己的配置。推薦這種做法。

- /run/systemd/system這個目錄一般是程式在執行時動態建立unit檔案的目錄,一般很少修改,除非是修改程式執行時的一些引數時,即Session級別的,才在這裡做修改。

 服務配置

- 每一個服務以.service結尾,一般會分為3部分:[Unit]、[Service]和[Install],就以nginx為例吧,具體內容如下:


[Unit]

Description=nginx - high performance web server

Documentation=http://nginx.org/en/docs/

After=network.target remote-fs.target nss-lookup.target

[Service]

Type=forking

PIDFile=/usr/local/nginx/logs/nginx.pid

ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf

ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

ExecReload=/bin/kill -s HUP $MAINPID

ExecStop=/bin/kill -s QUIT $MAINPID

PrivateTmp=true

[Install]

WantedBy=multi-user.target

 配置項說明

- 下面分別解釋下著三部分的含義

 [Unit]

- Description : 服務的簡單描述

- Documentation : 服務文件

- After= : 依賴,僅當依賴的服務啟動之後再啟動自定義的服務單元

 [Service]

- Type : 啟動型別simple、forking、oneshot、notify、dbus

    - Type=simple(預設值):systemd認為該服務將立即啟動,服務程式不會fork。如果該服務要啟動其他服務,不要使用此型別啟動,除非該服務是socket啟用型

    - Type=forking:systemd認為當該服務程式fork,且父程式退出後服務啟動成功。對於常規的守護程式(daemon),除非你確定此啟動方式無法滿足需求, 使用此型別啟動即可。使用此啟動型別應同時指定PIDFile=,以便systemd能夠跟蹤服務的主程式。

    - Type=oneshot:這一選項適用於只執行一項任務、隨後立即退出的服務。可能需要同時設定 RemainAfterExit=yes 使得 systemd 在服務程式退出之後仍然認為服務處於啟用狀態。

    - Type=notify:與 Type=simple 相同,但約定服務會在就緒後向 systemd 傳送一個訊號,這一通知的實現由 libsystemd-daemon.so 提供

    - Type=dbus:若以此方式啟動,當指定的 BusName 出現在DBus系統匯流排上時,systemd認為服務就緒。

- PIDFile : pid檔案路徑

- Environment : 環境變數(可以新增多個)eg :Environment=REPO_REF=dev

- ExecStartPre :啟動前要做什麼,上文中是測試配置檔案 -t

- ExecStart:啟動

- ExecReload:過載

- ExecStop:停止

- PrivateTmp:True表示給服務分配獨立的臨時空間

 [Install]

- WantedBy:服務安裝的使用者模式,從字面上看,就是想要使用這個服務的有是誰?上文中使用的是:multi-user.target ,就是指想要使用這個服務的目錄是多使用者。

 操作示例

- 每一個.target實際上是連結到我們單位檔案的集合,當我們執行

systemctl enable nginx.service

- 就會在 /etc/systemd/system/multi-user.target.wants/ 目錄下新建一個 /usr/lib/systemd/system/nginx.service 檔案的連結。

 常用的service操作

# 自啟動
systemctl enable nginx.service

# 禁止自啟動
systemctl disable nginx.service

# 啟動服務
systemctl start nginx.service

# 停止服務
systemctl stop nginx.service

# 重啟服務
systemctl restart nginx.service

# 檢視Unit定義檔案
systemctl cat nginx.service

# 編輯Unit定義檔案
systemctl edit nginx.service

# 重新載入Unit定義檔案
systemctl reload nginx.service

# 列出已啟動的所有unit,就是已經被載入到記憶體中
systemctl list-units

# 列出系統已經安裝的所有unit,包括那些沒有被載入到記憶體中的unit
systemctl list-unit-files

# 檢視服務的日誌
journalctl -u nginx.service    # 還可以配合`-b`一起使用,只檢視自本次系統啟動以來的日誌

# 檢視所有target下的unit
systemctl list-unit-files --type=target

# 檢視預設target,即預設的執行級別。對應於舊的`runlevel`命令
systemctl get-default

# 設定預設的target
systemctl set-default multi-user.target

# 檢視某一target下的unit
systemctl list-dependencies multi-user.target

# 切換target,不屬於新target的unit都會被停止
systemctl isolate multi-user.target
systemctl poweroff    # 關機
systemctl reboot       # 重啟
systemctl rescue    # 進入rescue模式

 Systemd + Golang Demo

- 下面例子通過 Systemd 部署一個最簡單的 Golang Web Server

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
)

func main() {
    var address string
    flag.StringVar(&address, "address", "5353", "listen address")
    flag.Parse()

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, This is a test for systemd !\n")
    }) //   設定訪問路由

    log.Printf("Starting server on %s\n", address)
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", address), nil))
}

- 編譯程式碼,並將可執行檔案同步到遠端伺服器上

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o systemd-test  main.go
rsync -zP ./systemd-test root@gp-aliyun:/usr/local/bin/

- 在遠端伺服器上編寫服務配置,放在/etc/systemd/system/中

[Unit]
Description=Systemd Test
After=network.target

[Service]
User=nobody
# Execute `systemctl daemon-reload` after ExecStart= is changed.
ExecStart=/usr/local/bin/systemd-test -address "6060"
[Install]
WantedBy=multi-user.target

- 通過systemctl啟動服務

# 每一次修改ExecStart都需執行
systemctl daemon-reload
# 啟動
systemctl start systemd-test.service
# 檢視狀態
systemctl status systemd-test.service

- 狀態如下
Golang

- 可以通過curl進行測試:
Golang

相關文章