RUN - RUN命令是一个常用的命令,执行完成之后会成为一个新的镜像,通常用于运行安装任务从而向映像中添加额外的内容。在这里,我们需更新包,安装 python3 和 pip 。在第二个 RUN 命令中使用 pip 来安装 requirements.txt 文件中的所有包。
COPY - 复制本机文件或目录,添加到指定的容器目录, 本例中将 requirements.txt 复制到镜像中。
WORKDIR - 为RUN、CMD、ENTRYPOINT指令配置工作目录。可以使用多个WORKDIR指令,后续参数如果是相对路径,则会基于之前命令指定的路径。
ENTRYPOINT - 在启动容器的时候提供一个默认的命令项。
RUN - 运行 app 目录中的 app.py 。
Docker镜像构建原理Docker镜像是使用 Docker build 命令构建的。在构建镜像时,Docker创建了所谓的“层(layers)”。每一层都记录了Dockerfile中的命令所导致的更改,以及运行命令后镜像的状态。
Docker在内部缓存这些层,这样在重新构建镜像时只需要重新创建已更改的层。例如,这里使用了 ubuntu:16.04 的基础镜像,相同容器的所有后续构建都可以重用它,因为它不会改变。但是,因为项目修改,在下次重新构建过程中 app 目录的内容可能会有所不同,因此只会重新构建这一层。
需要注意的是,每当重新构建某一层时,Dockerfile 中紧随其后的所有层也都需要重新构建。例如,我们首先复制 requirements.txt 文件,然后再复制应用程序的其余部分。这样之前安装的依赖项只要没有新的依赖关系,即使应用程序中的其他文件发生了更改,也不需要重新构建这一层。这一点在创建 Dockerfiles 时一定要注意。
因此,通过将 pip 安装与应用程序其余部分的部署分离,可以优化容器的构建过程。
构建Docker镜像现在 Dockerfile 已经准备好了,而且也了解了Docker的构建过程,接下来为我们的应用程序创建Docker映像:
docker build -t docker-flask:0.1 . 调试模式运行根据前面讲到的容器化的优点,开发的应用程序通过容器部署,这从一开始就确保了应用程序构建的环境是干净的,从而消除了交付过程中的意外情况。
但是呢,在开发应用程序的过程中,更重要的是要快速重新构建和测试,以检查验证过程中的每个中间步骤。为此,web应用程序的开发人员需要依赖于Flask等框架提供的自动重启功能(Debug模式下,修改代码自动重启)。而这一功能也可以在容器中使用。
为了启用自动重启,在启动Docker容器时将主机中的开发目录映射到容器中的app目录。这样Flask就可以监听主机中的文件变化(通过映射)来发现代码更改,并在检测到更改时自动重启应用程序。
此外,还需要将应用程序的端口从容器转发到主机。这是为了能够让主机上的浏览器访问应用程序。
因此,启动Dokcer容器时需要使用 volume-mapping 和 port-forwarding 选项:
docker run --name flask_app -v $PWD/app:/app -p 5000:5000 docker-flask:0.1改命令将会执行以下操作:
基于之前构建的 docker-flask 镜像启动一个容器;
这个容器的名称被设置为 flask_app 。如果没有 ——name 选项,Docker将为容器生成一个名称。显式指定名称可以帮助我们定位容器(用来停止等操作);
-v 选项将主机的app目录挂载到容器;
-p 选项将容器的端口映射到主机。
现在可以通过:5000 或者 :5000/ 访问到应用:
如果我们在容器运行的时候,修改应用程序代码,Flask会检测到更改并重新启动应用程序。
要停止容器的话,可以使用 Ctrl + C, 并运行 docker rm flask_app 移除容器。
生产模式运行虽然直接使用Flask裸跑运行应用程序对于开发来说已经足够好了,但是我们需要在生产中使用更健壮的部署方法。
目前主流的部署方案是 nginx + uwsgi,下面我们将介绍如何为生产环境部署web应用程序。Nginx是一个开源web服务器,uWSGI是一个快速、自我修复、开发人员和系统管理员友好的服务器。
首先,我们创建一个入口脚本,用来控制以开发模式还是生产模式启动我们的应用程序,这两者区别是选择直接运行python还是nginx模式。
然后再写一个简单shell启动脚本 entry-point.sh:
#!/bin/bash if [ ! -f /debug0 ]; then touch /debug0 while getopts 'hd:' flag; do case "${flag}" in h) echo "options:" echo "-h show brief help" echo "-d debug mode, no nginx or uwsgi, direct start with 'python3 app/app.py'" exit 0 ;; d) touch /debug1 ;; *) break ;; esac done fi if [ -e /debug1 ]; then echo "Running app in debug mode!" python3 app/app.py else echo "Running app in production mode!" nginx && uwsgi --ini /app.ini fi