英文:
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
- 这个命令需要提升权限。根据需要使用
sudo
。 - 每个新版本的程序都会生成一个新的二进制文件,需要通过
setcap
重新授权。
英文:
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
- This command needs to be escalated.
sudo
as necessary - Every new version of your program will result in a new binary that will need to be reauthorized by
setcap
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论