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 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)
运行完成后的输出如下
6、end
如果需要部署示例的这份源码可以关注公众号"一颗程序树"在公众号菜单进行获取