文章目录

    • 1、生成requirements.txt
    • 2、编写dockerfile
    • 3、构建镜像
    • 4、启动容器
    • 5、编写脚本自动化完成上述操作
    • 6、end

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

3、构建镜像

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

docker build -f dockerfile -t epidemic .

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

4、启动容器

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

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

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

我们本地访问我们配置的映射端口即可,浏览器输入127.0.0.1:5001即可

查看我们刚刚生成的容器。

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

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

完整代码如下

import osimport sysimport timedef 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_nameself.image_name = image_namedef 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.txtCOPY . {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 Truedef 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 imagesreturn Falsedef 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)

运行完成后的输出如下

6、end

如果需要部署示例的这份源码可以关注公众号”一颗程序树“在公众号菜单进行获取