IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    构建一个Flask Web的Docker应用

    chancel发表于 2024-06-12 00:00:00
    love 0
    <![CDATA[

    1. 前言

    Docker兴起已经非常长的一段时间了,现在Docker已经非常成熟了,作为实践本文将尝试打包一个使用Flask框架的Web服务应用

    • https://github.com/chancelyg/syncmemo

    Tips:本文默认已简单了解Docker的一些基础知识,如仓库、镜像、容器之间的关系以及基础的Docker操作如拉取镜像、运行容器等

    2. 准备

    要学习Docker项目打包,首先要安装Docker的环境,这里以 Ubuntu1804 为例子进行环境安装部署,官方已支持大部分Linux发行版直接安装,如下

    Bash
    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镜像测试安装是否顺利

    Bash
    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为例,我们需要

    1. Linux操作环境
    2. 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大致步骤如下

    1. 导入Ubuntu1804
    2. 编译Python3.9.1
    3. 克隆SyncMemo并安装项目依赖
    4. 运行程序

    3.1. Dockerfile撰写

    第一步是导入Ubuntu1804并安装编译工具,如下

    Docker
    # 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仓库安装相关的库依赖,如下

    Docker
    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文件,如下

    Docker
    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生成镜像

    Bash
    docker build -t syncmemo:v0.1 . --no-cache
    
    # 此时位于/home/chancel/docker/syncmemo文件夹下,文件夹中只有Dockerfile一个文件
    

    查看生成的镜像

    Bash
    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如下,可自行参考

    Docker
    # 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"]
    

    在改用多阶段构建之后占用大小如下,可以看到明显减少了一半的体积

    Bash
    docker images
    
    # 输出如下
    REPOSITORY      TAG                IMAGE ID       CREATED          SIZE
    syncmemo        latest             894cdf854d7d   29 seconds ago   325MB
    

    4. 结束

    参考资料

    • https://yeasy.gitbook.io/docker_practice/image/dockerfile/shell
    • http://dockone.io/article/8163



沪ICP备19023445号-2号
友情链接