De localhost:8080 a un endpoint público#

El punto de partida es habitual: un servicio backend HTTP que funciona en tu máquina, por ejemplo una API en Go que escucha en el puerto 8080. El objetivo es exponerlo en internet con un dominio, varias instancias y despliegues repetibles desde una rama, un tag o un commit.

Cualquier plataforma de despliegue te pide los mismos datos: el repositorio, el lenguaje o cómo construir la imagen, si el acceso es público o privado, un prefijo de ruta, la ruta del health check, CPU y memoria, número mínimo y máximo de instancias y cuándo escalar. En esta guía los resolvemos directamente con servicios de AWS: Amazon ECR para la imagen, Amazon ECS sobre AWS Fargate para ejecutarla y un Application Load Balancer (ALB) delante.

El requisito del código: un health check#

El único requisito del código es un endpoint que responda 200 cuando el proceso puede atender peticiones. El balanceador lo consulta periódicamente y deja de enviar tráfico a las instancias que fallan. Este ejemplo usa solo la biblioteca estándar de Go:

go
// main.go (Go 1.22+: patrones con método en ServeMux)
package main

import (
	"log"
	"net/http"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /api/demo/health-check", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ok")) // 200 por defecto
	})
	mux.HandleFunc("GET /api/demo/hello-world", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})
	log.Fatal(http.ListenAndServe(":8080", mux))
}
Servicio mínimo con dos rutas. Los patrones "GET /ruta" requieren Go 1.22 o posterior.

Mantén el health check barato. Puede comprobar dependencias críticas, pero si verifica todo, una caída de un servicio secundario sacará de rotación todas tus instancias a la vez.

Documentación: Go · net/http ↗ · Go · Mejoras de routing en 1.22 ↗

Dónde ejecutarlo en AWS#

OpciónQué gestionasCuándo elegirla
ECS sobre Fargate + ALBTask definition, servicio, target group, escaladoControl total sin administrar servidores; la opción que detalla esta guía
ECS Express ModeImagen y dos roles IAM; AWS crea servicio, ALB con TLS y escaladoQuieres valores por defecto razonables y empezar rápido
AWS App RunnerImagen o códigoSolo si ya eres cliente: AWS lo cerró a nuevos clientes y recomienda migrar a ECS Express Mode

ECS Express Mode crea un servicio de ECS sobre Fargate con URL propia, balanceador con SSL/TLS, políticas de autoescalado y monitorización, y todos los recursos quedan en tu cuenta para ajustarlos después. Si necesitas cada pieza bajo tu control desde el principio, sigue con el enfoque manual.

Documentación: AWS Fargate ↗ · Amazon ECS · Express Mode ↗ · AWS App Runner · Cambio de disponibilidad ↗

Construir la imagen y subirla a ECR#

Un build multietapa compila en una imagen con el toolchain y copia solo el binario a una imagen final mínima, que además se ejecuta como usuario sin privilegios:

dockerfile
# Dockerfile
FROM golang:1.25 AS build
WORKDIR /src
COPY go.mod ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /server .

FROM gcr.io/distroless/static-debian13:nonroot
COPY --from=build /server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
La etiqueta nonroot de distroless ejecuta el proceso como usuario sin privilegios. Construye para la arquitectura que declares en la task definition (aquí ARM64).

Construye la imagen en tu CI para la plataforma correcta (linux/arm64 o linux/amd64) y súbela a un repositorio de Amazon ECR con una etiqueta inmutable, como la versión o el SHA del commit. Evita desplegar la etiqueta latest: no sabrás qué versión corre.

Documentación: Docker · Builds multietapa ↗ · Docker · Builds multiplataforma ↗ · distroless ↗ · Amazon ECR · Subir una imagen ↗

La task definition#

La task definition describe cómo ejecutar el contenedor: imagen, CPU y memoria, puerto y logs. En Fargate, 256 unidades de CPU (0,25 vCPU) admiten 512 MiB, 1 GB o 2 GB de memoria; 1024 unidades equivalen a 1 vCPU.

