[{"Value":"","Discard":false,"Expires":9999999999}]
La entrada 🩺 Docker HEALTHCHECK: Is Your App Really Alive Inside the Container? se publicó primero en CloudArch.
]]>

Welcome to the world of Docker HEALTHCHECK — a super underrated feature that can make or break your reliability game. Today we’ll dive into:
Why HEALTHCHECK is essential
Real risks of skipping it
How Docker HEALTHCHECK Works
How to add it to your Dockerfiles
Two practical test cases (healthy vs unhealthy)
Why You Should CareLet’s be honest. We often celebrate when our container is “up and running” — but that just means the process inside hasn’t crashed. It doesn’t tell us if:



Without a healthcheck, Docker assumes everything is okay. That’s dangerous in production, but also in dev: it gives you a false sense of security.
Healthchecks add real visibility — if your app doesn’t behave as expected, Docker will mark it as unhealthy, and tools like Docker Swarm or Kubernetes can act accordingly (restarts, scaling, etc.).
How Docker HEALTHCHECK Works — Under the HoodWhen you add a HEALTHCHECK instruction in your Dockerfile, you’re telling the Docker engine to periodically run a command inside the container to determine its health status. Here’s how it works step by step:
1. The HEALTHCHECK InstructionExample:
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1You’re defining:
| Option | Meaning |
|---|---|
CMD | The actual command to run inside the container. It must exit with 0 for healthy, non-zero for unhealthy. |
--interval | How often to run the health check (default: 30s). |
--timeout | How long to wait before the command is considered failed (default: 30s). |
--retries | Number of consecutive failures before the container is marked unhealthy (default: 3). |
2. Docker Monitors Using a Background Healthcheck ManagerWhen you start a container that has a HEALTHCHECK, Docker spawns a lightweight internal timer per container. This timer schedules and executes the CMD at the interval you define.
It’s all handled by the Docker daemon, which adds a health state entry to the container’s metadata.
3. Exit Codes Determine HealthDocker executes the healthcheck command inside the container, and uses its exit code to decide the result:
| Exit Code | Meaning |
|---|---|
0 | Healthy ![]() |
1 | Unhealthy ![]() |
>1 | Unhealthy ![]() |
CMD not found or fails to run? Still counts as unhealthy.
Docker tracks the consecutive failures, and once the retry limit is reached, the container is marked as unhealthy.
4. Status Stored in Container MetadataYou can view this with:
docker inspect --format='{{json .State.Health}}' [container_name] | jqIt shows:
Status: starting, healthy, or unhealthyFailingStreak: how many times it failed consecutivelyLog: recent healthcheck attempts with timestamps and outputsDocker updates this metadata in real-time, and you can consume it via:
docker ps, docker inspect)/containers/id/json)
5. No Magic, Just Smart LogicDocker doesn’t inject anything magical into your container. It simply:
curl, wget, etc.)But this tiny mechanism becomes powerful when combined with:
--restart=on-failure)
A Note About “Starting”After the container boots, healthchecks begin after a default grace period of 0s (can be configured). During this period, the container status shows as:
"Status": "starting"Once the first successful check is done, status becomes healthy. If it fails N times, it becomes unhealthy.
What Healthchecks DON’T Do
They do not stop or restart containers by themselves
They don’t directly affect container networking or DNS
They don’t send alerts unless you wire them to an external system
Adding a HEALTHCHECK to Your DockerfileIt’s simple! Here’s the syntax:
HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD curl -f http://localhost:5000/health || exit 1This checks every 10 seconds if the /health endpoint returns a success. If it fails 3 times in a row, the container becomes unhealthy.
Let’s Test It in ActionWe’ll create two test containers:
Healthy AppThis one includes a proper /health endpoint that always returns 200 OK.
Dockerfile:
FROM python:3.11-slim
ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /app
COPY app.py .
# Install curl
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN pip install flask
EXPOSE 5000
HEALTHCHECK --interval=10s CMD curl -f http://127.0.0.1:5000/health || exit 1
CMD ["python", "app.py"]
app.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "All good!"
@app.route('/health')
def health():
return "OK", 200
app.run(host="0.0.0.0", port=5000)
Build and run:
docker build -t healthy-app .healthtest
docker run -d --namehealthy-apphealthtest
docker inspect --format='{{.State.Health.Status}}'
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
55e9b6f148a9 healthcheck_test "python app.py" 18 seconds ago Up 18 seconds (healthy) 0.0.0.0:5000->5000/tcp, [::]:5000->5000/tcp healthtest
You’ll get: healthy
Unhealthy AppNow let’s break the /health endpoint.
Modified app.py:
@app.route('/health')
def health():
return "Error", 500Build and run again:
docker build -t unhealthy-app .
docker run -d --name broken unhealthy-app
docker inspect --format='{{.State.Health.Status}}' broken
Result: unhealthy
You’ll also see the logs showing failed healthcheck attempts:
$docker inspect broken | jq '.[].State.Health.Log'
[
{
"Start": "2025-06-05T19:26:07.323262742+02:00",
"End": "2025-06-05T19:26:07.367595028+02:00",
"ExitCode": 1,
"Output": " % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r 0 5 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\ncurl: (22) The requested URL returned error: 500\n"
},
{
"Start": "2025-06-05T19:26:17.369661511+02:00",
"End": "2025-06-05T19:26:17.408770486+02:00",
"ExitCode": 1,
"Output": " % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r 0 5 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\ncurl: (22) The requested URL returned error: 500\n"
},
{
"Start": "2025-06-05T19:26:27.409488914+02:00",
"End": "2025-06-05T19:26:27.450101106+02:00",
"ExitCode": 1,
"Output": " % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r 0 5 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\ncurl: (22) The requested URL returned error: 500\n"
},
{
"Start": "2025-06-05T19:26:37.450803223+02:00",
"End": "2025-06-05T19:26:37.492805511+02:00",
"ExitCode": 1,
"Output": " % Total % Received % Xferd Average Speed Time Time Time Current\n Dload Upload Total Spent Left Speed\n\r 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\r 0 5 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\ncurl: (22) The requested URL returned error: 500\n"
}
]
What’s the Impact?| Scenario | Behavior |
|---|---|
| No HEALTHCHECK | Docker marks container as healthy by default |
| HEALTHCHECK passes | Container state = healthy ![]() |
| HEALTHCHECK fails | Container state = unhealthy ![]() |
Why it matters:
Final ThoughtsA HEALTHCHECK is like a pulse check for your app 
Just because a container runs doesn’t mean your service is okay.
Whether you’re in local development or scaling in production, a tiny HEALTHCHECK line in your Dockerfile can save you hours of debugging and nights of firefighting.
So go ahead — make your containers honest.
Docker HEALTHCHECK is:
Bonus tip: Want to auto-restart unhealthy containers?
Add this when running your container:
docker run --restart=on-failure ...La entrada 🩺 Docker HEALTHCHECK: Is Your App Really Alive Inside the Container? se publicó primero en CloudArch.
]]>La entrada Deploy your first computing cloud service se publicó primero en CloudArch.
]]>Let’s imagine you have your service written in Python using Flask (this doesn’t really matter, is just an example and can actually be replicated for every other language).
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World'
if __name__ == '__main__':
app.run()The next thing we would need is to create then a Dockerfile, but why? Well, dockerizing our service will help us to use any of the services available in GCP which can run Docker containers, mainly Cloud Run and Kubernetes. But in this case we will be using just Cloud Run since it will work out of the box and we won’t need to configure any subnetwork neither other services to expose externally our application.
FROM python:3.11
RUN pip install gunicorn
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENV PORT 8080
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:appOnce we have our Dockerfile ready, we will just need to create the image based on that definition containing our service:
$ docker build -t <your_service_name> .Next, make sure you have Compute and Artifact APIs in GCP enabled and create a repository in Artifact Registry where we would push our image that we just created from that Dockerfile.
When we already have the repository created in Artifact Registry, is time to push our image!
# Tagging the image so we can reference it
$ docker tag SOURCE-IMAGE LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE:TAG
$ Pushing the image to the repository
docker push LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE:TAGAfterwards you should see your image in the repository:

