Go 語言(Golang)以其簡單、高效和易于部署的特點,成為了很多企業開發和部署服務的首選語言。無論是微服務架構,還是命令行工具,Go 的編譯方式和標準庫使得部署變得更加輕松。本文將介紹部署 Go 語言項目的幾種常見方法,以幫助開發者根據不同的需求選擇合適的部署方案。
本文以部署 Go Web 程序為例,介紹了在 CentOS7 服務器上部署 Go 語言程序的若干方法。
獨立部署
Go 語言支持跨平臺交叉編譯,也就是說我們可以在 Windows 或 Mac 平臺下編寫代碼,并且將代碼編譯成能夠在 Linux amd64 服務器上運行的程序。
對于簡單的項目,通常我們只需要將編譯后的二進制文件拷貝到服務器上,然后設置為后臺守護進程運行即可。
編譯
編譯可以通過以下命令或編寫 makefile 來操作。
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./bin/bluebell
下面假設我們將本地編譯好的 bluebell 二進制文件、配置文件和靜態文件等上傳到服務器的/data/app/bluebell
目錄下。
補充一點,如果嫌棄編譯后的二進制文件太大,可以在編譯的時候加上-ldflags "-s -w"
參數去掉符號表和調試信息,一般能減小 20% 的大小。
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o ./bin/bluebell
如果還是嫌大的話可以繼續使用 upx 工具對二進制可執行文件進行壓縮。
我們編譯好 bluebell 項目后,相關必要文件的目錄結構如下:
├── bin
│ └── bluebell
├── conf
│ └── config.yaml
├── static
│ ├── css
│ │ └── app.0afe9dae.css
│ ├── favicon.ico
│ ├── img
│ │ ├── avatar.7b0a9835.png
│ │ ├── iconfont.cdbe38a0.svg
│ │ ├── logo.da56125f.png
│ │ └── search.8e85063d.png
│ └── js
│ ├── app.9f3efa6d.js
│ ├── app.9f3efa6d.js.map
│ ├── chunk-vendors.57f9e9d6.js
│ └── chunk-vendors.57f9e9d6.js.map
└── templates└── index.html
nohup
nohup 用于在系統后臺不掛斷地運行命令,不掛斷指的是退出執行命令的終端也不會影響程序的運行。
我們可以使用 nohup 命令來運行應用程序,使其作為后臺守護進程運行。由于在主流的 Linux 發行版中都會默認安裝 nohup 命令工具,我們可以直接輸入以下命令來啟動我們的項目:
sudo nohup ./bin/bluebell conf/config.yaml > nohup_bluebell.log 2>&1 &
其中:
./bluebell conf/config.yaml
是我們應用程序的啟動命令nohup ... &
表示在后臺不掛斷的執行上述應用程序的啟動命令> nohup_bluebell.log
表示將命令的標準輸出重定向到 nohup_bluebell.log 文件2>&1
表示將標準錯誤輸出也重定向到標準輸出中,結合上一條就是把執行命令的輸出都定向到 nohup_bluebell.log 文件
上面的命令執行后會返回進程 id
[1] 6338
當然我們也可以通過以下命令查看 bluebell 相關活動進程:
ps -ef | grep bluebell
輸出:
root 6338 4048 0 08:43 pts/0 00:00:00 ./bin/bluebell conf/config.yaml
root 6376 4048 0 08:43 pts/0 00:00:00 grep --color=auto bluebell
此時就可以打開瀏覽器輸入http:// 服務器公網 ip: 端口
查看應用程序的展示效果了。
supervisor
Supervisor 是業界流行的一個通用的進程管理程序,它能將一個普通的命令行進程變為后臺守護進程,并監控該進程的運行狀態,當該進程異常退出時能將其自動重啟。
首先使用 yum 來安裝 supervisor:
如果你還沒有安裝過 EPEL,可以通過運行下面的命令來完成安裝,如果已安裝則跳過此步驟:
sudo yum install epel-release
安裝 supervisor
sudo yum install supervisor
Supervisor 的配置文件為:/etc/supervisord.conf
,Supervisor 所管理的應用的配置文件放在 /etc/supervisord.d/
目錄中,這個目錄可以在 supervisord.conf 中的include
配置。
[include]
files = /etc/supervisord.d/*.conf
啟動 supervisor 服務:
sudo supervisord -c /etc/supervisord.conf
我們在/etc/supervisord.d
目錄下創建一個名為bluebell.conf
的配置文件,具體內容如下。
[program:bluebell] ;程序名稱
user=root ;執行程序的用戶
command=/data/app/bluebell/bin/bluebell /data/app/bluebell/conf/config.yaml ;執行的命令
directory=/data/app/bluebell/ ;命令執行的目錄
stopsignal=TERM ;重啟時發送的信號
autostart=true
autorestart=true ;是否自動重啟
stdout_logfile=/var/log/bluebell-stdout.log ;標準輸出日志位置
stderr_logfile=/var/log/bluebell-stderr.log ;標準錯誤日志位置
創建好配置文件之后,重啟 supervisor 服務
sudo supervisorctl update
查看 bluebell 的運行狀態:
sudo supervisorctl status bluebell
輸出:
bluebell RUNNING pid 10918, uptime 0:05:46
最后補充一下常用的 supervisr 管理命令:
supervisorctl status
supervisorctl shutdown
supervisorctl start 程序名
supervisorctl stop 程序名
supervisorctl reload
接下來就是打開瀏覽器查看網站是否正常了。
搭配 nginx 部署
在需要靜態文件分離、需要配置多個域名及證書、需要自建負載均衡層等稍復雜的場景下,我們一般需要搭配第三方的 web 服務器(Nginx、Apache)來部署我們的程序。
正向代理與反向代理
正向代理可以簡單理解為客戶端的代理,你訪問墻外的網站用的那個屬于正向代理。
反向代理可以簡單理解為服務器的代理,通常說的 Nginx 和 Apache 就屬于反向代理。
Nginx 是一個免費的、開源的、高性能的 HTTP 和反向代理服務,主要負責負載一些訪問量比較大的站點。Nginx 可以作為一個獨立的 Web 服務,也可以用來給 Apache 或是其他的 Web 服務做反向代理。相比于 Apache,Nginx 可以處理更多的并發連接,而且每個連接的內存占用的非常小。
使用 yum 安裝 nginx
EPEL 倉庫中有 Nginx 的安裝包。如果你還沒有安裝過 EPEL,可以通過運行下面的命令來完成安裝:
sudo yum install epel-release
安裝 nginx
sudo yum install nginx
安裝完成后,執行下面的命令設置 Nginx 開機啟動:
sudo systemctl enable nginx
啟動 Nginx
sudo systemctl start nginx
查看 Nginx 運行狀態:
sudo systemctl status nginx
Nginx 配置文件
通過上面的方法安裝的 nginx,所有相關的配置文件都在 /etc/nginx/
目錄中。Nginx 的主配置文件是 /etc/nginx/nginx.conf
。
默認還有一個nginx.conf.default
的配置文件示例,可以作為參考。你可以為多個服務創建不同的配置文件(建議為每個服務(域名)創建一個單獨的配置文件),每一個獨立的 Nginx 服務配置文件都必須以 .conf
結尾,并存儲在 /etc/nginx/conf.d
目錄中。
Nginx 常用命令
補充幾個 Nginx 常用命令。
nginx -s stop
nginx -s reload
nginx -s quit
nginx -t
Nginx 反向代理部署
我們推薦使用 nginx 作為反向代理來部署我們的程序,按下面的內容修改 nginx 的配置文件。
worker_processes 1;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 80;server_name localhost;access_log /var/log/bluebell-access.log;error_log /var/log/bluebell-error.log;location / {proxy_pass http://127.0.0.1:8084;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}
}
執行下面的命令檢查配置文件語法:
nginx -t
執行下面的命令重新加載配置文件:
nginx -s reload
接下來就是打開瀏覽器查看網站是否正常了。
當然我們還可以使用 nginx 的 upstream 配置來添加多個服務器地址實現負載均衡。
worker_processes 1;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;upstream backend {server 127.0.0.1:8084;}server {listen 80;server_name localhost;access_log /var/log/bluebell-access.log;error_log /var/log/bluebell-error.log;location / {proxy_pass http://backend/;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}
}
Nginx 分離靜態文件請求
上面的配置是簡單的使用 nginx 作為反向代理處理所有的請求并轉發給我們的 Go 程序處理,其實我們還可以有選擇的將靜態文件部分的請求直接使用 nginx 處理,而將 API 接口類的動態處理請求轉發給后端的 Go 程序來處理。
下面繼續修改我們的 nginx 的配置文件來實現上述功能。
worker_processes 1;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 80;server_name bluebell;access_log /var/log/bluebell-access.log;error_log /var/log/bluebell-error.log;location ~ .*\.(gif|jpg|jpeg|png|js|css|eot|ttf|woff|svg|otf)$ {access_log off;expires 1d;root /data/app/bluebell;}location / {root /data/app/bluebell/templates;index index.html;try_files $uri $uri/ /index.html;}location /api {proxy_pass http://127.0.0.1:8084;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}
}
前后端分開部署
前后端的代碼沒必要都部署到相同的服務器上,也可以分開部署到不同的服務器上,下圖是前端服務將 API 請求轉發至后端服務的方案。
上面的部署方案中,所有瀏覽器的請求都是直接訪問前端服務,而如果是瀏覽器直接訪問后端 API 服務的部署模式下,如下圖。
此時前端和后端通常不在同一個域下,我們還需要在后端代碼中添加跨域支持。
這里使用github.com/gin-contrib/cors庫來支持跨域請求。
最簡單的允許跨域的配置是使用cors.Default()
,它默認允許所有跨域請求。
func main() {router := gin.Default()router.Use(cors.Default())router.Run()
}
此外,還可以使用cors.Config
自定義具體的跨域請求相關配置項:
package mainimport ("time""github.com/gin-contrib/cors""github.com/gin-gonic/gin"
)func main() {router := gin.Default()router.Use(cors.New(cors.Config{AllowOrigins: []string{"https://foo.com"},AllowMethods: []string{"PUT", "PATCH"},AllowHeaders: []string{"Origin"},ExposeHeaders: []string{"Content-Length"},AllowCredentials: true,AllowOriginFunc: func(origin string) bool {return origin == "https://github.com"},MaxAge: 12 * time.Hour,}))router.Run()
}
優點
- 完全自動化,減少人工操作。
- 方便的版本控制和回滾。
缺點
- 初期配置可能較為復雜。
- 需要正確設置云服務器和訪問權限。
總結
Go 語言的部署方式有很多種,每種方法適用于不同的場景和需求。以下是一些常見的部署方式總結:
- 直接部署二進制文件:適合小型項目和簡單的部署環境。
- 使用 Docker:適合跨平臺部署,能夠更好地管理依賴。
- 使用 Kubernetes:適合大規模微服務架構,具備高可用性和自動擴展能力。
- 使用云服務平臺:適合不想管理基礎設施的開發者,提供自動化管理和擴展能力。
- 使用 CI/CD 管道:適合需要自動化部署和頻繁更新的項目。
根據你的項目需求和技術棧選擇合適的部署方式,能夠有效提高開發和運維效率。