运行 Shutit 的 Cloud Run Flask API 容器进入睡眠循环

ala*_*nah 6 python flask docker google-cloud-platform google-cloud-run

这个问题最近出现了,之前健康的容器现在在创建 shutdown 会话时进入睡眠循环。该问题仅发生在 Cloud Run 上,而不是本地。

最小可重现代码:

requirements.txt

Flask==2.0.1
gunicorn==20.1.0
shutit
Run Code Online (Sandbox Code Playgroud)

Dockerfile

FROM python:3.9

# Allow statements and log messages to immediately appear in the Cloud Run logs
ENV PYTHONUNBUFFERED True

COPY requirements.txt ./
RUN pip install -r requirements.txt

# Copy local code to the container image.
ENV APP_HOME /myapp
WORKDIR $APP_HOME
COPY . ./

CMD exec gunicorn \
 --bind :$PORT \
 --worker-class "sync" \
 --workers 1 \
 --threads 1 \
 --timeout 0 \
 main:app
Run Code Online (Sandbox Code Playgroud)

main.py

Flask==2.0.1
gunicorn==20.1.0
shutit
Run Code Online (Sandbox Code Playgroud)

cloudbuild.yaml

FROM python:3.9

# Allow statements and log messages to immediately appear in the Cloud Run logs
ENV PYTHONUNBUFFERED True

COPY requirements.txt ./
RUN pip install -r requirements.txt

# Copy local code to the container image.
ENV APP_HOME /myapp
WORKDIR $APP_HOME
COPY . ./

CMD exec gunicorn \
 --bind :$PORT \
 --worker-class "sync" \
 --workers 1 \
 --threads 1 \
 --timeout 0 \
 main:app
Run Code Online (Sandbox Code Playgroud)

循环的云运行日志:

Setting up prompt
In session: host_child, trying to send: export PS1_ORIGIN_ENV=$PS1 && PS1='OR''IGIN_ENV:rkkfQQ2y# ' && PROMPT_COMMAND='sleep .05||sleep 1'
================================================================================
Sending>>> export PS1_ORIGIN_ENV=$PS1 && PS1='OR''IGIN_ENV:rkkfQQ2y# ' && PROMPT_COMMAND='sleep .05||sleep 1'<<<, expecting>>>['\r\nORIGIN_ENV:rkkfQQ2y# ']<<<
Sending in pexpect session (68242035994000): export PS1_ORIGIN_ENV=$PS1 && PS1='OR''IGIN_ENV:rkkfQQ2y# ' && PROMPT_COMMAND='sleep .05||sleep 1'
Expecting: ['\r\nORIGIN_ENV:rkkfQQ2y# ']
export PS1_ORIGIN_ENV=$PS1 && PS1='OR''IGIN_ENV:rkkfQQ2y# ' && PROMPT_COMMAND='sleep .05||sleep 1'
root@localhost:/myapp# export PS1_ORIGIN_ENV=$PS1 && PS1='OR''IGIN_ENV:rkkfQQ2y# ' && PROMPT_COMMAND='sleep .05||sleep 1'
Stopped sleep .05
Stopped sleep 1
pexpect: buffer: b'' before: b'cm9vdEBsb2NhbGhvc3Q6L3B1YnN1YiMgIGV4cx' after: b'DQpPUklHSU5fRU5WOnJra2ZRUTJ5IyA='
Resetting default expect to: ORIGIN_ENV:rkkfQQ2y# 
In session: host_child, trying to send: stty cols 65535
================================================================================
Sending>>> stty cols 65535<<<, expecting>>>ORIGIN_ENV:rkkfQQ2y# <<<
Sending in pexpect session (68242035994000): stty cols 65535
Expecting: ORIGIN_ENV:rkkfQQ2y# 
ORIGIN_ENV:rkkfQQ2y# stty cols 65535
stty cols 65535
Stopped stty cols 65535
Stopped sleep .05
Stopped sleep 1
Run Code Online (Sandbox Code Playgroud)

