im trying to build docker image with my golang project
I use the following
#build stage
FROM golang:alpine as builder
WORKDIR /go/src/app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o main .
RUN apk add --no-cache git
#final stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /go/bin/app /app
ENTRYPOINT ./app
LABEL Name=fzr-dbc Version=0.0.1
EXPOSE 3000
This build is failing in my main.go file which is looks like following
package main
import (
"fzr-dbc/cmd/tsr”
)
func main() {
tsr.Execute()
}
when I run the command
docker build -t fzr .
The error is:
main.go:4:2: cannot find package "fzr-dbc/cmd/tsr” in any of:
/go/src/app/vendor/fzr-dbc/cmd/tsr (vendor tree)
/usr/local/go/src/fzr-dbc/cmd/tsr (from $GOROOT)
/go/src/fzr-dbc/cmd/tsrs (from $GOPATH)
The error since it’s not finding my project path , what could be missing here ?
The docker file is in my root project fzr and I run the docker build from there
You are running go build in your Dockerfile:
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o main .
This requires you to install all your dependencies for building it.
To fix this, either:
Build the binary on your host and COPY the binary directly into the docker; or,
Install dependencies inside your docker as part of RUN processes:
For Go before 1.11, you need to move your project source code into proper directory in GOPATH. Then, on that folder, run go get -u ./...
For Go 1.11+, you need to use Go 1.11 with go.mod and go.sum properly defined. Then you can use the command go mod download to download all the dependencies to the Go package cache inside your docker image.
Related
I’ve the following docker which works ok, I was able to run it and build it successfully!
FROM golang:1.13.6 AS build-env
ENV GO111MODULE=on
ENV GOOS=linux
ENV CGO_ENABLED=0
RUN mkdir -p /go/src/github.company.corp/deng/fst-cl
WORKDIR /go/src/github.company.corp/deng/fsr-clie
COPY ./ ./
# build the code
RUN go build -v -o ./fsr ./src/cmd/main.go
Now I want to change the image to use lighter docker image such as go alpine
So I change the from and added alpine version and also added git ,however the build is failing for
So go lib which doesn’t happen before the change, any idea what could be missing ?
FROM golang:1.13.6-alpine AS build-env
ENV GO111MODULE=on
ENV GOOS=linux
ENV CGO_ENABLED=0
## git is required to fetch go dependencies
RUN apk add --no-cache ca-certificates git
RUN apk add --no-cache gcc musl-dev
RUN mkdir -p /go/src/github.company.corp/deng/fst-cl
WORKDIR /go/src/github.company.corp/deng/fsr-clie
COPY ./ ./
# build the code
RUN go build -v -o ./fsr ./src/cmd/main.go
The error is for specifid repo which resides on our company git repo, but I don’t understand why its happen on golang:1.13.6-alpine and works ok on golang:1.13.6 ????
Btw I try to use different version of go alpine without success…
This is the error:
get "github.company.corp/deng/logger-ut": found meta tag get.metaImport{Prefix:"github.company.corp/deng/logger-ut", VCS:"git", RepoRoot:"https://github.company.corp/deng/logger-ut.git"} at //github.company.corp/deng/logger-ut?go-get=1
go: github.company.corp/deng/logger-ut#v1.0.0: reading github.company.corp/deng/logger-ut/go.mod at revision v1.0.0: unknown revision v1.0.0
If you want a lighter image and wish to use apline, you can use example below. Your final app image should be something like 7MB on scratch. Adjust it as it fits!
# STAGE 1: prepare
FROM golang:1.13.1-alpine3.10 as prepare
WORKDIR /source
COPY go.mod .
COPY go.sum .
RUN go mod download
# STAGE 2: build
FROM prepare AS build
COPY . .
RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o bin/app -v your/app.go
# STAGE 3: run
FROM scratch as run
COPY --from=build /source/bin/app /app
ENTRYPOINT ["/app"]
I am trying to use CompileDaemon to hot reload a go project using Docker.
My folder structure looks like the below
my-api
- server
- main.go
- Dockerfile
- docker-compose.yml
- Makefile
This is the error I am getting:
go build github.com/firstApi/test-platform/lib/my-api/server: build output "server" already exists and is a directory
This is what my dockerfile looks like
FROM golang:1.12-stretch
ENV GO111MODULE=on
WORKDIR /go/src
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN ["go", "get", "github.com/githubnemo/CompileDaemon"]
RUN go test ./... \
&& CGO_ENABLED=0 go build -v -a -installsuffix cgo -o /main server/main.go
ENTRYPOINT CompileDaemon -log-prefix=false -build="go build ./server" -command="./main"
any ideas what I am doing wrong and what I need to change in order to fix this issue?
UPDATE*****
I tried the solution as suggested by the only answer but I now get the following error:
Could not start command:%!(EXTRA *errors.errorString=can't start command: fork/exec ./server: permission denied)
Your default go build is attempting to output the same name as the directory. You could change your build and ENTRYPOINT line to refer to "go build -o apiserver".
When deploying a simple API with a Docker multi-stage build the following error is being thrown:
$ docker build -t api:latest .
[...]
$ docker run -p 4880:4880 --rm --name=api api:latest
2019/01/29 23:02:15 exec: "go": executable file not found in $PATH
As my application is not calling go from anywhere (or any exec.Command) I ran a go mod vendor so I could check the dependency source code and found the following:
vendor/github.com/lib/pq/oid/gen.go
12: "os/exec"
64: cmd := exec.Command("gofmt")
Could this be the issue and if so how can I fix it? I am sure I have managed to deploy github.com/lib/pq in a multi-stage build before but I am currently stuck.
Many thanks and Happy Hacking.
Dockerfile
FROM golang:1-alpine AS builder
ENV GO111MODULE=on
RUN apk --no-cache add ca-certificates git
WORKDIR /app
# Copy go module info first...
COPY go.mod .
COPY go.sum .
# ...then download to cache dependencies between builds
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -installsuffix cgo -ldflags '-extldflags "-static"' -o api cmd/api/
FROM scratch
WORKDIR /app
COPY --from=builder /app/api /app/
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["./api"]
Your actual build line:
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -installsuffix cgo -ldflags '-extldflags "-static"' -o api cmd/api/
is missing a relative path in front of cmd, making it instead be ./cmd/api will result in a successful build/run. cmd/api is a real thing apparently, https://golang.org/cmd/api/, so it's not erring out, but also not doing what you are expecting it to do. If you type go run cmd/api in your terminal you should see a ton of output unrelated to your application.
I want to use the multi stage build for my gaoling project, when I build the project locally for linux/windows/Mac
I got 12.6 mb of size , I’ve currently small gaoling CLI program.
Now I want to build it with to build from it lightwhigt docker image with the scratch option and build as
I use the following, but when I check the image, I see that the size it 366MB , any idea what am I missing here?
It should be less then 20MB…
#build stage
FROM golang:alpine as builder
WORKDIR /go/src/tzf
ADD . /go/src/tzf
RUN CGO_ENABLED=0 go build -ldflags '-extldflags "-static"' -o ova tzf
RUN apk add --no-cache git
FROM golang:alpine
RUN mkdir /build
ADD . /build/
WORKDIR /build
RUN CGO_ENABLED=0 go build -ldflags '-extldflags "-static"' -o ova tzf
FROM scratch
COPY --from=builder /build/main /app/
WORKDIR /app
CMD [“./ova -v"]
You should use first a golang:alpine container to build the app, then an alpineto run the compiled app.
Something like this:
# builder
FROM golang:alpine AS builder
WORKDIR /go/src/tzf
ADD . /go/src/tzf
RUN CGO_ENABLED=0 go build -ldflags '-extldflags "-static"' -o ova tzf
# runner
FROM alpine
WORKDIR /app
COPY --from=builder /build/main /app/
CMD [“./ova -v"]
should result in a small footprint container.
When you build your final image, be careful to copy only the exact files you want to end up in the image. It makes sense here to make your binary be the ENTRYPOINT of the image, since there's literally nothing else you can do with it.
I might make a two-stage pipeline like so:
# size of this stage doesn't matter; use the standard image
FROM golang AS builder
WORKDIR /go/src/tzf
ADD . ./
RUN CGO_ENABLED=0 go build -ldflags '-extldflags "-static"' -o /ova tzf
FROM scratch
# only copy the one file, may as well put it in /
COPY --from=builder /ova /ova
ENTRYPOINT ["/ova"]
# if you want to launch it with default options, you can
# CMD ["-v"]
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.
Copy project files to /go/src/myapp.
Set Working directory to /go/src/myapp.
Install dependencies, I used go get but replace it with which ever dependency management tool you are using.
Install/build the binary.
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
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
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"]