In Kubernetes, individual probes like liveness, readiness, and startup are mission-critical when deploying applications. Kubernetes uses probes to determine the health of containers in a Pod. Kubernetes may restart Pods because of failing probes. On top of that, Kubernetes uses probes to determine if a particular container can deal with incoming requests. Kubernetes Services will route incoming requests to containers that made it to the Ready state. If a readiness probe is defined on a container, that container must successfully respond to the probe invocation to become Ready.

Custom health probes with Azure Container Apps

In Azure Container Apps, we could not provide custom probes for our containers. But this has changed now! We can provide custom probes for our containers running in Azure Container Apps, and this article will demonstrate how to use them. Before we dive into specifying custom probes for our containers running in Azure Container Apps, let’s quickly revisit the different probe types.

Kubernetes Probes

The startup probe in Kubernetes

The startup-probe is the latest addition to Kubernetes health-probes. If you provide a custom startup-probe, both readiness- and liveness-probe will be delayed until startup-probe has been invoked successfully. You can use a startup probe to prevent Kubernetes from killing a pod (because of failing readiness- or liveness-probe) during startup time.

The Readiness probe in Kubernetes

Kubernetes uses the readiness probe to determine when a container has bootstrapped correctly and can deal with incoming requests. If you’re running multiple containers as part of a Kubernetes pod (sidecar-pattern), the pod will move to state Ready as soon as all containers are Ready. Kubernetes services will start routing traffic to a particular pod when it moves to state Ready. Depending on the actual bootstrap logic of your container, you may want to set an initial delay to prevent Kubernetes from executing the readiness probe. By default, the readiness probe is delayed for 1 second. (See pod.spec.containers.readinessProbe.initialDelaySeconds).

The Liveness probe in Kubernetes

Kubernetes can continuously monitor the health of your container. You typically use the liveness-probe to express if the actual container can process work. Kubernetes invokes the liveness-probe on a customizable interval (See pod.spec.containers.livenessProbe.periodSeconds). If the liveness-probe of a container fails (configurable threshold), Kubernetes will restart the container. There are situations in that restarting a container could resolve issues and keep the application working as expected while developers can investigate and fix the actual root cause. In environments other than Kubernetes, this approach is often called heartbeat.

Probes in Azure Container Apps

At the point of writing this article (March 2022), Azure Container Apps supports http probes for liveness, readiness, and startup. Using the combination of those three probes, we can control how the underlying Kubernetes cluster should handle every single container of our application without even having access to the cluster itself.

Configuring custom probes in Azure Container Apps

From a configuration point of view, an array of probes (ContainerAppProbe[]) can be specified as a property on every container of your application. For demonstration purposes, let’s take thorstenhans/aca-healthprobes:0.0.1 , an existing Http-API that I’ve published on Docker Hub. The API exposes the four endpoints:

  • GET /hello: Always returns HTTP 200 and some JSON as response body
  • GET /healthz/startup: Always returns HTTP 200 (delayed 400 msec)
  • GET /healthz/readiness: Always returns HTTP 200 (delayed 1sec)
  • GET /healthz/liveness: Always returns HTTP 200 (delayed 250msec)

Check my Azure Container Apps sample repository on GitHub and find the 006-custom-probes folder. You’ll find the entire code (Bicep) used to provision the application to Azure Container Apps. For now, let’s focus on defining the probes for our custom container:

containers: [
    {
     image: containerImage
     name: name
     env: envVars
     probes: [
       {
         type: 'liveness'
         initialDelaySeconds: 15
         periodSeconds: 30
         failureThreshold: 3
         timeoutSeconds: 1
         httpGet: {
           port: containerPort
           path: '/healthz/liveness'
         }
       }
       {
         type: 'startup'
         timeoutSeconds: 2
         httpGet: {
           port: containerPort
           path: '/healthz/startup'
         }
       }
       {
        type: 'readiness'
        timeoutSeconds: 3
        failureThreshold: 3
        httpGet: {
          port: containerPort
          path: '/healthz/readiness'
        }
       }
     ]
    }
   ]

If you’ve worked with Kubernetes before, this looks quite familiar 😄. We configure probes in Azure Container Apps precisely the same way we have been doing it in plain Kubernetes for years now. We can configure things like custom delays, individual timeouts, and thresholds for every probe.

The preceding code shows how to configure all available probes in Azure Container Apps using the corresponding endpoints exposed by the sample API. Although I would highly recommend providing probes for all three probe types, it is not mandatory. You can also provide just those probe types that could be processed from your existing workload.

You can deploy the entire sample to your Azure Subscription by running the deploy.sh (also located in 006-custom-probes).

Recap

Seeing more and more concepts from underlying Kubernetes becoming available in Azure Container Apps is excellent. Health-probes are mission-critical for Kubernetes to address self-healing concepts and proper traffic routing capabilities. I’m curious to see how the product team balances highly demanded features like health-probes and the - desired - simplicity of configuring apps when deploying them to Azure Container Apps. The upcoming weeks and months will show how complex real-world deployment manifests for applications in Azure Container Apps will become.