尝试过的解决方法:

  • 不同地区:一些欧洲(1 级和 2 级)、亚洲、美国。
  • 使用 docker 而不是 kaniko 构建
  • 分配给容器的CPU和内存不同
  • 最小容器数量 1-5(以确保 CPU 始终分配给容器)
  • --no-cpu-throttling也没有什么区别
  • 最大容器数量 1-30
  • 不同的GCP项目
  • 不同的 Docker 基础镜像(3.5-3.9 + 从一年前到最近的各种 shas)

Pri*_*dra 2

我已经重现了您的问题,并且我们讨论了几种可能性,我认为问题是您的 Cloud Run 无法处理请求,因此准备关闭(sigterm)。\n我列出了一些可能性供您查看和分析。

\n
    \n
  • Cloud Run 服务无法启动的一个很好的原因是容器内的\n服务器进程被配置为侦听\nlocalhost (127.0.0.1) 地址。指环回网络接口,该接口无法从容器外部访问,因此无法进行Cloud Run健康检查,导致服务部署失败。要解决此问题,请配置您的应用程序以启动 HTTP 服务器以侦听所有网络接口(通常表示为 0.0.0.0)。

    \n
  • \n
  • 在搜索您遇到的云日志错误时,我\n发现了这个答案和来自shutit库\n开发者的GitHub链接,它指出了一种在shutit会话中跟踪复杂容器构建中的输入和输出的技术。来自 GitHub 链接的一个很好的发现,我认为您必须传递您未在 main.py 文件中指定的session_type\ninshutit.create_session(\xe2\x80\x98bash\xe2\x80\x99)或\n。shutit.create_session(\xe2\x80\x98docker\xe2\x80\x99)这可能是\n您的 shutdown 会话失败的原因。

    \n
  • \n
  • 此外,此问题可能是由于此 shutdownit 库使用的某些 Linux 内核功能造成的,而 gVisor 目前未正确支持该功能。我不确定第一次是如何为您执行的。\n 大多数应用程序都可以正常运行,或者至少在常规 Docker 中运行良好,但可能无法提供 100% 的兼容性。

    \n

    Cloud Run 应用程序在 gVisor 容器沙盒(当前仅支持 Linux)上运行,该沙盒执行您的应用程序在用户空间中进行的 Linux 内核系统调用。gVisor 不实现所有\n系统调用(请参阅此处)。从这个Github 链接来看,\xe2\x80\x9c如果你的\n应用程序有这样的系统调用(非常罕见),它将无法在 Cloud\nRun 上运行。此类事件会被记录下来,您可以使用strace \n确定您的应用\xe2\x80\x9d 中何时进行系统调用

    \n

    如果您在 Linux 上运行代码,请安装并启用 strace:\nsudo apt-get install strace通过在常用调用前加上 strace -f 来运行您的应用程序,其中 -f 表示跟踪所有子线程。例如,如果您通常使用\n调用应用程序./main,则可以通过调用 strace 来运行它/usr/bin/strace -f ./main

    \n

    根据本文档,\xe2\x80\x9c 如果您认为问题是由容器沙箱中的限制引起的。在 GCP Console 的 Cloud Logging 部分(而不是 Cloud Run 部分的“日志”选项卡中),\n您可以在日志中查找\n严重性Container Sandbox或使用日志查询:DEBUGvarlog/system

    \n
  • \n
\n
\n
resource.type="cloud_run_revision"\nlogName="projects/PROJECT_ID/logs/run.googleapis.com%2Fvarlog%2Fsystem"\n
Run Code Online (Sandbox Code Playgroud)\n
\n
\n

例如:容器沙箱:不支持的系统调用
\nsetsockopt(0x3,0x1,0x6,0xc0000753d0,0x4,0x0)\xe2\x80\x9d

\n
\n

默认情况下,容器实例的最小实例数处于关闭状态,设置为 0。我们可以使用 Cloud Console、gcloud 命令行或 YAML 文件来更改此默认设置,方法是指定要保温的最小容器实例数并准备好满足请求。

\n

您还可以查看此文档GitHub 链接,其中讨论了 Cloud Run 容器运行时行为和故障排除以供参考。

\n