Google Cloud Run: Container Fails to Start and Listen on Specified Port Despite Local Success
06:01 31 Oct 2024

Problem

I'm deploying a FastAPI app with Uvicorn on Google Cloud Run. The app runs fine locally, but on Cloud Run, the deployment fails with the error:

Revision 'chat-api-00001-mcn' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable within the allocated timeout.

Details

1. Environment:

  • Container: Python 3.10 on Debian Bookworm.
  • Application: FastAPI app running via Uvicorn, using Google Cloud Storage and an OpenAI API key.
  • Credentials: Google Cloud Storage requires service account credentials via JSON key file, which I have set up as a Google Secret.
  • Dockerfile: I've configured the Dockerfile to expose port 8080 as expected by Cloud Run, and I use $PORT in the CMD command:

2. dockerfile

# Use a newer Debian version that includes SQLite > 3.35
FROM python:3.10-bookworm

# Install dependencies
RUN apt-get update && apt-get install -y wget build-essential libsqlite3-dev
RUN wget https://www.sqlite.org/2023/sqlite-autoconf-3410200.tar.gz && \
    tar xzf sqlite-autoconf-3410200.tar.gz && \
    cd sqlite-autoconf-3410200 && \
    ./configure && make && make install && \
    cd .. && rm -rf sqlite-autoconf-3410200*

# Set up app files and dependencies
COPY requirements.txt /chatbot/requirements.txt
COPY app /chatbot/app
WORKDIR /chatbot
RUN pip install --upgrade pip && pip install -r requirements.txt

# Expose port for Cloud Run
EXPOSE 8080
CMD ["sh", "-c", "uvicorn app.chat_api:app --host 0.0.0.0 --port $PORT"]

3. Environment Variable Setup:

  • OPENAI_API_KEY and GOOGLE_APPLICATION_CREDENTIALS are set in the deployment command.
  • GOOGLE_APPLICATION_CREDENTIALS points to a secret mounted by Cloud Run.

4. Local Tests:

  • Goal: To ensure the Dockerized FastAPI app runs correctly before deployment.
  • Result: The container works as expected when run locally with docker run -p 8080:8080. API requests return expected responses without any errors.
docker run -p 8080:8080 \
  -e PORT=8080 \
  -e OPENAI_API_KEY="my_openai_api_key" \
  -e GOOGLE_APPLICATION_CREDENTIALS='/app/credentials.json' \
  -v '/path/to/local/credentials.json:/app/credentials.json' \
  europe-west1-docker.pkg.dev/chatbot/chatbot-api-repo/chatbot-api:0.3

5. Deployment Attempts:

  • Attempt #1: Set PORT=8080 and confirmed it matches the exposed port. Used --update-secrets to load Google credentials from a secret.
  • Attempt #2: Changed the path in the application to /secrets/chatbot-key, which is the correct path for Cloud Run secrets.
  • Attempt #3: Updated Dockerfile explicitly to use port 8080, but the error persists.

6. Logs:

The Cloud Run logs indicate a FileNotFoundError related to the Google credentials file, even though it exists and is specified in --update-secrets.

Question

Why does the container fail to start on Cloud Run with a port or credential error, even though it works perfectly locally? Could there be an issue with how Cloud Run handles port exposure or secrets mounting that I might be overlooking?

Any insights on solving this Cloud Run deployment issue would be appreciated!

python-3.x dockerfile google-cloud-storage fastapi google-cloud-run