• windows部署python项目(以Flask为例)到docker,通过脚本一键生成dockerfile并构建镜像启动容器


    文章目录

    1、生成requirements.txt

    这里使用pipreqs进行依赖库的识别。使用 pipreqs 可以自动检索到当前项目下的所有组件及其版本,并生成 requirements.txt 文件。相比直接用pip freeze 命令,避免将整个python环境的依赖包写入。
    在项目的当前目录中执行
    pipreqs ./ --encoding=utf8 --force
    这里使用的是一个基于flask项目,目录结构如下
    在这里插入图片描述

    2、编写dockerfile

    dockerfile定义python版本号,将本地项目进行拷贝,定义启动命令。
    这部分固定流程我们其实可以抽象出来通过自定义脚本去一键生成。这里做一个简单的示例。自动生成脚本见文末。

    # 基于的基础镜像
    FROM python:3.8.8
    
    # 设置app文件夹是工作目录
    WORKDIR /usr/src/app
    
    # 先将依赖文件拷贝到项目中
    COPY requirements.txt /usr/src/app
    
    # 执行指令,安装依赖
    RUN pip install -r requirements.txt
    
    # 拷贝当前目录的项目文件和代码
    COPY . /usr/src/app
    
    # 执行命令
    CMD [ "python", "/usr/src/app/app.py" ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3、构建镜像

    这里以我自己写的一个疫情可视化的flask项目为例,项目名称为epidemic

    docker build -f dockerfile -t epidemic .
    
    • 1

    这里就是读取项目目录下的dockerfile进行构建
    -f

    4、启动容器

    镜像构建完成后使用docker run启动容器,-p指定

    docker run -it -p 5001:5000 --name epidemic_container epidemic
    
    • 1

    -p 指定端口映射,格式为:主机(宿主)端口:容器端口
    -i: 以交互模式运行容器,通常与 -t 同时使用;
    -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
    运行完成后我们就能看到如下界面,这里的控制台输出的就是此时容器中的flask运行控制台了。
    在这里插入图片描述

    我们本地访问我们配置的映射端口即可,浏览器输入127.0.0.1:5001即可
    在这里插入图片描述
    查看我们刚刚生成的容器。
    在这里插入图片描述

    5、编写脚本自动化完成上述操作

    通过脚本去将第二章中的dockerfile设置为模板,每次只需要自定义镜像名称即可,也可直接使用默认值。
    脚本按如下逻辑依次执行

    Created with Raphal 2.3.0 生成dockerfile 根据模板填充参数并生成dockerfile 检查requirements.txt是否存在? 执行生成的dockerfile 根据镜像配置参数启动容器 结束 使用pipreqs生成requirements.txt yes no

    完整代码如下

    import os
    import sys
    import time
    
    
    def get_cmd(cmd):
        res = os.popen(cmd)
        return res.read()
    
    
    class Generate:
        def __init__(self, dockerfile_name="generate.dockerfile", image_name="docker_img"):
            self.dockerfile_name = dockerfile_name
            self.image_name = image_name
    
        def generate_dockerfile(self, work_dir="/usr/src/app", main_file="app.py"):
            # 首先生成dockerfile模板,python版本通过命令行获取
            python_version = sys.version.split(" ")[0]
            template = f"""
    FROM python:{python_version}
    WORKDIR {work_dir}
    COPY requirements.txt {work_dir}
    RUN pip install -i https://pypi.doubanio.com/simple/ -r requirements.txt
    COPY . {work_dir}
    CMD [ "python", "{work_dir}/{main_file}" ]
    """
            # 检查requirements.txt文件是否存在,不存在则调用命令生成生成
            if not os.path.exists("requirements.txt"):
                print("正在等待requirements.txt文件生成,请稍候....")
                os.system("pip install -i https://pypi.doubanio.com/simple/ pipreqs && pipreqs ./ --encoding=utf8 --force")
                while not os.path.exists("requirements.txt"):
                    print("正在等待requirements.txt文件生成...")
                    time.sleep(2)
    
            # 确定requirements文件生成后,将dockerfile写入到本地
            with open(self.dockerfile_name, "w") as f:
                f.write(template)
            print(f"dockerfile生成成功,文件名称为{self.dockerfile_name}")
            return True
    
        def build_image(self):
            images = get_cmd(f"docker images")
            if self.image_name not in images:
                cmd = f"docker build -f {self.dockerfile_name} -t {self.image_name} ."
                print(cmd)
                os.system(cmd)
                return self.image_name in images
            return False
    
        def run_container(self, container_name, local_port=5001, container_port=5000):
            cmd = f"docker run -p {local_port}:{container_port} --name {container_name} {self.image_name}"
            #cmd = f"docker run {self.image_name}"
            print(cmd)
            os.system(cmd)
    
    
    if __name__ == '__main__':
        generate = Generate(dockerfile_name="generate_dockerfile.dockerfile", image_name="epidemic")
        generate.generate_dockerfile()
        generate.build_image()
        generate.run_container(container_name="epidemic_container", local_port=5001, container_port=5000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    运行完成后的输出如下
    在这里插入图片描述

    6、end

    如果需要部署示例的这份源码可以关注公众号"一颗程序树"在公众号菜单进行获取
    在这里插入图片描述

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    flink sql clinet 实战:窗口函数----flink-1.13.6
    学校档案管理系统软件-学校数字档案室解决方案
    2024年最新通信安全员考试题库
    Spring Bean循环依赖问题及解决
    Stable Diffusion webui 常用启动参数
    【Verilog语法】比较不同计数器的运算方式,其中有一个数是延迟打一拍的效果,目的是使得两个计数器的结果相同。
    494. 目标和
    Excel 冻结前几行
    想要搭建网站帮助中心,看这一篇指南就对了!
    深度详解 Android 屏幕刷新机制之 Choreographer
  • 原文地址:https://blog.csdn.net/web18224617243/article/details/126080505