ปัญหาเกี่ยวกับการสร้างหลายขั้นตอนของ Docker

ฉันมีปัญหากับบิลด์แบบหลายสเตจที่ไบนารี่ที่สร้างขึ้นในสเตจที่ 1 ถูกคัดลอกไปยังสเตจ 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: ล่าสุด
/docker/bin # ls

go_docker image_version
/docker/bin # ./go_docker /bin/sh: ./go_docker: ไม่พบ
/docker/bin #

ถ้าฉันเรียกใช้ไบนารี่จากคอนเทนเนอร์ goimage ระดับกลางที่สร้างขึ้น มันก็จะทำงานได้ดี ขนาดไฟล์ตรงกัน...

หมายเหตุ: ใน dockerfile นี้ ฉันได้ใส่ความคิดเห็นเกี่ยวกับ CMD และกำลังทดสอบผ่านเชลล์ หากคุณไม่ใส่ข้อคิดเห็น CMD คุณจะประสบปัญหาเดียวกัน:

นักเทียบท่ารัน go-docker: นักเทียบท่าล่าสุด: การตอบสนองข้อผิดพลาดจาก daemon: การสร้างรันไทม์ OCI ล้มเหลว: container_linux.go:344: การเริ่มต้นกระบวนการคอนเทนเนอร์ทำให้เกิด "exec: \"go_docker\": ไม่พบไฟล์ปฏิบัติการใน $PATH": ไม่ทราบ ข้อผิดพลาด ERRO[0001] กำลังรอคอนเทนเนอร์: บริบทถูกยกเลิก

ฉันได้สร้างโค้ดทดสอบใน git repo สู่สาธารณะแล้วหากคุณต้องการดู

ขอบคุณล่วงหน้า


person Bryon    schedule 09.05.2019    source แหล่งที่มา
comment
โปรดคำนึงถึงคำสั่งที่คุณใช้สร้างอิมเมจนี้ด้วย   -  person ctt    schedule 09.05.2019
comment
ฉันขอแนะนำชื่อที่เฉพาะเจาะจงกว่านี้ได้ไหม เช่น. โปรแกรม go หายไปใน build dockerfile แบบหลายขั้นตอน   -  person kristianp    schedule 06.08.2019


คำตอบ (1)


คุณจะได้รับข้อผิดพลาดนี้ในระดับสากลบน 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"]
person David Maze    schedule 09.05.2019
comment
ทำได้ดีนี่! ฉันลืมเรื่องการติดตั้งไปเลย คุณช่วยอธิบายได้ไหมว่าทำไมการตั้งค่าตัวแปรสภาพแวดล้อมจึงหายไปในภายหลัง ฉันคิดว่าปัญหานั้นเกิดขึ้นหลังจาก FROM เท่านั้น - person Bryon; 09.05.2019
comment
คำสั่ง RUN แต่ละคำสั่งทำงานในเชลล์ใหม่ในคอนเทนเนอร์ใหม่ คุณสามารถเล่นกับสิ่งต่าง ๆ เช่น RUN export ... และดูว่ามันไม่มีผลกระทบใด ๆ ENV จะยังคงอยู่ในเลเยอร์และแสดงในสภาพแวดล้อมของคำสั่ง RUN (และจะถูกรีเซ็ตเมื่อคุณเริ่ม FROM รูปภาพใหม่) - person David Maze; 09.05.2019