Reputation: 1017
I have an issue with a multi-stage build where the binary that is being built in stage one is properly copied to stage 2, but when you try and run it the executable cannot be found.
The dockerfile is:
FROM golang as goimage
ENV SRC=/go/src/
RUN mkdir -p /go/src/
WORKDIR /go/src/go_docker
RUN git clone https://github.com/bryonbaker/simple-microservice.git /go/src/go_docker/ \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64
RUN go get github.com/gorilla/mux
RUN go build -o bin/go_docker
FROM alpine:latest AS microservice
RUN apk --no-cache add bash
ENV WORK_DIR=/docker/bin
WORKDIR $WORK_DIR
COPY --from=goimage /go/src/go_docker/bin/ ./
# Put a container-image version identifier in the root directory.
ARG VERSION=1.0
RUN echo $VERSION > image_version
EXPOSE 10000
#CMD ["go_docker"]
The result is:
$ docker run -ti -p 80:10000 go-docker:latest
/docker/bin # lsgo_docker image_version
/docker/bin # ./go_docker /bin/sh: ./go_docker: not found
/docker/bin #
If I run the binary from the intermediate goimage container that is built then it runs fine. The file sizes match...
NOTE: In this dockerfile I have commented out CMD and am testing via a shell. If you uncomment the CMD you get the same problem:
docker run go-docker:latest docker: Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused "exec: \"go_docker\": executable file not found in $PATH": unknown. ERRO[0001] error waiting for container: context canceled
I have made the test code in the git repo public if you want to look at it.
Thanks in advance
Upvotes: 2
Views: 3873
Reputation: 160073
You will get this error pretty much universally on Linux if a binary's shared libraries aren't available. (In your debug shell, try running ldd /docker/bin/go_docker
.)
You probably aren't expecting a dynamically-linked binary, but you're getting one because shell and environment variables don't carry across between RUN
commands. Where you set CGO_ENABLED=0
at the end of a RUN
step, that value gets lost when the actual go build
runs two steps later.
(I'd also clean up the Dockerfile a little bit: things like paths inside the containers don't need to be variables, and it's totally fine to use system paths for things.)
This leaves us with:
FROM golang as goimage
# Use standard $GOPATH layout?
# WORKDIR /go/src/github.com/byronbaker/simple-microservice
# COPY . .
# RUN go get .
# RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install .
# !!! Docker layer caching will not repeat this step if the repo changes
# !!! You won't be able to build a test copy of your uncommitted code
RUN git clone https://github.com/bryonbaker/simple-microservice.git /go/src/go_docker
RUN go get github.com/gorilla/mux
# vvv Put magic environment variables in this line
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install go_docker
# ^^^
# Runtime image
FROM alpine:latest
COPY --from=goimage /go/bin/go_docker /bin/go_docker
ARG VERSION=1.0
RUN echo $VERSION > /image_version
EXPOSE 10000
CMD ["go_docker"]
Upvotes: 2