使用Go应用构建Docker:找不到软件包

I have my Dockerfile in the root of directory with src/myapp folder, myapp contains myapp.go with main package.

Dockerfile looks like following:

FROM golang:1.9.2

ADD . /
RUN go build myapp;

ENTRYPOINT ["/go/bin/myapp"]

I get following error:

can't load package: package myapp: cannot find package "myapp" in any of:
    /usr/local/go/src/myapp (from $GOROOT)
    /go/src/myapp (from $GOPATH)

What am I doing wrong? Can I log ls command after docker has done ADD?

You are copying all the files to Image root directory, Didn't installed any dependencies, Trying to Build it and then run the binary from /go/bin/app. The binary doesn't exists in that directory and it's generating errors.

I would recommend using a Dockerfile like this,

FROM golang:1.9.2 
ADD . /go/src/myapp
WORKDIR /go/src/myapp
RUN go get myapp
RUN go install
ENTRYPOINT ["/go/bin/myapp"]

This'll do the following.

  1. Copy project files to /go/src/myapp.
  2. Set Working directory to /go/src/myapp.
  3. Install dependencies, I used go get but replace it with which ever dependency management tool you are using.
  4. Install/build the binary.
  5. Set entry point.

You can run ls or any other command using docker exec.

Example:

docker exec <image name/hash> ls

You can also enter the shell in the generated image to understand it well using

docker run --rm -it <image hash/name> /bin/sh

myapp needs to be in /go/src/myapp as suggested, or in /usr/local/go/src/myapp. You can add it in ADD section.

If the objective is to create a container that simply runs your binary, I would take different approach.

First build the binary for linux:

GOOS=linux CGO_ENABLED=0 go build -a -installsuffix cgo

Then build a lightweight docker image from scratch:

FROM scratch
COPY myApp 
CMD ["/myApp"]

After experiments I've come to this way of building Golang apps.

This way has several advantages:

  • dependencies are installed on build stage

  • if you need you may uncomment test options

  • build first fully-functional image about 800 MB

  • copies your program to an fresh empty image and produces very small image about 10 MB

Dockerfile:

# Two-stage build:
#    first  FROM prepares a binary file in full environment ~780MB
#    second FROM takes only binary file ~10MB

FROM golang:1.9 AS builder

RUN go version

COPY . "/go/src/github.com/your-login/your-project"
WORKDIR "/go/src/github.com/your-login/your-project"

#RUN go get -v -t  .
RUN set -x && \
    #go get github.com/2tvenom/go-test-teamcity && \  
    go get github.com/golang/dep/cmd/dep && \
    dep ensure -v

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build  -o /your-app

CMD ["/your-app"]

EXPOSE 8000



#########
# second stage to obtain a very small image
FROM scratch

COPY --from=builder /your-app .

EXPOSE 8000

CMD ["/your-app"]

For go 1.11 , you can use go module, the following is example

FROM alpine AS base
RUN apk add --no-cache curl wget

FROM golang:1.11 AS go-builder
WORKDIR /go/app
COPY . /go/app
RUN GO111MODULE=on  CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /go/app/main /go/app/cmd/myapp/main.go

FROM base
COPY --from=go-builder /go/app/main /main
CMD ["/main"]

The official docs suggests the following Dockerfile:

FROM golang:1.8

WORKDIR /go/src/app
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]

Please, visit https://hub.docker.com/_/golang for more info