【问题标题】:How correctly to run golang application in docker?如何在 docker 中正确运行 golang 应用程序?
【发布时间】:2019-03-11 13:43:32
【问题描述】:

我在 Windows 10 中开发了 Golang 应用程序。在我的本地机器上它运行良好。我将源代码删除到具有 Docker 的远程 CentOS 服务器。现在我正在尝试在 Docker 中运行这个应用程序。

我在 ma​​in.go 文件所在的同一文件夹中创建了 Dockerfile

- questionnaire
    - database
    - routes
    - utils
    - models
    - controllers
      main.go
      Dockerfile

Dockerfile 看起来像这样:

FROM golang:1.12

RUN go get github.com/gorilla/mux && \
  go get github.com/gorilla/handlers && \
  go get github.com/lib/pq && \
  go get github.com/joho/godotenv && \
  go get github.com/jinzhu/gorm && \
  go get github.com/go-goracle/goracle

COPY / ./

EXPOSE 8000

CMD ["go", "run", "main.go"]

我的 ma​​in.go 文件看起来很简单:

package main

import (
  "github.com/gorilla/handlers"
  "github.com/gorilla/mux"
  "github.com/joho/godotenv"
  "log"
  "net/http"
  "questionnaire/database"
  "questionnaire/routes"
  "questionnaire/utils"
)

func main()  {
  err := godotenv.Load(".env")
  if err != nil {
    panic(err)
  }

  database.ConnectOracle()
  defer database.DisconnectOracle()

  router := mux.NewRouter()

  headers := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"})
  methods := handlers.AllowedMethods([]string{"GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"})
  origins := handlers.AllowedOrigins([]string{"*"})

  router.StrictSlash(true)

  routes.Handle(router)

  port := utils.CheckEnvironmentVariable("APPLICATION_PORT")

  log.Printf("RESTful web service is running on %s port.", port)

  log.Fatal(http.ListenAndServe(":" + port, handlers.CORS(headers, methods, origins)(router)))
}

我成功创建了 Docker Image 但创建 Docker 容器时出现错误:

main.go:9:2: cannot find package "questionnaire/database" in any of:
        /usr/local/go/src/questionnaire/database (from $GOROOT)
        /go/src/questionnaire/database (from $GOPATH)
main.go:10:2: cannot find package "questionnaire/routes" in any of:
        /usr/local/go/src/questionnaire/routes (from $GOROOT)
        /go/src/questionnaire/routes (from $GOPATH)
main.go:11:2: cannot find package "questionnaire/utils" in any of:
        /usr/local/go/src/questionnaire/utils (from $GOROOT)
        /go/src/questionnaire/utils (from $GOPATH)

谁能告诉我如何解决这个问题?

我还尝试通过下一个 Dockerfile 在 Docker 中构建 golang 应用程序的二进制文件,但错误消息是相同的 RUN go build 命令:

FROM golang:1.12

RUN go get github.com/gorilla/mux && \
  go get github.com/gorilla/handlers && \
  go get github.com/lib/pq && \
  go get github.com/joho/godotenv && \
  go get github.com/jinzhu/gorm && \
  go get gopkg.in/goracle.v2

ADD . /go/src/questionnaire

WORKDIR /go/src/questionnaire

RUN go build -o /bin questionnaire

ENV PORT=8000

CMD ["/bin"]

【问题讨论】:

  • 不要使用相对导入。
  • Relative imports in Go的可能重复
  • @Flimzy 你好!为什么你认为这篇文章是重复的?这是不同的问题;(
  • 这一行:RUN go build -o /bin questionnaire 对我来说似乎不是一个好主意,大多数(如果不是全部)Linux 在文件系统的根目录下都有一个名为 bin 的文件夹。该文件夹包含机器按预期运行可能需要的一堆二进制文件。通过用你的应用程序的二进制文件覆盖该文件夹,你会让自己头疼,我想......我还没有尝试过,所以我不能肯定......无论哪种方式我都建议你将你的二进制文件重命名为与现有文件/文件夹不冲突的东西或...
  • ...保留名称,但将其移动到尚未使用该名称的子文件夹中。

标签: docker go


【解决方案1】:

main.go 文件中的导入指定:

"questionnaire/database" "questionnaire/routes" "questionnaire/utils"

这意味着 go 编译器正在寻找 $GOPATH/questionnaire$GOROOT/questionnaire 中的那些包。您必须确保将它们复制到您正在构建的 docker 映像中的正确位置。

golang:1.12 图像中的默认 $GOPATH 是 /go。确保您的问卷包正确放置在 docker 镜像内的/go/src 目录中。

关于 Dockerfile: 为 Go 应用程序构建/部署 Docker 映像时的一个常见策略是使用构建器模式(参见下面的示例 Dockerfile)。它的要点是创建一个多阶段 Dockerfile,其中第一阶段构建 go 可执行文件,第二阶段运行它。这意味着您可以在第一阶段隔离所有依赖项,并在最后得到一个非常小的整体图像。

它可能看起来像这样:

FROM golang:1.11-alpine AS builder

########
# Prep
########

# add the source
COPY . /go/src/questionnaire
WORKDIR /go/src/questionnaire/

########
# Build Go Wrapper
########

# Install go dependencies
RUN go get github.com/gorilla/mux && \
  go get github.com/gorilla/handlers && \
  go get github.com/lib/pq && \
  go get github.com/joho/godotenv && \
  go get github.com/jinzhu/gorm && \
  go get github.com/go-goracle/goracle

#build the go app
RUN GOOS=linux GOARCH=amd64 go build -o ./questionnaire ./main.go

########
# Package into runtime image
########
FROM alpine

# copy the executable from the builder image
COPY --from=builder /go/src/questionnaire .

ENTRYPOINT ["/questionnaire"]

EXPOSE 8080

希望这会有所帮助!

(已编辑以反映下面的 cmets)

【讨论】:

  • “看起来数据库、路由和实用程序是与 main.go 位于同一文件夹中的文件。” 它们不是文件,它们是文件夹。而且它们也是有效的软件包,因为正如第一段中的 OP 所述,该应用程序在其本地计算机上运行良好。如果这些是文件,应用程序将无法使用这些导入进行编译。
  • mkopriva 是对的! databaseroutesutils 是文件夹(包)。在它们里面我有不同的.go 文件。正如我所看到的,您使用多阶段构建。事实上我使用Docker version 17.03.2-ce, build f5ec1e2。该版本不支持多阶段构建。
  • 我的错!我肯定误读了。我已经相应地更新了我的回复。您的应用程序的文件夹和包结构看起来不错 - 我怀疑问卷包没有被添加到 docker 映像中的 GOPATH
  • 对于多阶段构建,如果您的版本不支持它,您可以忽略它 - 我认为确保将文件添加到 $GOPATH 应该可以解决您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-07
  • 2017-10-21
  • 2016-10-25
  • 1970-01-01
  • 2023-03-16
相关资源
最近更新 更多