json
{
  "family": "demo-api",
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "256",
  "memory": "512",
  "runtimePlatform": { "operatingSystemFamily": "LINUX", "cpuArchitecture": "ARM64" },
  "executionRoleArn": "arn:aws:iam::111122223333:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "api",
      "image": "111122223333.dkr.ecr.us-east-1.amazonaws.com/demo-api:1.0.0",
      "essential": true,
      "portMappings": [{ "containerPort": 8080, "protocol": "tcp" }],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/demo-api",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "api"
        }
      }
    }
  ]
}
Ejemplo ilustrativo. El rol de ejecución permite a ECS descargar la imagen de ECR y escribir logs; si tu código llama a otros servicios de AWS, añade además un task role con solo esos permisos.

Las variables de entorno van en la task definition; los secretos, como referencias a Secrets Manager o Parameter Store, para que no queden en texto plano.

Documentación: Amazon ECS · Parámetros de task definition ↗ · Amazon ECS · Fargate ↗ · Amazon ECS · Logs con awslogs ↗ · Amazon ECS · Rol de ejecución ↗ · Amazon ECS · Datos sensibles ↗

Servicio, ALB y health checks#

Con Fargate, las tareas usan el modo de red awsvpc, así que el target group del ALB debe ser de tipo ip, no instance. Configura su health check con la ruta /api/demo/health-check y el código 200. Por defecto, el ALB marca un target como sano tras 5 comprobaciones correctas y como no sano tras 2 fallidas.

Coloca el ALB en subredes públicas y las tareas en subredes privadas. Si el servicio solo debe ser accesible por otros servicios internos, usa un ALB interno: es el equivalente a elegir acceso privado en una plataforma de despliegue. El prefijo de ruta se implementa con reglas de listener por path.

bash
aws ecs create-service \
  --cluster demo \
  --service-name demo-api \
  --task-definition demo-api \
  --desired-count 2 \
  --launch-type FARGATE \
  --network-configuration 'awsvpcConfiguration={subnets=[subnet-private-a,subnet-private-b],securityGroups=[sg-api],assignPublicIp=DISABLED}' \
  --load-balancers targetGroupArn=arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/demo-api/0123456789abcdef,containerName=api,containerPort=8080 \
  --health-check-grace-period-seconds 30 \
  --deployment-configuration 'deploymentCircuitBreaker={enable=true,rollback=true}'
Crea el servicio con dos tareas en subredes privadas, registradas en el target group. Los IDs de subred, security group y target group son de ejemplo.

healthCheckGracePeriodSeconds indica cuánto tiempo, tras arrancar una tarea, ECS ignora los health checks fallidos; súbelo si tu servicio tarda en iniciar. El deployment circuit breaker detecta despliegues que no llegan a estado estable y, con rollback activado, vuelve a la última versión completada.

Documentación: Amazon ECS · ALB y target type ip ↗ · ELB · Health checks ↗ · Amazon ECS · Parámetros de servicio ↗ · AWS CLI · ecs create-service ↗ · Amazon ECS · Circuit breaker ↗ · Amazon VPC · Subredes ↗

Escalado y costo#

  • Target tracking: define un valor objetivo, por ejemplo 60 % de CPU media del servicio, y Application Auto Scaling añade o quita tareas entre tu mínimo y tu máximo.
  • Fargate Spot: ejecuta tareas tolerantes a interrupciones con descuento; AWS puede recuperarlas con un aviso de dos minutos. Combínalo con capacidad Fargate normal para mantener un mínimo estable.
  • Mantén al menos dos tareas en zonas de disponibilidad distintas para que un fallo de zona no te deje sin servicio.

Documentación: Amazon ECS · Target tracking ↗ · Amazon ECS · Fargate Spot ↗

Verificar y diagnosticar#

Cuando el servicio esté estable, llama a los mismos endpoints que usabas en local, ahora a través del dominio del ALB. Si los targets no pasan a healthy, revisa en este orden: que el contenedor escucha en el puerto declarado, que la ruta del health check es exacta, que el security group de las tareas acepta tráfico del ALB en ese puerto, que el grace period da tiempo al arranque y que los logs en CloudWatch no muestran errores de configuración.

Fuentes y alcance

Documentación consultada el 25 de septiembre de 2026. Los ejemplos y criterios de decisión son propuestas editoriales; adáptalos al contrato de tu aplicación y valídalos en tu entorno de pruebas autorizado.

Del diseño a la decisión

Compara soluciones cloud

Revisa tarifas, límites, condiciones y fuentes de cada opción.

Abrir comparador