Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reduce multistage build duplicate steps time cost issue?

Tags:

docker

I have a go application, which depends on cgo. When build, it needs libsodium-dev, libzmq3-dev, libczmq-dev, and when run it also needs above three packages.

Currently, I use next multistage build: a golang build environment as the first stage & a debian slim as the second stage. But you could see the 3 packages installed for two times which waste time(Later I may have more such kinds of package added).

FROM golang:1.12.9-buster AS builder

WORKDIR /src/pigeon

COPY . .

RUN apt-get update && \
  apt-get install -y --no-install-recommends libsodium-dev && \
  apt-get install -y --no-install-recommends libzmq3-dev && \
  apt-get install -y --no-install-recommends libczmq-dev && \
  go build cmd/main/pgd.go


FROM debian:buster-slim

RUN apt-get update && \
  apt-get install -y --no-install-recommends libsodium-dev && \
  apt-get install -y --no-install-recommends libzmq3-dev && \
  apt-get install -y --no-install-recommends libczmq-dev && \
  apt-get install -y --no-install-recommends python3 && \
  apt-get install -y --no-install-recommends python3-pip && \
  pip3 install jinja2

WORKDIR /root/

RUN mkdir logger

COPY --from=builder /src/pigeon/pgd .
COPY --from=builder /src/pigeon/logger logger

CMD ["./pgd"]

Of course, I can give up multi-stage build, just use golang1.12.9-buster for build, and continue for run, but this will make final run image bigger (which is the advantage of multi-stage build).

Do I miss something or I had to make choice between above?

like image 478
atline Avatar asked Jan 28 '26 00:01

atline


1 Answers

this is my take about your question:

FROM debian:buster-slim as base

RUN mkdir /debs /debs_tmp \
    && chmod 777 /debs /debs_tmp

WORKDIR /debs
RUN apt-get update \
    && apt-get install -y -d \
            --no-install-recommends \
            -o dir::cache::archives="/debs_tmp/" \
        libsodium-dev \
        libzmq3-dev \
        libczmq-dev \
    && mv /debs_tmp/*.deb /debs \
    && rm -rf /debs_tmp \
    && apt-get install -y --no-install-recommends \
        python3 \
        python3-pip \
    && pip3 install jinja2 \
    && rm -rf /var/lib/apt/lists/*


##################

FROM golang:1.12.9-buster AS builder

COPY --from=base /debs /debs
WORKDIR /debs

RUN dpkg -i *.deb

WORKDIR /src/pigeon
COPY . .

RUN go build cmd/main/pgd.go

##################

FROM base

RUN rm -rf /debs

WORKDIR /root/
RUN mkdir logger

COPY --from=builder /src/pigeon/pgd .
COPY --from=builder /src/pigeon/logger logger

CMD ["./pgd"]

You can download the required packages in a temporary folder, move the debs in a new location and finally COPY the debs in the next stage. Finally you simply use the first image you've created.

BTW the containers will run as root. This might be an issue depending on what the software does, you might want to consider to use a user without "powers".

EDIT: sorry for the edits but I ran a couple of example locally and didn't have a go script ready.

like image 156
Stefano Avatar answered Jan 31 '26 03:01

Stefano