Now we are ready to deploy our service! Go to Cloud Run section and create a new service. It’s very important that you give it a meaningful name, since the URL to access it will include that name. Mark the source as “Artifact Registry” and in the select box look for the docker image you just uploaded.
A few good recommendations will be:


If we followed all the previous steps in order, most probably your new instance has already spined up and you have now your service in production! You will be given a dedicated URL using HTTPS and you will see some insightful dashboards to see the metrics of your service

If you want to learn more about Cloud Run and how to optimize your services, don’t hesitate to consult our section where I talk more deeply about this service.
Leave me your comment below!
La entrada Deploy your first computing cloud service se publicó primero en CloudArch.
]]>La entrada Tags en CloudRun: por qué eliminar los que no se usen se publicó primero en CloudArch.
]]>Esperas un poco de tiempo, porque piensas que quizá aún la antigua revisión sigue reportando sus métricas pese a que la nueva ya ha sido desplegada. Pero después de varios minutos ves en la gráfica que siguen habiendo 4 pods vivos. ¿Cómo es posible esto si hemos indicado que queremos entre 2 y 3?
En la pestaña dónde podemos ver todas las revisiones, aparecerá un signo de tick verde en todas las revisiones que estén sirviendo tráfico.

En este caso, podemos ver como las dos revisiones están disponibles, entonces si cada una presenta un mínimo de dos pods disponibles, eso significa que podríamos tener desde 4 pods. Esto puede ser un problema ya que Google Cloud nos cobraría por cada pod, y nosotros solo deseamos tener 2 vivos con la última versión de nuestro servicio. Estaríamos pagando por 2 pods que no se van a usar.
A menudo podemos pensar que es por el tráfico configuardo, ya que podemos configurar un balanceo de la carga sobre nuestras diferentes revisiones. Por ejemplo, podemos asignar un 80% del tráfico a la revisión antigua y sólo un 20% a la última subida a producción. Sin embargo, en algunos casos podemos ver cómo el tráfico está configurado al 100% para una revisión y otra sigue apareciendo como disponible. ¿A qué se debe eso?
Pues bien, cómo buena práctica estás asignando tags a cada una de tus revisiones que vas subiendo para poder identificarlas más tardes por versión (por ejemplo). Sin embargo, no has eliminado los tags de las revisiones que no estabas usando.
Por defecto, Google Cloud mantiene vivas las instancias o pods que tengas en CloudRun con un tag o más asignados. De modo que aunque no reciba tráfico, siempre estará lista para empezar a recibir tráfico si se la configura y conseguir minimizar el tiempo de puesta a punto de un pod.
Si estamos seguros de que no queremos volver a usar una revisión antigua o no nos importa más tiempo de inicio en caso de necesitarla, deberíamos siempre eliminar los tags para asegurarnos de que Google Cloud apaga correctamente ese tag. De ese modo, no seremos facturados por esos recursos que realmente no estamos consumiendo.
¿Alguna vez te has topado con un problema similar? Te leo en los comentarios.
¿Quieres leer más sobre CloudRun? CloudRun
La entrada Tags en CloudRun: por qué eliminar los que no se usen se publicó primero en CloudArch.
]]>La entrada ¿Kubernetes o CloudRun? se publicó primero en CloudArch.
]]>Pues bien, en este artículo os traigo que premisas sigo yo para saber cuál es la mejor opción dependiendo de cada caso en particulas, pues aquí como en todo “no existen balas de plata”.

