如何在Docker中正确运行Golang应用程序?

如何在Docker中正确运行Golang应用程序?

问题描述:

I developed Golang application in Windows 10. In my local machine it works fine. I remove source code to remote CentOS server which has Docker. Right now I am trying to run this application in Docker.

I created Dockerfile in the same folder where located main.go file.

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

Dockerfile looks like this:

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"]

My main.go file looks pretty simple:

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)))
}

I successfully created Docker Image but I have error when created Docker Container:

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)

Can anyone say how to fix this problem?

I also tried to build binary of golang application inside Docker by next Dockerfile but error message was the same RUN go build command:

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"]

The imports in your main.go file specify:

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

This means the go compiler is looking for those packages in $GOPATH/questionnaire and $GOROOT/questionnaire. You have to make sure those are copied into the correct place inside the docker image you are building.

The default $GOPATH inside that golang:1.12 image is /go. Make sure your questionnaire package is correctly placed in the /go/src directory inside the docker image.

As for the Dockerfile: A common strategy when building / deploying Docker images for go apps is to use a builder pattern (see example Dockerfile below). The gist of it is to create a multi-stage Dockerfile, where the first stage builds the go executable, and the second stage runs it. This means you can isolate all of your dependencies in the first stage, and end up with a very small overall image at the end.

It might look something like this:

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

Hope this helps!

(edited to reflect the comments below)