Docker技术越来越得到广泛的应用。利用Docker可以创建一个隔离的、自包含的程序运行环境,并且非常方便的进行部署。这篇文章将详细介绍,如何在Docker中开发Flask应用以及如何在Docker中来运行、访问Flask应用。
Docker的优势
通常对于Python开发来讲,我们可以借助virtualenv来建立彼此独立的开发环境。比如应用程序A依赖Python2.7,而应用程序B依赖Python3.5。我们可以分别建立两个virtualenv,其中一个安装python2.7,另外一个安装python3.5。之后我们就可以在各自的虚拟环境中进行开发了。貌似,viertualenv完美解决了不同程序的环境依赖问题。可是,真的是这样吗?
想象一下,我们在开发环境搭建了一套virtualenv,如果部署到生产环境中,还需要再生产环境再部署一套完全一样的virtualenv,对不对?而且还需要在主机上安装必要的软件才能建立虚拟环境。
利用Docker就可以解决这个问题。Docker不但可以做到在同一台主机上开发时建立不同的环境,还可以将建立的Docker镜像搬到其他不同的主机上,而不需要再次安装环境就可以运行程序。这样就可以保证开发、测试、生产环境的服务器上的环境完全一致。
本篇文章默认已经在你的服务器上安装好了Docker服务。如不会安装请参考Docker的官方文档。本文重点是讲解如何构建Docker镜像、如何在镜像中开发Flask程序、如何在镜像中运行Flask应用。
创建Docker镜像
搭建Flask应用的框架
先创建一个Flask应用程序的目录,我们叫它toolbox_docker。1
2
3 cd ~
mkdir -p toolbox_docker
cd toolbox_docker
在这个目录中,我们将创建Flask应用程序的源码文件夹toolbox、用于构建Docker镜像的Dockerfile以及Flask应用说明文件Readme.md。
.
├── Dockerfile
├── Readme.md
└── toolbox
Flask 应用程序源码toolbox目录结构如下:
├── app
├── manage.py
├── requirements.txt
└── start_server.sh
在这个程序的源码中,包含Flask应用的管理脚本、项目的依赖requirements.txt、以及Flask应用的启动脚本start_server.sh。
创建entry-point启动脚本
entry-point启动脚本是用来启动Flask应用程序的。这个脚本可以作为容器启动时的默认命令,这样在容器启动时,Flask应用程序就被启动了。
start_server.sh脚本如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#!/bin/bash
set -e
touch /opt/toolbox/log/gunicorn.log
touch /opt/toolbox/log/gunicorn.err
touch /opt/toolbox/log/access.log
# Start Gunicorn processes
echo Starting Gunicorn...
exec gunicorn manage:app \
--bind 0.0.0.0:8000 \
--workers 4 \
--log-level=info \
--log-file=/opt/toolbox/log/gunicorn.log \
--access-logfile=/opt/toolbox/log/access.log \
"$@"
echo Gunicorn is running...
在这个脚本中,我们创建了三个log files用于记录gunicorn的运行情况。并且通过gunicorn启动Flask应用。
最后,”$@”允许我们在容器启动时,再传递额外的参数给gunicorn。
另外,要记得修改start_server.sh的执行权限:$ chmod u+x start_server.sh
创建Dockerfile
创建Docker镜像的构建文件Dockerfile。内容如下: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##########################################################
# Dockerfile to run a flask-based web application# Based on an centos:7 image
##########################################################
# Set the base image to use to centos
FROM centos:7
# Set the file maintainer
MAINTAINER liuchunming033,liuchunming033@163.com
# Set env varibles used in this Dockerfile (add a unique prefix, such as DOCKYARD)
# Local directory with project source
ENV DOCKYARD_SRC=toolbox
# Directory in [Container](http://lib.csdn.net/base/docker "Docker知识库") for all project files
ENV DOCKYARD_SRCHOME=/opt
# Directory in container for project source files
ENV DOCKYARD_SRCPROJ=/opt/toolbox
# Update the defualt application repository source list
RUN yum -y install epel-release
RUN yum -y install python-pip
RUN yum clean all
# Copy application source code to SRCDIR
COPY $DOCKYARD_SRC $DOCKYARD_SRCPROJ
# Create application subdirectories
WORKDIR $DOCKYARD_SRCPROJ
RUN mkdir log
VOLUME [“$DOCKYARD_SRCPROJ/log/”]
# Install Python dependencies
RUN pip install -r $DOCKYARD_SRCPROJ/requirements.txt
# Port to expose
EXPOSE 8000
# Copy entrypoint script into the image
WORKDIR $DOCKYARD_SRCPROJ
ENTRYPOINT [“./start_server.sh”]
Dockerfile表明了我们构建Docker镜像的步骤。
1、我们将centos:7作为基础镜像,后续的指令都是在此基础镜像中安装的;
2、使用ENV指令在Container中设置环境变量。这些环境变量可以在Dockerfile的后面指令中使用,也可以被在该容器中运行的程序使用。
3、执行YUM安装系统工具pip,pip用于安装后续requirements.txt中的依赖包
4、将Docker主机上的目录DOCKYARD_SRC内容,复制到镜像中的DOCKYARD_SRCPROJ目录。
5、使用requirements.txt来安装Python依赖。
6、使用EXPOSE指令暴露8000端口,以便容器外可以访问8000端口
7、ENTRYPOINT指令规定了在容器启动时执行的指令。这里是启动Flask应用的脚本。
构建Docker镜像
$ docker build -t automation/toolbox ~/toolbox_docker
将构建的Docker镜像命名为automation/toolbox。该构建执行过程中将经过一系列的Step。最终将输出类似Successfully built 08de9083be30的信息。表示构建镜像已经完成。构建完成后,执行docker images命名查看构建后的镜像:
1 | REPOSITORY TAG IMAGE ID CREATED SIZE |
启动Docker容器
执行docker run命令启动构建的镜像:
sudo docker run –rm -d -p 8002:8000 -v /var/log/toolbox:/opt/toolbox/log –name toolbox_server –restart=always automation/toolbox
上面这个命令的解释如下:
1、 –rm 表示每次启动容器时,删除旧的容器
2、-d 表示后台启动容器
3、-p 8002:8000 表示将Docker主机的8002端口与容器的8000接口绑定,这样访问Docker主机的8002端口时就相当于访问了容器内的8000端口。而容器内的8000端口正好是Flask应用提供的端口。
4、-v 表示将Docker主机的/var/log/toolbox目录与容器内的/opt/toolbox/log目录做映射。这样Flask应用在容器内产生的log文件就可以在主机的/var/log/toolbox目录里面直接读取了。
5、–name 选项给启动的容器起了一个名字
6、–restart=always表示当容器中的Flask应用停止或者崩溃时,要重新启动Docker容器
6、automation/toolbox是镜像的名字。
查看Docker容器
执行docker ps命令查看docer容器:1
2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce272d8960b4 automation/toolbox “/start_server.sh” 3 days ago Up 3 days 0.0.0.0:8002->8000/tcp toolbox_server1
管理Docker容器
下面的命令用于启动、停止、重启Docker容器:1
2
3$ docker stop toolbox_server1
$ docker start toolbox_server1
$ docker restart toolbox_server1
修改Gunicorn启动选项
Docker允许在容器启动时传递参数给容器中执行的命令,在本文中Docker容器启动时,执行的是start_server.sh。start_server.sh脚本中执行的是Gnicorn,因此传递参数给start_server.sh时,就相当于传递参数给Gnicorn了。比如要修改Gnicorn启动的线程数,可以这么做:docker run automation/toolbox --workers 5