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。

$ 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脚本如下:

#!/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应用。
最后," @ " 允 许 我 们 在 容 器 启 动 时 , 再 传 递 额 外 的 参 数 给 g u n i c o r n 。 另 外 , 要 记 得 修 改 s t a r t s e r v e r . s h 的 执 行 权 限 : ‘ ‘ ‘ @"允许我们在容器启动时,再传递额外的参数给gunicorn。 另外,要记得修改start_server.sh的执行权限: ``` @"gunicornstartserver.sh chmod u+x start_server.sh```
####创建Dockerfile
创建Docker镜像的构建文件Dockerfile。内容如下:

##########################################################
# 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 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镜像命名为automation/toolbox。该构建执行过程中将经过一系列的Step。最终将输出类似Successfully built 08de9083be30的信息。表示构建镜像已经完成。构建完成后,执行docker images命名查看构建后的镜像:

REPOSITORY TAG IMAGE ID CREATED SIZE
automation/toolbox latest 08de9083be30 3 days ago 360.7 MB

###启动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容器:

CONTAINER 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容器:

$ 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

###参考资料
http://michal.karzynski.pl/blog/2015/04/19/packaging-django-applications-as-docker-container-images/

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