1. 前言
Docker兴起已经非常长的一段时间了,现在Docker已经非常成熟了,作为实践本文将尝试打包一个使用Flask框架的Web服务应用
Tips:本文默认已简单了解Docker的一些基础知识,如仓库、镜像、容器之间的关系以及基础的Docker操作如拉取镜像、运行容器等
2. 准备
要学习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的环境安装完成
2.1. Dockerfile文件
Docker可以采用commit的方式打包容器,但缺点也很明显,由于分层存储的概念,在容器做任何简单的操作都将改动大量的底层文件,此时Commit导致镜像臃肿,此外由于缺乏记录工具,从容器Commit更改而来的镜像将不具备复用性与可维护性
Dockerfile便能避免这一点,顾名思义Dockerfile是一个定义Docker的文本文件,内容由一条条指令构成,描述镜像该如何生成
2.2. Dockerfile 关键字
Docker的关键字不少,但基础入门需要了解的不多,定制一个镜像无非主要就2点
- 运行环境
- 运行指令
以SyncMemo为例,我们需要
- Linux操作环境
- Python3.9.1
为了满足这2个条件,我们简单了解以下操作指令
FROM指令
- 导入基础的镜像,通常是Linux发行版或者应用环境(如Docker官方直接提供的Python3环境)
RUN命令
- 通常用来执行命令行
- RUN的层数将决定镜像的大小
- RUN之间没有任何联系,RUN cd /app是错误的,要用WORKDIR来定义目录
COPY/ADD指令
- COPY复制文件
- ADD是支持解压缩、自动下载的高级COPY指令(如无特殊情况一般建议使用COPY指令)
EXPOSE指令
- 对外服务端口(Docker run -p 4704:3700… 3700即是对外服务端口)
WORKDIR/USER指令
- RUN之间是没有联系的,所以如需定义Docker的工作目录(即每一个RUN命令执行时的初始路径)则采用WORKDIR
- 同理,USER指令用于指定每一个RUN的执行者(在使用USER前必须先用RUN指令创建执行者)
掌握了以上的命令就已足够构建一个简单的镜像
3. 构建
SyncMemo基于Python3.9.1,由于没有合适的基础镜像,为了方便起见,则以Ubuntu1804为基础镜像
此次定制Dockerfile大致步骤如下
- 导入Ubuntu1804
- 编译Python3.9.1
- 克隆SyncMemo并安装项目依赖
- 运行程序
3.1. 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
...
打包成功!
3.2. 体积优化
虽然是打包成功了,但761Mb的镜像很显然太大了
一个简单的Python Flask应用不应该占用如此大的空间
优化的思路一般如下
- 选择更小的基础镜像
- 删减不必要的RUN指令减少分层
- 采用多阶段构建
- 其他第三方的Docker压缩工具来压缩镜像大小
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
4. 结束
参考资料