我有一个go应用程序,它取决于cgo。构建时,它需要libsodium-dev, libzmq3-dev, libczmq-dev
,运行时,它也需要以上三个软件包。
当前,我使用下一个多阶段构建:a golang build environment
作为第一阶段,a debian slim
作为第二阶段。但是您可能会看到3个软件包安装了两次,这浪费了时间(稍后我可能会添加更多此类软件包)。
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"]
当然,我可以放弃多阶段构建,仅使用golang1.12.9-buster
进行构建,然后继续运行,但这将使最终运行映像更大(这是多阶段构建的优势)。
我想念东西还是不得不在以上两者之间做出选择?
答案 0 :(得分:1)
在COPY . .
步骤中,只要您的源代码发生更改,缓存就会崩溃,您将再次运行所有后续步骤。您可以重新排列步骤顺序,以允许docker缓存您的依赖项的安装。您还可以将apt-get install
命令合并为一个,以减少处理程序包管理器数据库的开销。
FROM golang:1.12.9-buster AS builder
WORKDIR /src/pigeon
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libsodium-dev \
libzmq3-dev \
libczmq-dev
COPY . .
RUN go build cmd/main/pgd.go
FROM debian:buster-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libsodium-dev \
libzmq3-dev \
libczmq-dev \
python3 \
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"]
您仍将安装软件包两次,但是现在这些安装已被缓存以备将来使用。重复使用库安装的方法是重新排序步骤,将库安装在一个通用的基础映像中,然后在构建阶段安装go编译器,但这几乎肯定比两次安装库要大。 >
使用BuildKit,您可以使用实验性语法在构建之间共享apt缓存,但这要求所有构建都使用BuildKit(语法不向后兼容),并修改docker的Debian映像以保留apt软件包缓存。在BuildKit实验性文档中,有以下适用于apt的示例:
# syntax = docker/dockerfile:experimental
FROM ubuntu
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
apt update && apt install -y gcc
https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md
答案 1 :(得分:1)
这是我对您的问题的看法:
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"]
您可以将所需的软件包下载到一个临时文件夹中,将Deb移到新位置,最后在下一阶段COPY
Debs。最后,您只需使用创建的第一张图片。
顺便说一句,这些容器将以root身份运行。取决于软件的功能,这可能是一个问题,您可能要考虑使用没有“权力”的用户。
编辑:对所做的编辑感到抱歉,但我在本地运行了两个示例,但尚未准备好运行脚本。