La disponibilidad de nuestra carga de trabajo es una parte muy importante; ya que dependiendo desde dónde se realicen las peticiones podremos tener mayor o menor latencia, llegando a poder perjudicar a nuestros usuarios finales.
Mientras que Kubernetes, GKE en Google Cloud, nos permite tener el cluster con nodos en diferentes regiones y zonas, cuándo desplegamos un servicio en CloudRun sólo podemos hacerlo en una región en particular. Este problema podría resolverse desplegando dos veces el mismo servicio en dos regiones diferentes y luego balanceando el tráfico con un balanceador de carga, pero esto ya nos presupone un gasto adicional además de más configuración y mantenimiento por nuestra parte.
Kubernetes, definitivamente es la mejor opción para tener gran disponibilidad por múltiples zonas.
Otro punto a tener en cuenta es el número de contenedores vivos, mientras que Kubernetes garantiza que al menos habrá un pod de nuestra aplicación, CloudRun puede escalar a 0 contenedores por falta de tráfico. Esto puede ser perjudicial, pues la siguiente petición que tenga que proveer una respuesta, tardará más tiempo mientras el nodo se provee y se sirve la aplicación.
Ambas opciones ofrecen fuertes sistemas de escalados para garantizar la salud de tu aplicación; sin embargo, en Kubernetes nosotros tenemos que configurar los sitemas de autoescalado mediante Escalados Horizontales o Escalados Verticale, mientras que en CloudRun el escalado es automático en base al tráfico recibido y uso de CPU. Tan sólo tendríamos que indicar cuáles son el mínimo y el máximo de contenedores que deseamos.
CloudRun de manera automática siempre nos garantiza el número de instancias acorde a las demandas del contenedor.
Mientras que Kubernetes siempre tiene un costo mínimo garantizado por el cluster y sus nodos, el precio de CloudRun puede disminuir drásticamente si tenemos poco tráfico y los contenedores minimizan en número hasta 0. Incluso podemos contar con un par de configuraciones que nos permitan ahorrar mucho más dinero como puede ser:
Incluso, debido a la rápida puesta en marcha de CloudRun y la poca configuración que necesita, se podría llegar a automatizar alguna acción que borrase los servicios cuándo no se usasen (por ejemplo, borrar el entorno de desarrollo durante los fines de semana y festivos) y los re-desplegase una vez se necesiten.
Sin embargo, si vamos a hacer un uso extenso computacionalmente hablando, GKE podría llegar a ser una mejor opción a nivel económico.
Para más información sobre los precios, consulta los siguientes enlaces
Aunque es totalmente posible esto en ambos recuros, una vez más con CloudRun es muchísimo más sencillo. Con CloudRun todo es por y para Google Cloud.
En CloudRun bastaría con asignar los permisos y roles necesarios a la Service Account que nuestro servicio de CloudRun está usando, y eso sería todo. Es decir, si queremos acceder a CloudSQL desde nuestra instancia, sólo tendríamos que darle esos permisos, nada más.
Sin embargo, en GKE tendríamos que hacer un binding de la Service Account usada en el cluster con la Service Account en GCP con los permisos necesarios. Esto es un simple paso y se podría automatizar con Helm, pero hay que hacerlo. De lo contrario, nuestras cargas de trabajo no tendrán permisos. Además tenemos que asegurarnos de que nuestros pods están detrás del NAT y accediendo con la IP del cluster, de lo contrario tendríamos que estar añadiendo permisos y excepciones a nivel de firewall por cada IP de cada pod, por no hablar de que estás cambiarían con el tiempo. Una tarea tediosa si no se tiene en cuenta.
En el caso de que algo no funcione bien en nuestras aplicaciones, tanto Kubernetes como CloudRun se encargarán de terminar los pods problemáticos y proporcionar nuevos automáticamente. En el caso de que queramos ver los logs, en ambos recursos podemos tener acceso a todos los logs con Cloud Logging. Pero en el caso de que queramos entrar en algún pod a ver qué está sucediendo, con CloudRun será imposible. No hay modo de acceder a un pod de CloudRun. Con Kubernetes siempre podremos acceder a un pod para su análisis.
De nuevo, CloudRun vuelve a poner muchas más facilidades para exponer un servicio público a internet o para mantenerlo en nuestra red VPC privada. Al desplegar un servicio en CloudRun, este automáticamente tiene asignada una URL con un certificado TLS para poder acceder por HTTPS. Además, la fácil configuración nos permite exigir autenticación para mandar peticiones o incluso exponerla solamente internamente en nuestra VPC. No necesitariamos nada más. La misma URL redirigirá a nuestra instancia de CloudRun y el tráfico se puede dividir entre todas las revisiones de manera sencilla.
Para Kubernetes requerimos cambiar la configuración. Por defecto el servicio asignado es ClusterIP, con lo que no nos permitirá acceder a nuestras cargas de trabajo desde internet. Sin embargo, podemos cambiarlo (e incluso automatizarlo con Helm) para que use otro tipo de servicio y exponer nuestras aplicaciones. O incluso usar un balanceador de carga que redirija el trafíco a los puntos de acceso deseados, aunque en este caso los balanceadores de carga suponen un coste adicional.
Kubernetes o CloudRun
¿Y a ti se te ocurre alguna pauta más a tener en cuenta antes de decidir cuál usar? Déjame en los comentarios tu opinión, te leo.
La entrada ¿Kubernetes o CloudRun? se publicó primero en CloudArch.
]]>La entrada Cloud(ernetes)Run se publicó primero en CloudArch.
]]>
1. Abstracción de Infraestructura:
Cloud Run abstrae la infraestructura subyacente de manera similar a Kubernetes con Knative. Los desarrolladores pueden centrarse en la construcción y despliegue de aplicaciones sin preocuparse por la gestión de servidores o clusters. Esta abstracción permite una mayor portabilidad y flexibilidad, ya que las aplicaciones pueden ejecutarse tanto en entornos locales como en la nube de forma transparente.
2. Escalabilidad Automática:
Al igual que con Knative en Kubernetes, Cloud Run ofrece escalabilidad automática basada en la demanda del tráfico. Las aplicaciones se ejecutan en contenedores y se escalan horizontalmente según el número de solicitudes entrantes. Esto garantiza que las aplicaciones siempre tengan los recursos adecuados para manejar la carga de trabajo, sin necesidad de intervención manual.
3. Gestión de Tráfico Avanzada:
Cloud Run proporciona funcionalidades avanzadas de gestión de tráfico, permitiendo la implementación de versiones múltiples de una aplicación y el enrutamiento flexible del tráfico entre ellas. Esta característica, similar a los canales de tráfico en Knative, facilita la implementación de actualizaciones gradualmente y la realización de pruebas A/B sin interrumpir el servicio principal.
4. Pago por Uso:
Una de las ventajas clave de Cloud Run es su modelo de precios basado en el uso. Los usuarios solo pagan por el tiempo que sus aplicaciones están en ejecución y los recursos que consumen. Esto permite una mayor eficiencia económica, especialmente para aplicaciones con fluctuaciones en la demanda, ya que no se desperdician recursos subutilizados. Mientras que en Kubernetes siempre pagamos por el cluster aunque no esté siendo utilizado.
5. Integración con Ecosistema de GCP:
Cloud Run se integra perfectamente con el ecosistema de servicios de Google Cloud Platform, lo que permite aprovechar funcionalidades adicionales como Cloud Logging, Cloud Monitoring y Cloud IAM. Esto simplifica la gestión operativa y proporciona una visibilidad completa del rendimiento y la salud de las aplicaciones desplegadas en Cloud Run.
Conclusión:
Cloud Run en Google Cloud Platform ofrece una experiencia similar a Kubernetes con Knative, pero con una capa adicional de simplicidad y facilidad de uso. La abstracción de infraestructura, la escalabilidad automática, la gestión de tráfico avanzada, el modelo de precios basado en el uso y la integración con el ecosistema de GCP hacen de Cloud Run una opción atractiva para desarrolladores y equipos de operaciones que buscan una plataforma eficiente y poderosa para ejecutar aplicaciones en la nube. Prácticamente podríamos decir que CloudRun es Kubernetes con una capa de Knative por encima para hacer de un serivicio incluso más sencillo que Kubernetes.
¿Aún necesitas más información? No dudes y visita la documentación oficial de CloudRun proporcionada por Google Clound Platform en https://cloud.google.com/run?hl=es
Si además te has quedado con ganas de indagar también un poco más sobre por qué usar Kubernetes en lugar de CloudRun, no olvides en leerte este artículo dónde explicamos las mayores ventajas de este tipo de componente en sistemas de producción! Desmitificando Kubernetes: Las Ventajas que Hacen Brillar a tus Servicios en Producción
La entrada Cloud(ernetes)Run se publicó primero en CloudArch.
]]>