У меня есть проблема с многоэтапной сборкой, когда двоичный файл, который создается на первом этапе, правильно копируется на этап 2, но когда вы пытаетесь запустить его, исполняемый файл не может быть найден.
Докерфайл это:
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"]
Результат:
$ 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 #
Если я запускаю двоичный файл из созданного промежуточного контейнера goimage, он работает нормально. Размеры файлов совпадают...
ПРИМЕЧАНИЕ. В этом файле докеров я закомментировал CMD и тестирую через оболочку. Если вы раскомментируете CMD, вы получите ту же проблему:
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
Я сделал тестовый код общедоступным в репозитории git, если вы хотите его посмотреть.
заранее спасибо
Могу ли я предложить более конкретное название? например «Программа go отсутствует в многоэтапной сборке dockerfile»


Вы получите эту ошибку почти повсеместно в Linux, если общие библиотеки двоичного файла недоступны. (В отладочной оболочке попробуйте запустить ldd /docker/bin/go_docker.)
Вы, вероятно, не ожидаете динамически связанный двоичный файл, но вы его получите, потому что переменные оболочки и среды не переносятся между RUN командами. Когда вы устанавливаете CGO_ENABLED=0 в конце шага RUN, это значение теряется, когда фактическое go build выполняется двумя шагами позже.
(Я бы также немного подчистил Dockerfile: такие вещи, как пути внутри контейнеров, не обязательно должны быть переменными, и совершенно нормально использовать системные пути для вещей.)
Это оставляет нам:
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"]
Хороший! Я совсем забыл про "установить". Можете ли вы объяснить, почему установка переменных среды позже теряется? Я думал, что эта проблема возникла только после FROM.
Каждая команда RUN запускается в новой оболочке в новом контейнере. Вы можете поиграть с такими вещами, как RUN export ..., и увидеть, что это не имеет никакого эффекта. ENV будет сохраняться между слоями и отображаться в средах RUN команд (и будет сбрасываться при запуске FROM нового изображения).
Не могли бы вы включить команду, которую вы используете для создания этого образа?