Configuração de aplicativo da web de produção Golang

120

Para aqueles que executam back-ends de Go na produção:

Qual é a sua pilha / configuração para executar um aplicativo da web Go?

Eu não vi muito sobre este tópico além de pessoas usando o pacote net / http da biblioteca padrão para manter um servidor funcionando. Eu li usando Nginx para passar solicitações para um servidor Go - nginx com Go

Isso parece um pouco frágil para mim. Por exemplo, o servidor não seria reiniciado automaticamente se a máquina fosse reiniciada (sem scripts de configuração adicionais).

Existe uma configuração de produção mais sólida?

Um aparte sobre minha intenção - estou planejando um servidor backend REST com Go para meu próximo projeto e quero ter certeza de que Go será viável para lançar o projeto ao vivo antes de investir muito nele.

Chaseph
fonte
3
"o servidor não reiniciaria automaticamente se a máquina fosse reiniciada (sem scripts de configuração adicionais)." Não acho que isso possa ser feito. Idealmente, você criou scripts init / systemd / upstart para o serviço. Esta é a maneira recomendada para qualquer daemon Unix ser controlado.
Intermernet
Você está certo. Acho que quis dizer isso em contraste com um servidor como o apache, que configura automaticamente esses recursos no momento da instalação.
Chaseph

Respostas:

134

Os programas Go podem ouvir na porta 80 e atender a solicitações HTTP diretamente. Em vez disso, você pode querer usar um proxy reverso na frente do seu programa Go, para que ele escute na porta 80 e se conecte ao seu programa na porta, digamos, 4000. Há muitos motivos para fazer o último: não ter que executar seu programa Go como root, servindo outros sites / serviços no mesmo host, terminação SSL, balanceamento de carga, registro, etc.

Eu uso o HAProxy na frente. Qualquer proxy reverso pode funcionar. Nginx também é uma ótima opção (muito mais popular do que o HAProxy e capaz de fazer mais).

O HAProxy é muito fácil de configurar se você ler sua documentação ( versão HTML ). haproxy.cfgSegue-se todo o meu arquivo de um dos meus projetos Go, caso você precise de um ponto inicial.

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 é ainda mais fácil.

Com relação ao controle de serviço, executo meu programa Go como um serviço do sistema. Acho que todo mundo faz isso. Meu servidor executa o Ubuntu, então ele usa o Upstart. Eu coloquei isso no /etc/init/myapp.confUpstart para controlar meu programa:

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

Outro aspecto é a implantação. Uma opção é implantar apenas enviando o arquivo binário do programa e os ativos necessários. Esta é uma ótima solução IMO. Eu uso a outra opção: compilar no servidor. (Vou mudar para a implantação com arquivos binários quando configurar um sistema denominado “Integração / Implantação Contínua”.)

Eu tenho um pequeno script de shell no servidor que extrai o código do meu projeto de um repositório Git remoto, o constrói com Go, copia os binários e outros ativos ~/myapp/e reinicia o serviço.

No geral, a coisa toda não é muito diferente de qualquer outra configuração de servidor: você precisa ter uma maneira de executar seu código e fazer com que ele atenda a solicitações HTTP. Na prática, Go provou ser muito estável para essas coisas.

Mostafa
fonte
9
Ótima resposta! Bons exemplos de tudo o que é necessário para uma configuração básica recomendada.
Intermernet
O que você faz sobre a rotação do log? Essa é praticamente a única razão pela qual eu uso o supervisord, mas ele sofre quando há muito registro em log.
fiorix
@fiorix, tenho certeza que você poderia abrir uma pergunta diferente do SO sobre a rotação de log, mas ainda assim, se você estiver no unix e quiser usar ferramentas padrão, verifique logrotate: linuxcommand.org/man_pages/logrotate8.html . Isso é usado por muitos dos serviços mais conhecidos (apache, yum, etc.) e é bastante fácil de configurar.
Doody P
Seria fácil criar seu próprio proxy reverso no Go? Isso seria uma ideia significativamente pior do que usar nginx ou haproxy? Quer dizer, Go vem com ótimo suporte HTTP / HTTPS / HTTP / 2.
thomasrutter
58

nginx para:

  • Proxy HTTP reverso para meu aplicativo Go
  • Tratamento de arquivos estáticos
  • Rescisão SSL
  • Cabeçalhos HTTP (Cache-Control, et. Al)
  • Registros de acesso (e, portanto, aproveitando a rotação de registros do sistema)
  • Reescritas (sem www para www, http: // para https: //, etc.)

O nginx torna isso muito fácil e, embora você possa servir diretamente do Go graças ao net/http, há muito "reinventar a roda" e coisas como cabeçalhos HTTP globais envolvem alguns clichês que você provavelmente pode evitar.

supervisord para gerenciar meu binário Go. O Upstart do Ubuntu (como mencionado por Mostafa) também é bom, mas eu gosto do supervisord porque é relativamente independente de distro e está bem documentado.

Supervisord, para mim:

  • Executa meu binário Go conforme necessário
  • Traz depois de um acidente
  • Contém minhas variáveis ​​de ambiente (chaves de autenticação de sessão, etc.) como parte de uma única configuração.
  • Executa meu banco de dados (para garantir que meu binário Go não funcione sem ele)
elithrar
fonte
8

Para aqueles que querem um aplicativo go simples rodando como um daemon, use systemd (suportado por muitas distros Linux) ao invés do Upstart.

Crie um arquivo de serviço em

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

Entrar

[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

Em seguida, ative e inicie o serviço

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

O systemd possui um sistema de journaling separado que permite rastrear registros para fácil resolução de problemas.

mixdev
fonte
5

Você pode vincular seu binário a um soquete para portas privilegiadas de domínio da Internet (números de porta menores que 1024) usando setcap

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

  1. Este comando precisa ser escalado. sudocomo necessário
  2. Cada nova versão do seu programa resultará em um novo binário que precisará ser reautorizado por setcap

setcap documentação

cap_net_bind_service documentação

Emperor_Earth
fonte