docker - 如何减少多阶段构建重复步骤时间成本问题?
问题描述
我有一个 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
for build,继续for run,但这会使最终运行的图像更大(这是多阶段构建的优势)。
我错过了什么还是我不得不在上面做出选择?
解决方案
这是我对你的问题的看法:
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"]
您可以在临时文件夹中下载所需的包,将 debs 移动到新位置,最后COPY
将 debs 移动到下一阶段。最后,您只需使用您创建的第一个图像。
顺便说一句,容器将以 root 身份运行。这可能是一个问题,具体取决于软件的功能,您可能需要考虑使用没有“权力”的用户。
编辑:对编辑感到抱歉,但我在本地运行了几个示例并且没有准备好 go 脚本。
推荐阅读
- session - 无需每次都检查数据库的多通道会话管理的最佳实践是什么?
- html - 使用代理 PowerShell 调用 Web 请求
- python - 带有 Subprocess.popen 的 Pyinstaller 作为 exe 失败
- mysql - 使用mysql动态加密和解密数据
- nosql - 用于 Azure Functions 的 Cosmos DB 模拟
- ruby - 将 JS 文件注入 capybara chrome 无头
- scala - Play Framework 中是否有配置设置以在发送到客户端的响应中启用缓存控制标头
- html - 复选框元素下的额外空间
- visual-studio-code - 将 Visual Studio Code 中的 JavaScript 字符串重构/提取到 HTML 文件中
- scala - 如何火花提交 Play 框架项目