Skip to main content

Implementing Health Checks and Auto-Restarts for FastAPI Applications using Docker


Excerpts from Implementing Health Checks and Auto-Restarts for FastAPI Applications using Docker and… by Jegadeesh N:

Deploying applications can often come with unexpected challenges, and our recent experience with deploying a FastAPI application through Docker was no exception. We encountered a perplexing issue where our application would randomly stop responding, and despite checking the logs, no errors were evident. This story outlines our problem and the solution we implemented to ensure our application remained responsive.

The Problem

Our team was excited to deploy our FastAPI application using Docker. The initial setup went smoothly, and the application was running as expected. However, we soon noticed a troubling pattern: the application would randomly stop responding to requests.

This was particularly frustrating because the logs did not show any errors or warnings that could point us to the root cause of the issue. We tried various debugging techniques, including adding more detailed logging and monitoring the application’s performance metrics. Despite these efforts, the application continued to exhibit the same unresponsive behavior intermittently. This left us puzzled and searching for a more effective solution.

The Solution

After some research and experimentation, we decided to implement a health check mechanism within Docker. Docker’s health check feature allows us to define a command that runs inside the container to test if the application is still functioning correctly. If the health check fails, Docker can automatically restart the container, thereby restoring the application’s responsiveness.

Step 1: Setting Up Your FastAPI Application

First, let’s create a simple FastAPI application. Create a directory for your project and then a Python file named main.py:

from fastapi import FastAPIapp = FastAPI()@app.get("/")def read_root():    return {"Hello": "World"}@app.get("/health")def health_check():    return {"status": "healthy"}

Step 2: Creating a requirement file

Next, we’ll create requirements.txt file and list our depedencies

fastapi==0.111.0

Step 3: Creating a Dockerfile

Next, we’ll create a Dockerfile to containerize our FastAPI application. Create a file named Dockerfile in your project directory:

FROM python:3.11-slimRUN apt-get update && apt-get install -y curlWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .

Step 4: Creating a Docker-Compose File

Docker-Compose allows us to define and manage multi-container Docker applications. Create a file named docker-compose.yml:

version: "3.8"services:  fastapi:    build:      context: .      dockerfile: Dockerfile    ports:      - "8000:8000"    restart: on-failure    command: ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]    healthcheck:      test: curl --fail http://localhost:8000/health || exit 1      interval: 2s      timeout: 5s      retries: 3      start_period: 5s  autoheal:    restart: always    image: willfarrell/autoheal    environment:      - AUTOHEAL_CONTAINER_LABEL=all    volumes:      - /var/run/docker.sock:/var/run/docker.sock
  • build: Specifies the build context and Dockerfile for the fastapi service.
  • context: .: The build context is the current directory.
  • dockerfile: Dockerfile: The Dockerfile to use for building the image.
  • ports: Maps port 8000 on the host to port 8000 in the container.
  • “8000:8000”: This allows access to the FastAPI application running inside the container on port 8000 from the host machine.
  • restart: on-failure: Configures the container to restart only if it exits with a non-zero status (i.e., if it fails).
  • command: Specifies the command to run when the container starts.
  • [“uvicorn”, “main:app”, “ — host”, “0.0.0.0”, “ — port”, “8000”]: Runs the FastAPI application using Uvicorn, binding to all network interfaces (0.0.0.0) on port 8000
  • healthcheck: Defines a health check to monitor the status of the fastapi service.
  • test: curl — fail http://localhost:8000/health || exit 1: Uses curl to check if the /health endpoint returns a successful response. If it fails, the command exits with status 1.
  • interval: 2s: The interval between health checks.
  • timeout: 5s: The time to wait for a health check to complete.
  • retries: 3: The number of consecutive failures needed to consider the container unhealthy.
  • start_period: 5s: The initial period during which the container can start and stabilize before health checks begin.
  • image: willfarrell/autoheal: Uses the willfarrell/autoheal image, which automatically restarts unhealthy containers.
  • AUTOHEAL_CONTAINER_LABEL=all: Configures autoheal to monitor all containers for health status.
  • /var/run/docker.sock:/var/run/docker.sock: This allows the autoheal container to communicate with the Docker daemon on the host, enabling it to restart unhealthy containers.

Step 5: Running Your Application

With everything set up, you can now build and run your application using Docker-Compose:

docker-compose up --build

Docker will build the image, start the container, and continuously monitor its health. If the health check fails, Docker will automatically restart the container.

Conclusion:

By following these steps, you’ve successfully set up health checks and automatic restarts for your FastAPI application using Docker and Docker-Compose. This setup ensures that your application remains resilient and minimizes downtime, enhancing the reliability of your services.

Final Thoughts

Implementing health checks and automatic restarts is a crucial aspect of maintaining a robust production environment. With Docker and Docker-Compose, you can easily monitor and manage the health of your FastAPI applications, ensuring they recover gracefully from failures. Feel free to expand on this setup by adding more services, refining health checks, or integrating with orchestration tools like Kubernetes for even greater reliability and scalability. Happy coding!