Docker 多阶段构建
偷懒是人类进步的阶梯
今天看到一个概念,不是新的,但之前却很奇怪地完全没有接触过。
简单来说,就是 Dockerfile 支持多次 build,然后把上一次 build 产生的文件直接 COPY 到下一次的 build 过程中。
相当于第二次的 build 里只执行了一次 COPY,省去中间很多下载、安装、编译的过程。
优点
- 把 build + run 过程分离,让 run 只负责 run;
- 大幅度减少 run 镜像的层数,从而压缩 run 环境的分发和更新时间;
缺点
- 对于动态语言来说(比如 SRE 工程师最爱的 Python),依赖环境较难处理,需要用额外的打包工具;
- 打包后镜像只有 run 环境,出问题的时候不方便进行 debug;
从上面的优缺点可以看到,对静态语言,尤其是最后可以打包成二进制的文件来说,多阶段构建的好处是显而易见的,对动态语言来说,就需要各种尝试,确认打包后程序的稳定性。
例子
这里摘抄两个在网上看到的 python 的例子:
使用 wheel
FROM python:2.7-alpine as base
RUN mkdir /svc
COPY . /svc
WORKDIR /svc
RUN apk add --update \
postgresql-dev \
gcc \
musl-dev \
linux-headers
RUN pip install wheel && pip wheel . --wheel-dir=/svc/wheels
FROM python:2.7-alpine
COPY --from=base /svc /svc
WORKDIR /svc
RUN pip install --no-index --find-links=/svc/wheels -r requirements.txt
使用 pyinstaller
FROM python:3.6 as build-env
WORKDIR /app/
ADD . /app/
ADD https://github.com/pyinstaller/pyinstaller/archive/develop.zip /app/pyinstaller-develop.zip
RUN pip install -r requirements.txt && \
pip install pyinstaller-develop.zip
RUN pyinstaller --hidden-import=tornado --onefile -d -y run.py
FROM frolvlad/alpine-glibc
WORKDIR /app/
COPY --from=build-env /app/dist/run .
ENTRYPOINT ["./run"]