容器启动失败。无法在由PORT环境变量定义的端口上启动并侦听。

55

我已经构建好了容器镜像,但是当我尝试使用gcloud命令行或Cloud控制台部署时,出现以下错误:"容器启动失败。无法启动并侦听由PORT环境变量定义的端口。"

12个回答

37
在你的代码中,你可能没有监听传入的HTTP请求,或者你正在监听错误的端口。
或者如果你使用Node.js,你可能没有在你的package.json中设置启动脚本和模块。
根据Cloud Run容器运行时协议的文档,你的容器必须在由Cloud Run定义并在$PORT环境变量中提供的端口上监听传入的HTTP请求。
如果你的容器无法在预期的端口上进行监听,修订版本的健康检查将失败,修订版本将处于错误状态,并且流量将不会路由到它。
例如,在Node.js中使用Express,你应该使用以下代码:
// index.js
const port = process.env.PORT || 8080;
app.listen(port, () => {
  console.log('Hello world listening on port', port);
});



// package.json
    "engines": {
        "node": "16.x"
    },
    "scripts": {
        "start": "node index.js"
    },

在Go语言中:
port := os.Getenv("PORT")
if port == "" {
        port = "8080"
   }
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))

在Python中:
app.run(port=int(os.environ.get("PORT", 8080)),host='0.0.0.0',debug=True)

将“ENV PORT 8080 ENV HOST 0.0.0.0”添加到Dockerfile中不是一个好主意吗?就像这样https://paste.ubuntu.com/p/ccKB5khCyJ/ - LOG_TAG
1
如果我们不使用Express JS,只使用Node JS,那么代码是什么? - LOG_TAG
我们还需要在哪里粘贴这个 express 代码?是 server.js 文件吗?还是可以在 Docker 配置文件中实现?可以参考这个链接:https://scotch.io/tutorials/how-to-deploy-a-node-js-app-to-heroku - LOG_TAG
如何在Vue.js项目中编写此代码?https://github.com/Timtech4u/node-cloud-run-cd/blob/master/index.js 我们需要在config/index.js中找到index.js吗? - LOG_TAG
我应该把这行代码放在Python代码的哪里? app.run(port=int(os.environ.get("PORT", 8080)),host='0.0.0.0',debug=True) - Jefferson Santos
可以在 Dockerfile 中完成这个吗? - JustCurious

7

1
如果您已经在基于ARM的Mac上构建了代码,那么这可以正确地进行交叉编译以适配Cloud Run的linux/amd64环境。 - Zachary Moshansky
1
这就是我所能做的了,谢谢您。 - jsaddwater
1
我用的是Mac M2芯片,这是唯一对我有效的方法! - undefined

3
另一个原因可能是我所观察到的原因之一。Docker镜像可能没有运行应用程序所需的代码。
我有一个使用TypeScript编写的Node应用程序。为了将应用程序docker化,我需要做的就是编译代码 tsc 并运行 docker build,但我认为 gcloud builds submit 将会处理这个并按照 Dockerfile 建议的方式选择已编译的代码,以及.dockerignore文件并构建我的源代码并提交到存储库中。
但它所做的只是复制我的源代码并将其提交到 Cloud Build,然后根据 Dockerfile dockerize 我的源代码而不是已编译的代码。
因此,请记住在 Dockerfile 中包含构建步骤,如果您正在使用需要编译的语言编写源代码。
请注意,启用 Dockerfile 中的构建步骤会增加镜像大小,每次将镜像推送到存储库时都会如此。这会占用存储空间,谷歌公司将向你收取费用。

2
另一个可能性是Docker镜像以需要一定时间才能完成的命令结束。当部署开始时,服务器尚未运行,健康检查将失败。
这种命令通常是在开发模式下运行服务器的任何命令。对于Scala/SBT,它将是“sbt run”,对于Node,它将类似于“npm run dev”。简而言之,请确保仅在打包构建上运行。

1
一个容器启动需要多长时间,你有什么想法吗? - Fr4nc3sc0NL

2
在我的情况下,这只是在应用程序崩溃时发生的,与端口无关。我正确定义了process.env。当错误被抛出时,应该有一个指向日志记录的链接,点击它并先看看那里发生了什么。
编辑:另外,我的应用程序服务器(Fastify)在Docker容器内部不接受任何请求,除非将主机显式设置为0.0.0.0,但在本地使用yarn启动应用程序时可以正常工作。可能听起来很傻,但请确保您的容器在本地表现如预期。

2

我在dockerfile中暴露了一个端口,移除后问题自动解决。Google注入PORT环境变量,因此项目将会使用该环境变量。


1

我们还可以在命令行中指定图像使用的端口号。 如果我们正在使用Cloud Run,可以使用以下命令:

gcloud run deploy --image gcr.io/<PROJECT_ID>/<APP_NAME>:<APP_VERSION> --max-instances=3 --port <PORT_NO>

在哪里

  • <PROJECT_ID> 是项目 ID
  • <APP_NAME> 是应用程序名称
  • <APP_VERSION> 是应用程序版本
  • <PORT_NO> 是端口号

谢谢。这个非常有效! - Mamun
非常欢迎,Mamun。 - Fady Ibrahim

0
可能的解决方案如下:
  1. 本地构建
  2. 将镜像推送到 Google Cloud
  3. 在 Google Run 上部署

使用以下命令:

docker build -t gcr.io/project-name/image-name
docker push gcr.io/project-name/image-name
gcloud run deploy tag-name --image gcr.io/project-name/image-name

0

Cloud Run 会生成默认的 YAML 文件,其中硬编码了默认端口:

spec:
  containerConcurrency: 80
  timeoutSeconds: 300
  containers:
  - image: us.gcr.io/project-test/express-image:1.0
    ports:
    - name: http1
      containerPort: 8080
    resources:
      limits:
        memory: 256Mi
        cpu: 1000m 

所以,我们需要在 yaml 文件中暴露相同的 8080 端口或更改 containerPort,并重新部署。 这里有更多相关资料

0
通常情况下,当您在代码中将Docker镜像连接到Cloud SQL实例的公共IP地址而不是私有IP地址时,就会出现这种情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接