Docker兴起已经非常长的一段时间了,现在Docker已经非常成熟了,作为实践本文将尝试打包一个使用Flask框架的Web服务应用
Tips:本文默认已简单了解Docker的一些基础知识,如仓库、镜像、容器之间的关系以及基础的Docker操作如拉取镜像、运行容器等
要学习Docker项目打包,首先要安装Docker的环境,这里以 Ubuntu1804 为例子进行环境安装部署,官方已支持大部分Linux发行版直接安装,如下
curl -fsSL https://get.docker.com -o get-docker.sh
bash get-docker.sh
# 如果get-docker.sh下载不顺利,可从阿里云镜像站点下载
bash get-docker.sh --mirror Aliyun
拉取Hello World镜像测试安装是否顺利
docker run hello-world
# 输出如下
Unable to find image 'hello-world:latest' locally
...
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Docker的环境安装完成
Docker可以采用commit的方式打包容器,但缺点也很明显,由于分层存储的概念,在容器做任何简单的操作都将改动大量的底层文件,此时Commit导致镜像臃肿,此外由于缺乏记录工具,从容器Commit更改而来的镜像将不具备复用性与可维护性
Dockerfile便能避免这一点,顾名思义Dockerfile是一个定义Docker的文本文件,内容由一条条指令构成,描述镜像该如何生成
Docker的关键字不少,但基础入门需要了解的不多,定制一个镜像无非主要就2点
以SyncMemo为例,我们需要
为了满足这2个条件,我们简单了解以下操作指令
FROM指令
RUN命令
COPY/ADD指令
EXPOSE指令
WORKDIR/USER指令
掌握了以上的命令就已足够构建一个简单的镜像
SyncMemo基于Python3.9.1,由于没有合适的基础镜像,为了方便起见,则以Ubuntu1804为基础镜像
此次定制Dockerfile大致步骤如下
第一步是导入Ubuntu1804并安装编译工具,如下
# Compile python3.9.1
FROM ubuntu:18.04 AS compile-python
WORKDIR /app
RUN apt-get update && \
apt-get install -y git libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev zlib1g-dev make gcc
基础工具安装后,我们需要编译一个Python3.9.1并克隆SyncMemo仓库安装相关的库依赖,如下
ADD https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgz ./
RUN tar -zxvf Python-3.9.1.tgz && \
./Python-3.9.1/configure --prefix=/usr/local/python3.9.1 && \
make && make install && \
git clone https://github.com/chancelyg/syncmemo.git && \
/usr/local/python3.9.1/bin/pip3 install -r syncmemo/requirements.txt -i https://pypi.doubanio.com/simple
然后合并一下上面的片段并添加执行命令和端口,整个Dockerfile文件,如下
FROM ubuntu:18.04
WORKDIR /app
RUN apt-get update && \
apt-get install -y git wget libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev zlib1g-dev make gcc
RUN wget https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgz && \
tar -zxvf Python-3.9.1.tgz && \
./Python-3.9.1/configure --prefix=/usr/local/python3.9.1 && \
make && make install && \
rm -f ./Python-3.9.1.taz && rm -rf Python-3.9.1 && \
git clone https://github.com/chancelyg/syncmemo.git && \
/usr/local/python3.9.1/bin/pip3.9 install -r syncmemo/requirements.txt -i https://pypi.doubanio.com/simple
EXPOSE 7900
CMD ["/usr/local/python3.9.1/bin/python3","/app/src/main/py","--port=7900","--host=0.0.0.0"]
最后利用docker打包Dockerfile生成镜像
docker build -t syncmemo:v0.1 . --no-cache
# 此时位于/home/chancel/docker/syncmemo文件夹下,文件夹中只有Dockerfile一个文件
查看生成的镜像
docker images
# 输出如下
REPOSITORY TAG IMAGE ID CREATED SIZE
syncmemo v0.1 098681d3e5e3 About a minute ago 761MB
...
打包成功!
虽然是打包成功了,但761Mb的镜像很显然太大了
一个简单的Python Flask应用不应该占用如此大的空间
优化的思路一般如下
Tips:APT/YUM/APK等系统仓库包安装工具时可以添加“非必须依赖”参数来减少安装的软件数量
alipine就比Ubuntu小了20倍左右,但实测alipine对Python编译不太友好,遂放弃
检查我们的Dockerfile文件,仅使用了一次RUN,分层这一点无法再优化
第三方工具情况有些复杂,这里不做测试
最后是考虑用多阶段构建来减少镜像大小
多阶段构建即放弃安装了编译Python的Ubuntu镜像,在编译Python后直接迁移新的二进制Python程序到全新的Ubuntu镜像中
多阶段构建Dockerfile如下,可自行参考
# Compile python3.9.1
FROM ubuntu:18.04 AS compile-python
WORKDIR /app
RUN apt-get update && \
apt-get install -y git wget libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev zlib1g-dev make gcc wget
RUN wget https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgz --no-check-certificate && \
tar -zxvf Python-3.9.1.tgz && \
./Python-3.9.1/configure --prefix=/usr/local/python3.9.1 && \
make && make install && \
git clone https://github.com/chancelyg/syncmemo.git && \
/usr/local/python3.9.1/bin/pip3 install -r syncmemo/requirements.txt -i https://pypi.doubanio.com/simple
FROM ubuntu:18.04
WORKDIR /app/
COPY --from=compile-python /root/ /root/
COPY --from=compile-python /usr/local/python3.9.1 /usr/local/python3.9.1
COPY --from=compile-python /app/syncmemo /app/syncmemo
COPY app.conf /app/syncmemo/conf/app.conf
EXPOSE 7900
CMD ["/usr/local/python3.9.1/bin/python3","/app/syncmemo/src/main.py","--config=/app/syncmemo/conf/app.conf"]
在改用多阶段构建之后占用大小如下,可以看到明显减少了一半的体积
docker images
# 输出如下
REPOSITORY TAG IMAGE ID CREATED SIZE
syncmemo latest 894cdf854d7d 29 seconds ago 325MB
参考资料