Saltar al contenido principal

Go

Kubiy compila y ejecuta aplicaciones Go usando systemd como process manager. El flujo de producción compila un binario estático llamado kubiy-app que systemd ejecuta y reinicia si falla.

Presets disponibles

Binario compilado (exec)

Este es el preset recomendado para producción. Kubiy compila tu aplicación en un binario estático llamado kubiy-app y lo ejecuta directamente.

ParámetroValor
startModeexec
Target./kubiy-app (fijo, no configurable)
Build por defectogo build -o kubiy-app .

El binario siempre debe llamarse kubiy-app y estar en el directorio raíz del proyecto. Kubiy lo busca en esa ubicación específica para iniciarlo.

Ejemplo de configuración:

Preset: Binario compilado (exec)

go run

Modo de desarrollo. Compila y ejecuta la aplicación on-the-fly con go run. No produce un binario persistente.

ParámetroValor
startModego
Target por defectomain.go
Build por defectoninguno

Ejemplo de configuración:

Preset: go run
Target: main.go

:::warning Uso en producción go run recompila la app en cada inicio, lo que añade latencia al arranque y consume recursos de CPU. Úsalo solo para testing o demos. Para producción, usa siempre el preset de binario compilado. :::

Puerto

Kubiy inyecta tanto PORT como APP_PORT. Tu app debe leer el puerto desde alguna de estas variables:

package main

import (
"fmt"
"net/http"
"os"
)

func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}

http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{"status":"ok"}`)
})

http.ListenAndServe(":"+port, nil)
}

El puerto por defecto es 8080.

El binario kubiy-app

El nombre kubiy-app es obligatorio. Kubiy siempre busca y ejecuta ./kubiy-app en la raíz del proyecto.

Si usas el build por defecto (go build -o kubiy-app .), el binario se genera correctamente. Si especificas un Build Command personalizado, eres responsable de que el output sea ./kubiy-app.

# Correcto — produce ./kubiy-app
go build -o kubiy-app ./cmd/server

# Incorrecto — no produce ./kubiy-app
go build -o mi-app .

Build Command

Si dejas el campo vacío, Kubiy ejecuta:

go build -o kubiy-app .

Esto compila todos los archivos Go en el paquete principal y produce el binario kubiy-app.

Si tu estructura de proyecto es diferente (por ejemplo, el main está en cmd/server/), especifica el Build Command:

go build -o kubiy-app ./cmd/server

Otros ejemplos comunes:

# Con flags de optimización y version embedding
go build -ldflags="-s -w -X main.version=$(git rev-parse --short HEAD)" -o kubiy-app .

# Compilación con CGO deshabilitado (para mayor portabilidad)
CGO_ENABLED=0 go build -o kubiy-app .

# Con módulos en un subdirectorio
cd cmd/api && go build -o ../../kubiy-app .
aviso

Cuando especificas un Build Command, ese comando reemplaza completamente el build por defecto. Debes asegurarte de que el resultado es un binario ejecutable llamado kubiy-app en la raíz del proyecto.

Ver la referencia completa de Build Command.

Casos de uso comunes

API con net/http estándar

package main

import (
"encoding/json"
"log"
"net/http"
"os"
)

func main() {
mux := http.NewServeMux()

mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})

mux.HandleFunc("/api/hello", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"message": "Hello World"})
})

port := os.Getenv("PORT")
if port == "" {
port = "8080"
}

log.Printf("Escuchando en :%s", port)
log.Fatal(http.ListenAndServe(":"+port, mux))
}

Configuración en Kubiy:

Preset: Binario compilado (exec)
Health: /health

Gin Framework

package main

import (
"net/http"
"os"
"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()

r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})

port := os.Getenv("PORT")
if port == "" {
port = "8080"
}

r.Run(":" + port)
}

Proyecto con estructura cmd/

Si tu repositorio tiene esta estructura:

.
├── cmd/
│ └── server/
│ └── main.go
├── internal/
│ └── ...
├── go.mod
└── go.sum

Configuración en Kubiy:

Preset: Binario compilado (exec)
Build Command: go build -o kubiy-app ./cmd/server

Monorepo o subdirectorio

Si el proyecto Go está en services/api/:

Subdirectorio: services/api
Preset: Binario compilado (exec)

Kubiy usará services/api/ como raíz para el build y el go build -o kubiy-app . se ejecutará en ese directorio.

Variables de entorno disponibles

VariableDescripción
PORTPuerto asignado (default 8080)
APP_PORTAlias de PORT
KUBIY_DEPLOY_IDID del deploy actual
KUBIY_APP_IDID de la aplicación
import "os"

port := os.Getenv("PORT")
dbURL := os.Getenv("DATABASE_URL")
apiKey := os.Getenv("API_KEY")

Health Check recomendado

mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok"}`))
})

El endpoint debe responder en menos de 1 segundo para que Kubiy lo considere exitoso.

Troubleshooting

"kubiy-app not found" o el deploy falla al iniciar

El binario kubiy-app no se generó en la raíz del proyecto. Causas comunes:

  1. El main no está en la raíz — Si tu estructura tiene cmd/server/main.go, usa go build -o kubiy-app ./cmd/server como Build Command.
  2. Build Command personalizado con nombre de binario incorrecto — Asegúrate de que el flag -o produce kubiy-app.
  3. Error durante el build — Revisa los logs del deploy para ver el error de compilación.

Error de compilación — dependencia no encontrada

Go modules deben estar correctamente configurados. Asegúrate de que:

  • go.mod existe en la raíz del proyecto (o en el subdirectorio configurado)
  • go.sum está actualizado (go mod tidy localmente)
  • Los módulos se descargan durante el build (go build descarga automáticamente)

La app no responde en el puerto correcto

Verifica que tu app escucha en 0.0.0.0 (no solo en localhost):

// Correcto
http.ListenAndServe(":"+port, nil) // equivale a 0.0.0.0:port
http.ListenAndServe("0.0.0.0:"+port, nil)

// Incorrecto — solo acepta conexiones locales
http.ListenAndServe("127.0.0.1:"+port, nil)

Binario no ejecutable (permisos)

Si usas un Build Command que crea el binario de forma no convencional, asegúrate de que el archivo tenga permisos de ejecución. El go build estándar los asigna automáticamente.

CGO y dependencias nativas

Si tu app usa CGO (por ejemplo, sqlite3 con mattn/go-sqlite3), las dependencias nativas deben estar instaladas en el servidor. Por limitaciones del entorno, se recomienda deshabilitar CGO cuando sea posible:

CGO_ENABLED=0 go build -o kubiy-app .

Si necesitas CGO, contacta a soporte para verificar la disponibilidad de las dependencias nativas en el runtime.