Golang生产级Web应用配置

huangapple go评论75阅读模式
英文:

Golang production web application configuration

问题

对于那些在生产环境中运行Go后端的人:

你们运行Go Web应用程序的堆栈/配置是什么?

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

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

是否有更可靠的生产环境设置?

关于我的意图的一点说明 - 我正在计划为我的下一个项目设计一个由Go驱动的REST后端服务器,并希望确保在投入太多资源之前,Go在项目上线时是可行的。

英文:

For those of you running Go backends in production:

What is your stack / configuration for running a Go web application?

I haven't seen much on this topic besides people using the standard library net/http package to keep a server running. I read using Nginx to pass requests to a Go server - nginx with Go

This seems a little fragile to me. For instance, the server would not automatically restart if the machine was restarted (without additional configuration scripts).

Is there a more solid production setup?

An aside about my intent - I'm planning out a Go powered REST backend server for my next project and want to make sure Go is going to be viable for launching the project live before I invest too much into it.

答案1

得分: 137

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

我在前面使用HAProxy。任何反向代理都可以工作。Nginx也是一个很好的选择(比HAProxy更受欢迎,功能更强大)。

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

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在这方面被证明非常稳定。

英文:

Go programs can listen on port 80 and serve HTTP requests directly. Instead, you may want to use a reverse proxy in front of your Go program, so that it listens on port 80 and and connects to your program on port, say, 4000. There are many reason for doing the latter: not having to run your Go program as root, serving other websites/services on the same host, SSL termination, load balancing, logging, etc.

I use HAProxy in front. Any reverse proxy could work. Nginx is also a great option (much more popular than HAProxy and capable of doing more).

HAProxy is very easy to configure if you read its documentation (HTML version). My whole haproxy.cfg file for one of my Go projects follows, in case you need a starting pont.

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 is even easier.

Regarding service control, I run my Go program as a system service. I think everybody does that. My server runs Ubuntu, so it uses Upstart. I have put this at /etc/init/myapp.conf for Upstart to control my program:

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

Another aspect is deployment. One option is to deploy by just sending binary file of the program and necessary assets. This is a pretty great solution IMO. I use the other option: compiling on server. (I’ll switch to deploying with binary files when I set up a so-called “Continuous Integration/Deployment” system.)

I have a small shell script on the server that pulls code for my project from a remote Git repository, builds it with Go, copies the binaries and other assets to ~/myapp/, and restarts the service.

Overall, the whole thing is not very different from any other server setup: you have to have a way to run your code and have it serve HTTP requests. In practice, Go has proved to be very stable for this stuff.

答案2

得分: 59

nginx用于:

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

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

supervisord用于管理我的Go二进制文件。Ubuntu的Upstart(如Mostafa所提到的)也不错,但我喜欢supervisord,因为它相对于发行版来说比较通用,并且有很好的文档。

对我来说,Supervisord:

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

nginx for:

  • Reverse HTTP proxy to my Go application
  • Static file handling
  • SSL termination
  • HTTP headers (Cache-Control, et. al)
  • Access logs (and therefore leveraging system log rotation)
  • Rewrites (naked to www, http:// to https://, etc.)

nginx makes this very easy, and although you can serve directly from Go thanks to net/http, there's a lot of "re-inventing the wheel" and stuff like global HTTP headers involves some boilerplate you can probably avoid.

supervisord for managing my Go binary. Ubuntu's Upstart (as mentioned by Mostafa) is also good, but I like supervisord as it's relatively distro-agnostic and is well documented.

Supervisord, for me:

  • Runs my Go binary as needed
  • Brings it up after a crash
  • Holds my environmental variables (session auth keys, etc.) as part of a single config.
  • Runs my DB (to make sure my Go binary isn't running without it)

答案3

得分: 9

对于那些想要将简单的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有一个独立的日志记录系统,可以让您轻松地跟踪日志以进行故障排除。

英文:

For those who want simple go app running as a daemon, use systemd (Supported by many linux distros) instead of Upstart.

Create a service file at

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

Enter

[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

Then enable and start the service

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

systemd has a separate journaling system that will let you tail logs for easy trouble-shooting.

答案4

得分: 6

你可以使用setcap将你的二进制文件绑定到Internet域特权端口(端口号小于1024)的套接字。

setcap 'cap_net_bind_service=+ep' /path/to/binary

  1. 这个命令需要提升权限。根据需要使用sudo
  2. 每个新版本的程序都会生成一个新的二进制文件,需要通过setcap重新授权。

setcap文档

cap_net_bind_service文档

英文:

You can bind your binary to a socket to Internet domain privileged ports (port numbers less than 1024) using setcap

setcap 'cap_net_bind_service=+ep' /path/to/binary

  1. This command needs to be escalated. sudo as necessary
  2. Every new version of your program will result in a new binary that will need to be reauthorized by setcap

setcap documentation

cap_net_bind_service documentation

huangapple
  • 本文由 发表于 2013年7月3日 13:34:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/17440415.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定