生产环境下的Golang Web应用配置

124

对于正在生产中运行 Go 后端的用户:

您运行 Go web 应用程序时使用的堆栈/配置是什么?

除了使用标准库 net/http 包来保持服务器运行之外,我没有看到过关于这个话题的许多内容。 我阅读了一个使用 Nginx 将请求传递给 Go 服务器的文章 - nginx with Go

但是这种方式对我来说似乎有点脆弱。例如,如果机器重新启动(没有额外的配置脚本),服务器将不会自动重启。

是否有更稳定的生产设置方案?

关于我的意图 - 我正在计划使用 Go 构建 REST 后端服务器来开发我的下一个项目,并希望确保在投入太多资金之前可以通过 Go 在线上发布项目。


4
如果机器重新启动(没有额外的配置脚本),服务器将不会自动重启。我认为这是做不到的。理想情况下,您应该为服务创建init/systemd/upstart脚本。这是任何Unix守护程序控制的推荐方式。 - Intermernet
没错。我想我的意思是与像Apache这样的服务器相对,它会在安装时自动设置这些功能。 - Chaseph
4个回答

137

Go程序可以监听80端口并直接提供HTTP请求服务。不过,你可能希望在Go程序前使用一个反向代理,这样它将监听80端口,并连接到你的程序所在的端口,比如说4000端口。这样做的原因有很多,例如:不需要将Go程序以root用户身份运行、在同一主机上提供其他网站/服务、SSL终止、负载均衡、日志记录等。

我使用HAProxy作为反向代理,任何反向代理都可以工作。Nginx也是一个很棒的选择(比HAProxy更受欢迎并且能够做更多的事情)。

如果你阅读了文档HTML版本),就会发现配置HAProxy非常容易。我的整个haproxy.cfg文件用于我的一个Go项目,以防你需要一个起点。

global
        log     127.0.0.1       local0
        maxconn 10000
        user    haproxy
        group   haproxy
        daemon

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        timeout connect 5000
        timeout client  50000
        timeout server  50000

frontend http
        bind :80
        acl  is_stats  hdr(host)       -i      hastats.myapp.com
        use_backend    stats   if      is_stats
        default_backend        myapp
        capture        request header Host     len     20
        capture        request header Referer  len     50

backend myapp
        server  main    127.0.0.1:4000

backend stats
       mode     http
       stats    enable
       stats    scope   http
       stats    scope   myapp
       stats    realm   Haproxy\ Statistics
       stats    uri     /
       stats    auth    username:password

Nginx更加简单易用。

关于服务的控制,我将我的Go程序运行为系统服务。我认为每个人都这样做。我的服务器运行Ubuntu,因此使用Upstart。 我在/etc/init/myapp.conf中设置了这个程序,供Upstart控制:

start on runlevel [2345]
stop on runlevel [!2345]

chdir /home/myapp/myapp
setgid myapp
setuid myapp
exec ./myapp start 1>>_logs/stdout.log 2>>_logs/stderr.log

另一个方面是部署。一种选择是通过发送程序和必要资产的二进制文件来部署。在我看来,这是一个相当不错的解决方案。我使用另一种选项:在服务器上编译。(当我设置所谓的“持续集成/部署”系统时,我将切换到使用二进制文件进行部署。)

我的服务器上有一个小的shell脚本,从远程Git存储库中拉取我的项目代码,使用Go构建它,将二进制文件和其他资产复制到~/myapp/,然后重新启动服务。

总的来说,整个过程与任何其他服务器设置并没有太大区别:你必须有一种运行代码并处理HTTP请求的方式。在实践中,Go在这方面被证明非常稳定。


9
很好的回答!涵盖了推荐基本设置所需的所有要素,有很好的例子。 - Intermernet
你对日志轮换怎么处理?这几乎是我使用supervisord的唯一原因,但当有太多日志记录时,它会出现问题。 - fiorix
@fiorix,我相信你可以开一个关于日志轮换的不同SO问题,但是如果你在Unix上并且想要使用标准工具,请查看logrotate:http://linuxcommand.org/man_pages/logrotate8.html。这被许多知名服务(如apache、yum等)使用,并且相当容易配置。 - Doody P
在Go中创建自己的反向代理有多容易?这比使用nginx或haproxy明显更糟糕吗?我的意思是,Go具有出色的HTTP / HTTPS / HTTP / 2支持。 - thomasrutter

60

nginx用于:

  • 将HTTP请求反向代理到我的Go应用程序
  • 处理静态文件
  • SSL终止
  • HTTP头(Cache-Control等)
  • 访问日志(因此利用系统日志轮换)
  • 重写(裸域名到www,http://到https://等)

nginx使这些变得非常容易,虽然由于net/http,您也可以直接从Go提供服务,但是这需要很多“重新发明轮子”的工作,并且像全局HTTP头这样的东西涉及一些样板代码,您可能可以避免。

supervisord用于管理我的Go二进制文件。 Ubuntu的Upstart(Mostafa提到)也不错,但我喜欢supervisord,因为它相对独立于发行版,并且文档齐全。

对于我来说,Supervisord:

  • 根据需要运行我的Go二进制文件
  • 在崩溃后重新启动它
  • 保存我的环境变量(会话授权密钥等)作为单个配置的一部分。
  • 运行我的数据库(以确保我的Go二进制文件不会在没有它的情况下运行)

10

对于那些想要将简单的 Go 应用程序作为守护进程运行的人,建议使用 systemd(被许多 Linux 发行版支持),而不是 Upstart。

在以下路径创建一个服务文件:

touch /etc/systemd/system/my-go-daemon.service

输入

[Unit]
Description=My Go App

[Service]
Type=simple
WorkingDirectory=/my/go/app/directory
ExecStart=/usr/lib/go run main.go 

[Install]
WantedBy=multi-user.target

然后启用并启动服务

systemctl enable my-go-daemon
systemctl start my-go-daemon
systemctl status my-go-daemon

systemd拥有一个单独的日志系统,让您可以跟踪日志以便轻松进行故障排除。


6
您可以使用 setcap 命令将您的二进制文件绑定到 Internet 域特权端口(端口号小于 1024),以便进行套接字操作。 setcap 'cap_net_bind_service=+ep' /path/to/binary 注意:
1. 此命令需要提升权限,必要时使用 sudo。 2. 每个新版本的程序都会生成一个新的二进制文件,需要再次通过 setcap 授权。
有关更多信息,请参阅:
- setcap 文档 - cap_net_bind_service 文档

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接