Configuración de la aplicación web de producción de Golang

120

Para aquellos de ustedes que ejecutan Go backends en producción:

¿Cuál es su pila / configuración para ejecutar una aplicación web Go?

No he visto mucho sobre este tema además de personas que usan el paquete net / http de la biblioteca estándar para mantener un servidor en funcionamiento. Leí usando Nginx para pasar solicitudes a un servidor de Go - nginx con Go

Esto me parece un poco frágil. Por ejemplo, el servidor no se reiniciaría automáticamente si se reiniciara la máquina (sin scripts de configuración adicionales).

¿Existe una configuración de producción más sólida?

Un aparte sobre mi intención: estoy planeando un servidor backend REST con tecnología Go para mi próximo proyecto y quiero asegurarme de que Go será viable para lanzar el proyecto en vivo antes de invertir demasiado en él.

Chaseph
fuente
3
"el servidor no se reiniciaría automáticamente si se reiniciara la máquina (sin scripts de configuración adicionales)". No creo que esto se pueda hacer. Lo ideal es que haya creado scripts init / systemd / upstart para el servicio. Esta es la forma recomendada para controlar cualquier demonio de Unix.
Intermernet
Estás en lo correcto. Supongo que lo dije en serio, en contraste con un servidor como Apache, que configura automáticamente esas funciones en el momento de la instalación.
Chaseph

Respuestas:

134

Los programas Go pueden escuchar en el puerto 80 y atender solicitudes HTTP directamente. En su lugar, es posible que desee utilizar un proxy inverso delante de su programa Go, de modo que escuche en el puerto 80 y se conecte a su programa en el puerto, digamos 4000. Hay muchas razones para hacer esto último: no tener que ejecutar su programa Go como root, sirviendo otros sitios web / servicios en el mismo host, terminación SSL, equilibrio de carga, registro, etc.

Yo uso HAProxy en frente. Cualquier proxy inverso podría funcionar. Nginx también es una gran opción (mucho más popular que HAProxy y capaz de hacer más).

HAProxy es muy fácil de configurar si lees su documentación ( versión HTML ). A continuación se muestra todo el haproxy.cfgarchivo de uno de mis proyectos de Go, en caso de que necesite un pont 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 es aún más fácil.

Con respecto al control del servicio, ejecuto mi programa Go como un servicio del sistema. Creo que todo el mundo hace eso. Mi servidor ejecuta Ubuntu, por lo que usa Upstart. He puesto esto en /etc/init/myapp.confUpstart para controlar mi 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

Otro aspecto es el despliegue. Una opción es implementar simplemente enviando un archivo binario del programa y los activos necesarios. Esta es una gran solución en mi opinión. Yo uso la otra opción: compilar en el servidor. (Cambiaré a la implementación con archivos binarios cuando configure un sistema llamado "Integración / Implementación continua").

Tengo un pequeño script de shell en el servidor que extrae el código para mi proyecto desde un repositorio Git remoto, lo compila con Go, copia los binarios y otros activos ~/myapp/y reinicia el servicio.

En general, todo no es muy diferente de cualquier otra configuración de servidor: debe tener una forma de ejecutar su código y hacer que sirva solicitudes HTTP. En la práctica, Go ha demostrado ser muy estable para estas cosas.

Mostafa
fuente
9
¡Gran respuesta! Buenos ejemplos de todo lo necesario para una configuración básica recomendada.
Intermernet
¿Qué haces con la rotación de troncos? Esa es prácticamente la única razón por la que utilizo supervisord, pero sufre cuando hay demasiados registros.
fiorix
@fiorix, estoy bastante seguro de que podría abrir una pregunta SO diferente sobre la rotación de registros, pero aún así, si está en unix y desea usar herramientas estándar, consulte logrotate: linuxcommand.org/man_pages/logrotate8.html . Esto es utilizado por muchos de los servicios conocidos (apache, yum, etc.) y es bastante fácil de configurar.
Doody P
¿Qué tan fácil sería crear su propio proxy inverso en Go? ¿Sería esta una idea significativamente peor que usar nginx o haproxy? Me refiero a que Go viene con un excelente soporte para HTTP / HTTPS / HTTP / 2.
thomasrutter
58

nginx para:

  • Proxy HTTP inverso a mi aplicación Go
  • Manejo de archivos estáticos
  • Terminación SSL
  • Encabezados HTTP (Cache-Control, et. Al)
  • Registros de acceso (y, por lo tanto, aprovechando la rotación de registros del sistema)
  • Reescribe (desnudo en www, http: // en https: //, etc.)

nginx hace que esto sea muy fácil, y aunque puede servir directamente desde Go gracias a net/http, hay muchas "reinventar la rueda" y cosas como los encabezados HTTP globales implican un texto repetitivo que probablemente pueda evitar.

supervisor para administrar mi binario Go. Upstart de Ubuntu (como lo menciona Mostafa) también es bueno, pero me gusta supervisord ya que es relativamente independiente de la distribución y está bien documentado.

Supervisor, para mí:

  • Ejecuta mi binario Go según sea necesario
  • Lo trae a colación después de un accidente
  • Contiene mis variables ambientales (claves de autenticación de sesión, etc.) como parte de una única configuración.
  • Ejecuta mi base de datos (para asegurarse de que mi binario Go no se ejecuta sin él)
elithrar
fuente
8

Para aquellos que quieren una aplicación simple que se ejecute como un demonio, use systemd (compatible con muchas distribuciones de Linux) en lugar de Upstart.

Cree un archivo de servicio en

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

Luego habilite e inicie el servicio

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

systemd tiene un sistema de registro por diario independiente que le permitirá realizar registros finales para facilitar la resolución de problemas.

mixdev
fuente
5

Puede vincular su binario a un socket a puertos privilegiados de dominio de Internet (números de puerto inferiores a 1024) usando setcap

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

  1. Este comando debe escalarse. sudosegún sea necesario
  2. Cada nueva versión de su programa dará como resultado un nuevo binario que deberá ser reautorizado por setcap

setcap documentación

cap_net_bind_service documentación

Emperor_Earth
fuente