由来
Multi-stage builds are a new feature in Docker 17.05
官方文档讲述多步构建的示例是一个Go程序,Go程序本身就可以编译成可执行文件,所以使用多步构建很容易。这么好玩的功能必须要用Python实践一下咯。
Demo
Demo目录
tornado-multi-stage/
docker-compose.yml
Dockerfile
requirements.txt
run.py
requirments.txt:依赖Tornado
tornado==4.5.1
run.py:程序入口
程序实现的功能:接收到GET请求后返回Hello World
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello World")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888, '0.0.0.0')
tornado.ioloop.IOLoop.current().start()
docker-compose.yml
没做什么特别的事情,就做了一下端口映射
version: "3"
services:
web:
build: .
ports:
- 8888:8888
Dockerfile:重点
FROM python:3.5 as builder
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=builder /app/dist/run .
ENTRYPOINT ["./run"]
解释一下:
- 为了方便浏览,第八行空白行将
Dockerfile分隔成了两部分,上面为第一次构建,下面为第二次构建 - 第一次构建
- 以
python:3.5作为基础镜像,安装好依赖后,利用pyinstaller来 - 打包Tornado程序打包后的可执行文件路径为
/app/dist/run
- 以
- 第二次构建
- 以
frolvlad/alpine-glibc作为基础镜像,从第一次构建的镜像中把/app/dist/run文件复制过来
- 以
效果
运行效果
镜像体积
坑
打包工具
pyinstaller的官方说明
Works out-of-the-box with any Python version 2.7 / 3.3-3.5
- 踩坑第一步
我电脑系统是macOS 10.12.5,安装的是Python 3.6.2,安装了PyPI上的pyinstaller,发现本地打包会报错。于是后面我直接用GitHub上最新版本,结果是能成功打包,并且可执行文件可以运行,应用也可以正常工作。 - 踩坑第二步
我用python:3.6.2的镜像+最新版pyinstaller,在容器里能打包成功,但是可执行文件运行不了。 - 踩坑第三步
只好把基础镜像换成了python:3.5,这样打包出来的可执行文件正常了。
运行环境
第二步构建的基础镜像,决定着可执行文件能不能跑起来
- 踩坑第一步
一开始为了镜像最小化,就用了alpine:latest镜像,发现可执行文件根本跑不起来,会报错
web_1 | standard_init_linux.go:187: exec user process caused "no such file or directory"
torandomultistage_web_1 exited with code 1
通过公司大佬指导后发现,是因为alpine:latest镜像里缺少glibc
- 踩坑第二步
在DockerHub上找到了Alpine Docker image with glibc,使用这个基础镜像后应用就成功运行起来了
BTW
折腾需谨慎。Python应用打包成可执行文件放在一个小镜像里面跑,很不稳(手动doge)。出个错啥的都不好排查。没必要为了弄一个超小镜像给自己挖个大坑。

