1

我正在尝试在 Google Cloud Run 上使用 Docker 运行 Go 应用程序,但出现此错误:

Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Logs for this revision might contain more information.

我将端口修复8080为文档中所述,但我认为我的 Dockerfile 不正确。有谁知道我错过了什么?

FROM golang:1.12-alpine

RUN apk upgrade -U \
  && apk add \
  ca-certificates \
  git \
  libva-intel-driver \
  make \
  && rm -rf /var/cache/*

ENV GOOS linux
ENV GOARCH amd64
ENV CGO_ENABLED=0
ENV GOFLAGS "-ldflags=-w -ldflags=-s"
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN echo $PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
RUN go get -u github.com/cespare/reflex
# RUN reflex -h 
# Setup modules after reflex install
ENV GO111MODULE=on \
  GOFLAGS="$GOFLAGS -mod=vendor"

WORKDIR /go/src/bitbucket.org/team/app/

COPY . .

CMD [ "go", "run", "cmd/main.go" ]
4

2 回答 2

7

Dockerfiles 不会让你的应用程序监听特定的端口号。

Dockerfile 中的EXPOSE指令纯粹是一个文档,没有任何功能。

Go 应用程序有 2 个选项:

  1. 只需重构您的代码以读取PORTenv 变量:os.Getenv("PORT")并在您开始的 HTTP 服务器地址上使用它:

    port := os.Getenv("PORT")
    http.ListenAndServe(":"+port)
    
  2. 创建一个-port标志并在 Dockerfile 中的应用程序入口点期间读取它:

    例如,如果您可以go run main.go -port=8080工作,请将您的 dockerfile 更改为:

    exec go run main.go -port=$PORT
    

这些会让你得到你想要的。

理想情况下,您不应go run在容器内使用。做就是了:

RUN go build -o /bin/my-app ./my/pkg
ENTRYPOINT /bin/my-app

编译一个 Go 程序并直接使用它。否则,每次Cloud Run启动您的容器时,您都会从头开始重新编译它,这并不快,这会增加您的冷启动时间。


除了这些之外,您的 dockerfile 中似乎还有很多不一致之处。您设置了很多 Go env var,例如 GOOS GOARCH,但实际上并没有go build您的应用程序(go run我相信它是一个即时编译,并且没有考虑 GOFLAGS 中的链接器标志)。查看示例 Go dockerfiles 以更好地了解如何编写惯用的 Go dockerfiles。

于 2019-05-10T16:45:35.960 回答
0

您的 Dockerfile 中似乎缺少EXPOSE。请参阅https://docs.docker.com/engine/reference/builder/#expose

于 2019-05-10T10:26:18.410 回答