部署Go语言项目的 N 种方法

本文以部署 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 项目后,相关必要文件的目录结构如下:

1├── bin 2│   └── bluebell 3├── conf 4│   └── config.yaml 5├── static 6│   ├── css 7│   │   └── app.0afe9dae.css 8│   ├── favicon.ico 9│   ├── img 10│   │   ├── avatar.7b0a9835.png 11│   │   ├── iconfont.cdbe38a0.svg 12│   │   ├── logo.da56125f.png 13│   │   └── search.8e85063d.png 14│   └── js 15│   ├── app.9f3efa6d.js 16│   ├── app.9f3efa6d.js.map 17│   ├── chunk-vendors.57f9e9d6.js 18│   └── chunk-vendors.57f9e9d6.js.map 19└── templates 20 └── 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 

输出:

1root 6338 4048 0 08:43 pts/0 00:00:00 ./bin/bluebell conf/config.yaml 2root 6376 4048 0 08:43 pts/0 00:00:00 grep --color=auto bluebell

此时就可以打开浏览器输入http://服务器公网ip:端口查看应用程序的展示效果了。

bluebell效果

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配置。

1[include] 2files = /etc/supervisord.d/*.conf

启动supervisor服务:

sudo supervisord -c /etc/supervisord.conf 

我们在/etc/supervisord.d目录下创建一个名为bluebell.conf的配置文件,具体内容如下。

1[program:bluebell] ;程序名称 2user=root ;执行程序的用户 3command=/data/app/bluebell/bin/bluebell /data/app/bluebell/conf/config.yaml ;执行的命令 4directory=/data/app/bluebell/ ;命令执行的目录 5stopsignal=TERM ;重启时发送的信号 6autostart=true 7autorestart=true ;是否自动重启 8stdout_logfile=/var/log/bluebell-stdout.log ;标准输出日志位置 9stderr_logfile=/var/log/bluebell-stderr.log ;标准错误日志位置

创建好配置文件之后,重启supervisor服务

sudo supervisorctl update # 更新配置文件并重启相关的程序 

查看bluebell的运行状态:

sudo supervisorctl status bluebell 

输出:

bluebell                         RUNNING   pid 10918, uptime 0:05:46 

最后补充一下常用的supervisr管理命令:

1supervisorctl status # 查看所有任务状态 2supervisorctl shutdown # 关闭所有任务 3supervisorctl start 程序名 # 启动任务 4supervisorctl stop 程序名 # 关闭任务 5supervisorctl reload # 重启supervisor

接下来就是打开浏览器查看网站是否正常了。

搭配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 常用命令。

1nginx -s stop # 停止 Nginx 服务 2nginx -s reload # 重新加载配置文件 3nginx -s quit # 平滑停止 Nginx 服务 4nginx -t # 测试配置文件是否正确

Nginx反向代理部署

我们推荐使用 nginx 作为反向代理来部署我们的程序,按下面的内容修改 nginx 的配置文件。

1worker_processes 1; 2 3events { 4 worker_connections 1024; 5} 6 7http { 8 include mime.types; 9 default_type application/octet-stream; 10 11 sendfile on; 12 keepalive_timeout 65; 13 14 server { 15 listen 80; 16 server_name localhost; 17 18 access_log /var/log/bluebell-access.log; 19 error_log /var/log/bluebell-error.log; 20 21 location / { 22 proxy_pass http://127.0.0.1:8084; 23 proxy_redirect off; 24 proxy_set_header Host $host; 25 proxy_set_header X-Real-IP $remote_addr; 26 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 27 } 28 } 29}

执行下面的命令检查配置文件语法:

nginx -t 

执行下面的命令重新加载配置文件:

nginx -s reload 

接下来就是打开浏览器查看网站是否正常了。

当然我们还可以使用 nginx 的 upstream 配置来添加多个服务器地址实现负载均衡。

1worker_processes 1; 2 3events { 4 worker_connections 1024; 5} 6 7http { 8 include mime.types; 9 default_type application/octet-stream; 10 11 sendfile on; 12 keepalive_timeout 65; 13 14 upstream backend { 15 server 127.0.0.1:8084; 16 # 这里需要填真实可用的地址,默认轮询 17 #server backend1.example.com; 18 #server backend2.example.com; 19 } 20 21 server { 22 listen 80; 23 server_name localhost; 24 25 access_log /var/log/bluebell-access.log; 26 error_log /var/log/bluebell-error.log; 27 28 location / { 29 proxy_pass http://backend/; 30 proxy_redirect off; 31 proxy_set_header Host $host; 32 proxy_set_header X-Real-IP $remote_addr; 33 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 34 } 35 } 36}

Nginx分离静态文件请求

上面的配置是简单的使用 nginx 作为反向代理处理所有的请求并转发给我们的 Go 程序处理,其实我们还可以有选择的将静态文件部分的请求直接使用 nginx 处理,而将 API 接口类的动态处理请求转发给后端的 Go 程序来处理。

分离静态文件请求图示

下面继续修改我们的 nginx 的配置文件来实现上述功能。

1worker_processes 1; 2 3events { 4 worker_connections 1024; 5} 6 7http { 8 include mime.types; 9 default_type application/octet-stream; 10 11 sendfile on; 12 keepalive_timeout 65; 13 14 server { 15 listen 80; 16 server_name bluebell; 17 18 access_log /var/log/bluebell-access.log; 19 error_log /var/log/bluebell-error.log; 20 21 # 静态文件请求 22 location ~ .*\.(gif|jpg|jpeg|png|js|css|eot|ttf|woff|svg|otf)$ { 23 access_log off; 24 expires 1d; 25 root /data/app/bluebell; 26 } 27 28 # index.html页面请求 29 # 因为是单页面应用这里使用 try_files 处理一下,避免刷新页面时出现404的问题 30 location / { 31 root /data/app/bluebell/templates; 32 index index.html; 33 try_files $uri $uri/ /index.html; 34 } 35 36 # API请求 37 location /api { 38 proxy_pass http://127.0.0.1:8084; 39 proxy_redirect off; 40 proxy_set_header Host $host; 41 proxy_set_header X-Real-IP $remote_addr; 42 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 43 } 44 } 45}

前后端分开部署

前后端的代码没必要都部署到相同的服务器上,也可以分开部署到不同的服务器上,下图是前端服务将 API 请求转发至后端服务的方案。

前后端分开部署方案1

上面的部署方案中,所有浏览器的请求都是直接访问前端服务,而如果是浏览器直接访问后端API服务的部署模式下,如下图。

此时前端和后端通常不在同一个域下,我们还需要在后端代码中添加跨域支持。

前后端分开部署方案2

这里使用github.com/gin-contrib/cors库来支持跨域请求。

最简单的允许跨域的配置是使用cors.Default(),它默认允许所有跨域请求。

1func main() { 2 router := gin.Default() 3 // same as 4 // config := cors.DefaultConfig() 5 // config.AllowAllOrigins = true 6 // router.Use(cors.New(config)) 7 router.Use(cors.Default()) 8 router.Run() 9}

此外,还可以使用cors.Config自定义具体的跨域请求相关配置项:

1package main 2 3import ( 4 "time" 5 6 "github.com/gin-contrib/cors" 7 "github.com/gin-gonic/gin" 8) 9 10func main() { 11 router := gin.Default() 12 // CORS for https://foo.com and https://github.com origins, allowing: 13 // - PUT and PATCH methods 14 // - Origin header 15 // - Credentials share 16 // - Preflight requests cached for 12 hours 17 router.Use(cors.New(cors.Config{ 18 AllowOrigins: []string{"https://foo.com"}, 19 AllowMethods: []string{"PUT", "PATCH"}, 20 AllowHeaders: []string{"Origin"}, 21 ExposeHeaders: []string{"Content-Length"}, 22 AllowCredentials: true, 23 AllowOriginFunc: func(origin string) bool { 24 return origin == "https://github.com" 25 }, 26 MaxAge: 12 * time.Hour, 27 })) 28 router.Run() 29}

容器部署

容器部署方案可参照我之前的博客:使用Docker和Docker Compose部署Go Web应用,这里就不再赘述了。

本文转自 https://www.liwenzhou.com/posts/Go/deploy_go_app/,如有侵权,请联系删除。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )