阿里云
阿里云多端小程序中小企业获客首选
发表主题 回复主题
  • 594阅读
  • 0回复

[环境部署]Docker实用指南:将Python Web应用容器化

级别: 论坛版主
发帖
371
云币
447

前言 [(]uin+9Q  
Web应用随时可能被攻击者利用来夺取整个主机的权限,这是很常见也是很恐怖的一件事。为了更高的安全性,就需要将不同应用之间进行隔离(尤其是在这些应用属于不同的用户的情况下),然而这种隔离的实现一直是个挑战。到目前为止,隔离性的实现方法已经有了很多,然而它们要么太过昂贵(时间的层面以及资源的层面),要么太过复杂(无论对开发者还是对管理员)。 IU&n!5d$)|  
.^uNzN~  
GDhg VOW(  
本文将讨论如何让“容器化”的Python Web应用跑在安全的沙箱里,严格的坚守在其各的环境中(当然,除非你指定它们与其他应用进行“连接”)。我将一步一步的介绍如何创建一个Docker容器,如何用这个容器来跑我们的Python Web应用,以及如何用一个Dockerfile来描述整个构建过程以实现完整的自动化。 -K PbA`j+  
)%P!<|s:5  
p9fx~[_5/  
目录 T2GJoJ!  
1. Docker概述 FK>8(M/  
2. 在Ubuntu上安装Docker Iq(BH^K  
3. 基本的Docker命令 `N;JM3 ck  
Docker的守护进程与命令行 kowBB0  
Docker命令 0jG8Gmh!  
4. 创建Docker容器作为Python WSGI应用的沙箱 bvi Y.G3  
在Ubuntu里创建打底Docker容器 W A-\2  
安装前的准备工作 \K55|3~R  
安装Python工具 L `3x0u2  
安装我们的Web应用以及其依赖项 ~Cm_=[  
配置我们的Python WSGI应用 }mz@oEB#vF  
5. 创建Dockerfile以实现镜像创建的自动化 ~}+F$&  
Dockerfile概述 d=yuuS /  
Dockerfile命令一览 TZ3"u@ 06  
创建Dockerfile f }P6P>0T  
定义基本项 BRyrdt*_e  
更新默认的应用仓库 ?t46TV'G  
安装基础工具 ';'gKX!9V  
Python基础套装安装指南 )jm!bR`  
部署应用 >sGIpER7  
引导 yzWVUqtXm  
最终的Dockerfile E?v:7p<  
使用Dockerfile进行自动化的容器创建 ecvQEK2L  
Docker概述 fkk&pu  
Docker项目提供了一些可以搭配使用的上层工具,这些工具基于Linux内核的一些功能创建。整个项目的目标是帮助开发者和系统管理员门无痛的迁移应用(以及它们所涉及的所有依赖项),让应用在各种系统和机器上都能欢快的跑起来。 #|-i*2@oR  
1#}}:  
P.#@1_:gC  
实现这个目标的关键在于一个叫做docker容器的运行环境,这个环境实际上是一个具备安全属性的LXC(Linux Containers)。容器的创建使用了Docker镜像,Docker镜像可以手动敲命令创建,也可以通过Dockerfiles实现自动化创建。 #7v=#Jco  
8GlRO4yd  
%/.yGAPkx  
注:关于Docker的基础知识(守护进程、CLI、镜像等等),可参阅本系列的第一篇文章Docker Explained: Getting Started。 'nJ,mZx  
B5v5D[ o5  
CT{mzC8  
在Ubuntu上安装Docker c'md)nD2M  
最新版本的Docker(译注:本文撰写时间为2013年12月17日,当时的Docker最新版本为0.7.1)可以在Ubuntu/Debian和CentOS/RHEL等多个Linux发行版上部署(你也可以使用DigitalOcean上现成的Docker镜像,该镜像基于Ubuntu 13.04创建)。 V10JExsJ  
yo^M>^P\N  
L NS O]\  
下面快速介绍一下Ubuntu上的安装流程。 R/EpfYOX  
_kEU=)Xe  
gk hmQd  
在Ubuntu上安装Docker z#HNJAQ#|  
更新系统: F81Kxcs  
tZ>'tE   
,Jrm85 oG  
sudo aptitude    update }y>/#]X  
sudo aptitude -y upgrade 5Sz&j  
'IQ;; [Q  
<IBWA0A=8a  
检查系统是否支持aufs:  |\FJ  
y/Ui6D  
o)WzZ,\F^J  
sudo aptitude install linux-image-extra-`uname -r` T-F8[dd^/  
sq_ yu(  
b Bkg/p]  
往apt-key添加Docker仓库的密钥(用于软件包的验证): m^$KDrkD  
^XT;n  
Z6fR2A~Q[  
sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -" bQ`2ll*(  
~Dbu;cqR@  
_ |G') 9  
往aptitude软件源添加Docker仓库: %Y=  
L"L a|  
MjW{JR)I  
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\ &[t} /+)  
> /etc/apt/sources.list.d/docker.list" W~& QcSWqD  
)uO 3v  
04c`7[  
添加之后再更新一次系统: H2{&da@D5  
LG vPy  
!DBaC%TGC  
sudo aptitude update &UQP9wS4v  
]Wn=Oc{F  
/6FPiASbS  
最后,下载并安装Docker: TOsHb+Uv  
IAd[_<9D  
eC='[W<a.  
sudo aptitude install lxc-docker vv1W<X0e<  
~>u u1[ /  
r12e26_Ab  
Ubuntu默认的防火墙(UFW)的默认设置是拒绝一切转发(forwarding),但是Docker需要转发,所以也需要设置一下UFW。 qf*e2" ~v  
K7},X01^  
T# 3`&[  
用nano编辑器打开UFW配置文件: gmCB4MO  
]Z>zf]<  
pAH 9  
sudo nano /etc/default/ufw |DUOyQ  
;m}o$`  
L[Y|K%;~  
找到DEFAULT_FORWARD_POLICY这一行,将 "v+%F  
;'oi7b  
71G00@&w9D  
DEFAULT_FORWARD_POLICY="DROP" J1d|L|M  
*Bx' g| u  
.iH#8Z  
替换为: ;/ao3Q   
FUKE.Uxd  
\:-N<[  
DEFAULT_FORWARD_POLICY="ACCEPT" }$1Aw%p^  
P8;f^3V(+/  
&Qq4xn+J  
按 CTRL+X 再按 Y 键,保存退出。 !FR1yO'd>  
U-GV^j  
.X(ocs$}  
最后,把UFW重启一下: pI{s )|"  
Ld YaJh~h  
N>_d {=P  
sudo ufw reload POvpaPAZ<  
o*1t)HL<  
7<c&)No;  
基本的Docker命令 Eb=;D1)y]  
在正式开始之前,我们还是先复习一下上次在基础篇中介绍过的一些基本命令。 7<%Rx19L*  
9=Rj9%  
fO{E65uA  
Docker的守护进程与命令行 =m= utd8  
一般来说,Docker守护进程在你安装完成了之后就已经在后台运行,等待接收来自Docker命令行的指令。不过有的时候我们也需要手动启动Docker守护进程: `)R@\@jt  
g_w4}!|  
CmPix]YMQ  
sudo docker -d & xj!_]XJ^w  
O[fgn;@|  
{bvm83{T  
Docker命令行的基本语法如下: -/ #tQ~{gs  
0\y@etb:mf  
<U$A_ ]*w  
sudo docker [option] [command] [arguments] zorTZ #5  
l7r!fAV-f  
tEl4 !v A  
注:Docker的运行需要sudo权限。 <WGl4#(k  
L%.GKANM  
S,,3h0$X  
Docker命令 Az2$\  
下面列出了目前可用的Docker命令(译注:可以参考InfoQ中文站文章深入浅出Docker(二):Docker命令行探秘): :22IY> p  
0|:Ic,  
0R2 AhA#  
attach    附着到一个运行的容器上 Q(KLx)  
build     从一个Dockerfile建立镜像 =7mR#3yt  
commit    将一个变更后的容器创建为一个新镜像 8D:{05  
cp        在容器和本地文件系统之间复制文件/目录 RfB""b8]=  
create    创建一个新的容器 ZCMB]bL-e  
diff      检测容器文件系统的变更 BKm$H! u  
events    从服务获取实时事件 q'?:{k$%  
exec      在一个运行中的容器内执行命令 gH0B[w ]  
export    将一个容器的文件系统输出为tar压缩包 V|.aud=7z  
history   显示一个镜像的历史 zY|]bP[NEH  
images    列出镜像列表 v) q6  
import    从tarball压缩包导入内容以创建一个文件系统镜像 fwRlqfi  
info      显示系统信息 u hP0Zwn  
inspect   返回容器或镜像的底层信息 ;NRT a*  
kill      杀死一个运行中的容器 tGd<{nF%2  
load      从一个tar压缩包或STDIN加载一个镜像 v-) eT  
login     登入Docker注册表(Docker registry) l#o43xr  
logout    从Docker注册表登出 )B*?se]LJ  
logs      抓取一个容器的日志 \sC0om,  
network   管理Docker网络 KW&&AuPb}  
pause     暂停一个容器内的所有进程 fu=}E5ScK  
port      列出该容器的所有端口映射或指定端口映射 >UJ&noUD#:  
ps        列出容器列表 vO{ijHKE  
pull      从注册表拉取一个镜像或仓库 ojVpw4y.  
push      往注册表推送一个镜像或仓库 S53%*7K.  
rename    重命名容器 Whd4-pR8  
restart   重启容器 7"xd'\c@  
rm        删除一个或多个容器 vt mO  
rmi       删除一个或多个镜像 7 Nwi\#o  
run       在一个新的容器中运行一条命令 45j+n.9=  
save      将镜像保存至tar压缩包 ].dTEzL9X  
search    在Docker Hub搜索镜像 yK?~X V:  
start     启动一个或多个容器 Ip4NkUI3T  
stats     显示容器资源使用情况的实时信息流 X_'.@q<!CV  
stop      停止一个运行中的容器 MmWJYF=  
tag       向注册表标记一个镜像 L''0`a. +S  
top       显示一个容器下运行的进程 @gi Y  
unpause   恢复运行一个容器里所有被暂停的进程 $xu?zd"  
update    更新容器的资源 2 J4|7UwJ  
version   显示Docker版本信息 6eDIS|/  
volume    管理Docker卷 j|`{ 1`'  
wait      阻塞对指定容器的其他调用方法,直到容器停止后退出阻塞。 @L<[38  
FOk @W&  
]Hd 0 Y%  
创建Docker容器作为Python WSGI应用的沙箱 YRp\#pVnZ  
我们已经完成了Docker的安装,也熟悉了基本的命令,现在可以为我们的Python WSGI应用创建Docker容器了。 jm-0]ugY&`  
U[A*A^$c}  
@5?T]V g  
注:本章介绍的方法主要是练习用,并不适合于生产环境。生产环境下适用的自动化流程将在后续章节中介绍。 =|U2 }U;  
"]_|c\98  
btOTDqG`a  
在Ubuntu里创建打底Docker容器 7t04!dD}  
Docker的run指令会基于Ubunt镜像创建一个新的容器。接下来,我们要用 -t 标识给这个容器附着(attach)一个终端,并运行一个 bash 进程。 |Lhz^5/  
<,E*,&0W  
>|Jw,,uf  
我们将暴露这个容器的80端口用于从外部访问。以后在更加复杂的环境中,你可能需要给多个实例做负载均衡,把不同的容器“连接”起来,再用一个反向代理容器去访问它们。 rp'fli?0e  
S-rqrbr|AT  
f0D Ch]  
sudo docker run -i -t -p 80:80 ubuntu /bin/bash Pm1 " 0  
kQ#eWk J,  
`>sqP aD  
注:运行这个命令时,Docker可能需要先下载一个Ubuntu镜像,下载完毕后才创建新容器。 7&At _l_  
Mb>6.l  
"qj[[L Q  
注意:你的终端会“附着”(attach)在新创建的容器上。要与容器分离并回到之前的终端访问点,可以按 CTRL+P 接着 CTRL+Q 执行脱离操作。“附着”在一个Docker容器上,基本上相当于从一个VPS内部访问另一个VPS。 /B!m|)h5~  
fjWh}w8  
^z^>]Qd  
从脱离的状态想要回到附着的状态,需要执行如下步骤: NdNfai  
{cv;S2  
ob00(?;H  
用 sudo docker ps 列出所有运行中的容器 og\XLJ}_  
找到之前创建的那个容器的ID x>J3tp$2  
执行 sudo docker attach [id] 完成当前终端到该容器的附着 d_,tXV"z&  
注意:我们在容器内部做的一切操作都将仅限于在容器内部执行,对宿主机是完全没有影响的。 <dN=d3S  
$dnHUBB  
f oVD+\~Y  
安装前的准备工作 P\ s+2/  
要在容器内部署Python WSGI应用(以及我们所需要的工具),首先我们需要对应的软件仓库。然而在Docker默认的Ubuntu镜像里并没有提供仓库(Docker的设计者认为这样有利于保持事物的简化),因此我们需要给我们这个打底镜像添加Ubuntu的universe软件仓库: q8h{-^"  
_B1uE2j9  
A pjqSz"  
echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list 9(l'xuX  
AY;+Ws  
~1'468  
更新一下软件列表: 2`I;f/S d  
Uu X"AFy~\  
668bJ.M\O  
apt-get update +zdkdS,2<  
Qyjuzfmz  
D%idlL2%J  
再给我们的容器安装一些必要的工具: E`4=C@NN+,  
@c !67Z  
GnOo+hB  
apt-get install -y tar \ y|Y3,s  
                   git \ mG~y8nUtp  
                   curl \ ]2%P``Yj  
                   nano \ tTFoS[V  
                   wget \ &&]!+fTZ\(  
                   dialog \ <e&QTyb  
                   net-tools <u?hdwW \  
                   build-essential T+nC>}*jgJ  
3Gl]g/  
B ^(rUR  
安装Python工具 4_%FSW8-  
本文将用一个简单的Flask应用作为示范。如果你用的是其他框架也没关系,安装部署的方法都是一样的。 \u _v7g  
+@u C:3jM  
'D"K`Vw  
再提醒一次:以下所有的命令都是在容器内部执行的,不会影响到宿主机。你可以想象成自己在一个全新的VPS上进行操作。 /C"s_:m;3  
/eRtj:9M  
!;aC9VhSU  
安装Python和pip: d+2O^of:T  
.(1j!B4^  
,N7l/6  
# 安装pip依赖:setuptools Mto~ /  
apt-get install -y python python-dev python-distribute python-pip f76|  
P>T*:!s;  
i5<Va@ru!s  
安装Web应用以及其依赖项 &#oZ>`Qu  
安装我们的应用之前,还是让我们再确认一下所有的依赖都已经就绪。首先是我们的框架——Flask。 Px7g\[]  
g} ~<!VpX  
y[WYH5 &DJ  
因为我们已经装好了pip,所以就直接用pip来安装Flask: KO]?>>5S6  
EOnp!]Y  
]AC!R{H  
pip install flask @oqi@&L'C  
A[ECa{ v  
1xdESorX(  
装好了Flask,创建一个“my_application”文件夹: 9poEUjBI  
uCP6;~Ns  
/IJ9_To  
mkdir my_application ;*4tVp,  
`^bvj]>l  
C|d!'"p  
cd my_application +z jzO]8  
^z%o];  
$|cp;~ 1  
注:如果你想直接部署自己的应用(而不是这里的示范应用),可以参看下面的“小贴士”部分。 .f !]@"\  
ptWG@"j/b  
t1:S!@  
我们的示范应用是一个单页面的“Hello World” Flask应用。下面用nano来创建app.py: L >Ez-  
p[@oF5M  
`m@]  
nano app.py nhQ44qRgQ  
yrE,,N%I  
27*(oT  
把下面这些内容复制到新创建的文件里: >0<KkBH  
(@WDvgi(  
r8 Zyld_@  
from flask import Flask 17n+4J]  
app = Flask(__name__) \o62OfF!  
#lyM+.T  
[aWDD[#j~  
@app.route("/") JhhUg  
def hello(): ~D -JZx  
    return "Hello World!" hP4)8>  
:?$Sb8OuIL  
Gdf1+mi  
if __name__ == "__main__": \C+*loLs  
    app.run() PzMlua  
\`P2Yq  
w;yiX<t<  
按 CTRL+X 再按 Y 键,保存退出。 Msv*}^>  
un$ Z7W/  
+3/k/W  
或者,你也可以使用“requirements.txt”来定义应用的依赖项(比如Flask)。我们还是用nano来创建文件: v9t4 7>V  
P|e:+G7  
f%Z;05  
nano requirements.txt 6Q.{llO  
J8GXI:y  
xZ.~:V03\t  
在文件输入你所有的依赖项(下面只列出两个,如果你需要别的请自行添加): ih+*T1#:(  
[]A"]p  
[)Z 'N/;0  
flask KMxNH,5  
cherrypy iA55yT+  
 _DPB?)!x  
wMH[QYb<*  
按 CTRL+X 再按 Y 键,保存退出。 "8wf.nZ  
NCowt|#t  
/~o7Q$)-b  
注:你可以用pip来生成自定义的依赖项列表。具体的操作方法可以参考这篇Common Python Tools: Using virtualenv, Installing with Pip, and Managing Packages。 %sOWg.0_  
bx hPjAL  
j!zA+hF (  
最后,我们这个应用的文件组织结构是这样的: 2Ueq6IuQ  
D~G5]M,}$  
55 S\&Ad$  
/my_application -M7K8  
    | `3 f_d}b  
    |- requirements.txt  # 描述依赖项的文件 g".d"d{  
    |- /app              # 应用模块(你的应用应该在这个目录下) W4)kkJ  
    |- app.py            # WSGI文件,里面应该包含“app”的实例名称(callable) |A ;o0pL  
    |- server.py         # 可选,用于运行应用服务器(CherryPy) f,St h7y  
!1ML%}vvB,  
1a7!4)\  
注:关于“server.py”,请参阅下面的章节“配置我们的Python WSGI应用”。 ?8 SK\{9r6  
1vB-M6(  
[leW/2i  
注意:上面这些应用的文件、目录都是在容器内部创建的。如果你要在宿主机上自动化构建镜像(这个过程将在下面有关Dockerfile的章节中介绍),则你的宿主机上放置Dockerfile的目录下也需要同样的文件结构。 O0@w(L-  
6OfdD.y  
^y:FjQC:  
小贴士:部署自己的应用 |0tg:\.  
在容器内部搞定应用所需的软件仓库和依赖项 UH5w7M  
上述步骤描述了在容器内创建应用目录的过程。然而在真实场景下,我们往往需要从软件仓库拉取源代码。 285_|!.Y  
1*Sr5N[=  
uWUR3n  
要把你的软件仓库复制到容器内部,有几个方法可以实现。下面介绍其中的两个:  DZ^=*.  
w+q?T  
LYp'vZ!  
# 方法1 RS'} nY}  
# 用git下载源代码 fJX\'Rc\  
# 用法:git clone [源代码所在的URL]  KR&s?  
# 示范: `'u Umyg  
git clone https://github.com/mitsuhiko/flask/tree/master/examples/flaskr CXTt(-FT  
pJd0k"{  
o>2e !7  
# 方法2 =K&#.r  
# 下载源代码压缩文件 D,k(~  
# 用法:wget [源代码压缩文件所在的URL] pFpZbU^  
# 示范:(用真实的URL替换掉下面这个假的) ,:^ N[b   
wget http://www.github.com/example_usr/application/tarball/v.v.x gF3TwAr  
[!G)$<  
xS"$g9o0  
# 解压缩文件 4GVNw!V  
# 用法:tar vxzf [文件名 .tar (.gz)] NUMi])HkN  
# 示范:(用真实的文件名替换掉下面这个假的) #Rc5c+/(  
tar vxzf application.tar.gz oAY_sg+  
W}>=JoN^J  
Xem 05%,  
# 用pip下载安装应用依赖 ^\:yf.k  
# 下载 requirements.txt (可以用 pip freeze output 生成),再用pip全部安装: s|Zx(.EP  
# 用法:curl [requirements.txt 文件的URL] | pip install -r - cS}r9ga Q  
# 示范:(用真实的URL替换掉下面这个假的) yLW/ -%I#u  
curl http://www.github.com/example_usr/application/requirements.txt | pip install -r - co/7lsW  
Ivsb<qzG  
1i u =Y  
配置我们的Python WSGI应用 6yI}1g  
要运行这个应用,我们需要一个Web服务器。运行这个WSGI应用的Web服务器需要安装在代码所在的同一台容器中,作为该Docker容器运行的进程。 O-j$vzHpdY  
a+41Ojv (  
{rC~ P  
注:我们在示范中将使用CherryPy自带的HTTP Web服务器,这是一个比较简单而且可以用在生产环境的选择。你也可以用Gunicorn甚至uSWGI(可以让它们跑在Nginx的后面),我们其他的教程中介绍过这种用法。 #XI"@pD  
L~dC(J)@ZI  
:M j_2  
用pip下载安装CherryPy: RlsVC_H\  
Wt J{  
o 7G> y#Y  
pip install cherrypy (;}tf~~r  
?U_9{}r  
0KAj]5nvb  
创建“server.py”,用于服务“app.py”里面的Web应用: Pdw#o^Iq^  
S$e Dnw~$  
: ,p||_G&  
nano server.py C c*( {  
 ]>Si0%  
qX$u4I!,  
把下面的内容复制粘贴到server.py里: :[sOKV i  
g_w&"=.jBq  
 i-W  
# 导入应用的语法: t};~H\:  
# from app import application )`8pd 7<.  
# 示范: Km3&N  
s /%:dnij  
7 ({=*  
from app import app h1+ hds+  
?t rV72D  
\M(* =5  
# 导入 CherryPy !QEL"iJ6M'  
import cherrypy *Msr15  
Y ?'tUV  
ALGg AX3t  
if __name__ == '__main__': !@g)10u  
44sy`e  
?znSx}t  
    # 挂载应用 ?a.+j8pbGg  
    cherrypy.tree.graft(app, "/") 0{) $SY  
R$m`Z+/@  
R1ktj  
    # 从默认服务器上分离 6EJVD!#[K  
    cherrypy.server.unsubscribe() (j&A",^^S  
_:J*Cm[q  
N4UM82N  
    # 实例化一个新的服务器对象 <]G${y*;  
    server = cherrypy._cpserver.Server() ;sPzOS9  
/_\W+^fE  
N.j "S'(i  
    # 配置该服务器对象 J]pa4C`  
    server.socket_host = "0.0.0.0" onte&Ed\  
    server.socket_port = 80 F}X0',   
    server.thread_pool = 30 #^rU x.  
zAScRg$:?  
O}Le]2'  
    # SSL相关配置 Q M 1F?F  
    # server.ssl_module            = 'pyopenssl' G&9#*<F$c  
    # server.ssl_certificate       = 'ssl/certificate.crt' "uD= KlA  
    # server.ssl_private_key       = 'ssl/private.key' HGDV O Jq  
    # server.ssl_certificate_chain = 'ssl/bundle.crt' BC/_:n8O  
{3edTu  
H{fM%*w  
    # 订阅这个服务器对象 ,&]MOe4@>  
    server.subscribe() \pY^^ l*  
BW Uq%o,@g  
RiFw?Q+  
    # 启动服务器引擎 K5"sj|d&  
LSd*| 3E}n  
O/OiQ^T  
    cherrypy.engine.start() O\beKBT;  
    cherrypy.engine.block() 6yIvaY$KR  
/"#4T^7&  
E{Vo'!LY  
完成!现在我们就有了一个“Docker化”的Python Web应用,安全的跑在自己专属的沙箱里。只要输入下面的一行命令,它就可以给成千上万个客户端请求提供服务: eD;6okdP  
>PalH24]  
{aj/HFLNY  
python server.py FY#!N L  
.v`b[4M4  
Cmd329AH  
这是让服务器在前台运行的指令。按下 CTRL+C 终止运行。如果想在后台运行服务器,可输入下面的指令: eaZQ2  
5cfA;(H  
lZ+!H=`  
python server.py & jBtj+ TL8  
F=wRkU  
@h9MxCE!  
后台运行的应用需要用进程管理器(比如htop)来终止运行(kill或stop)。 :jem~6i  
a/:XXy |  
&a)vdlZSE=  
注:有关CherryPy上跑Python应用的配置,可参阅这篇教程:How to deploy Python WSGI apps Using CherryPy Web Server。 TT}]wZ  
Omyt2`q  
-q>^ALf|@>  
简单的测试一下应用的运行状态(以及端口的分配状态):在浏览器中访问 http://[容器所在的VPS的IP地址] ,应该能够看到“Hello World!”。 Plo,XU  
Je7RrCz  
bI ITPxz  
创建Dockerfile以实现镜像创建的自动化 l?E|R Kp  
上面简单的说过,手动创建容器的这个方法并不适合用于生产环境的部署。生产环境里应该用Dockerfile进行构建流程自动化。 Zz"}Cz:bX  
(.X]F_ *sc  
FxU'LN<;HY  
我们已经知道了如何在容器内部进行外部资源的下载和安装,那么Dockerfile其实也是一样的原理。一个Dockerfile定义了Docker要如何生成一个镜像,这个镜像可以直接用来跑我们的Python应用。 IB$7`7  
t9 F=^)s  
}STYG`  
先了解一下Dockerfile的基本功能。 v.g"{us  
$RO$}!  
O6c\KFBSJ  
Dockerfile概述 \U@3`  
Dockerfile是一种脚本文件,其中包含了一系列顺序执行的命令,Docker通过执行这些命令就可以创建一个新的Docker镜像。这极大的方便了部署。 P%>?[9!Nt  
O!F]^'!  
&7[[h+Lb  
Dockerfile一般会先用 FROM 命令定义一个打底的镜像,然后执行一系列的动作,动作全部执行完毕之后就形成了最终的镜像,并将完成的镜像提交给宿主机。 P:!)9/.2  
i$Z#9M9  
(xT*LF+  
使用: AXW!]=?X  
$k0H9_  
cf;Ht^M\  
# 在当前位置用Dockerfile创建一个镜像 GESXc $E8  
# 将生成的镜像标记为 [name] (比如nginx) 0|Uc d  
# 示范:sudo docker build -t [name] . (JZ".En#X  
sudo docker build -t nginx_img . !]b@RUU  
8Qrpa o  
%_f;G+fK\p  
注:我们还有一篇专门介绍dockerfile的文章可供查阅:Docker Explained: Using Dockerfiles to Automate Building of Images ef]B9J~h  
- q@69q  
G\~^&BAC  
Dockerfile命令一览 b1^cD6sT+  
### Add `deY i2z  
从宿主机复制文件到容器 Y1\K;;X  
z +VV}:Q  
l4T:d^Eb  
`wO}Hz  
\{v,6JC  
### CMD Ft-6m%  
设置要执行或者要发给ENTRYPOINT的默认命令 d-$_|G+  
`,#!C`E 9  
*\ECf .7jz  
q627<  
^.HWkS`e  
### ENTRYPOINT <GZhH:  
设置容器内默认要启动的应用 +R\~3uj[7  
^gg!Me  
#PAU'u 3{/  
|]ucHV  
8hB.fau  
### ENV p;->hn~D'5  
设置环境变量(key = value) ?qT(3C9p  
0XIxwc0Iw  
p24.bLr  
### EXPOSE A ,<@m2  
暴露一个端口 RVF F6N^  
gCV rC  
JlIS0hnv  
### FROM r)B3es&&  
设置打底镜像(base) 0yQe5i}  
E .;io*0  
uUS)#qM |  
### MAINTAINER JQT4N[rEE  
设置Dockerfile的作者/所有者信息 \=g!$  
'j#a%j@{  
A-0m8<  
### RUN 065A?KyD  
执行一条命令并提交执行后的(容器)镜像 Pd],}/ZG-  
l $Zs~@N  
sT1j F3  
### USER U_Y;fSl>  
设置从镜像运行容器的用户名 0UjyMEiK  
}AAbhr9d}  
uXNp!t Y  
### VOLUME mxhW|}_-j  
从宿主机加载一个目录给容器 _z%\'(l+  
G>j "cj  
i*A$SJ:}  
### WORKDIR b,vL8*  
设置CMD运行时所在的目录 c#x7N9;"!  
dw99FA6  
4ioN A/E  
创建Dockerfile ASM1Y]'Z  
在当前路径下用nano编辑器创建Dockerfile: ~,+[M-  
gQCC>8  
|vT=Nnu  
sudo nano Dockerfile )#mW7m9M#  
1 '%$-]~   
注:下面的内容需要按顺序添加到Dockerfile中。 Qv=Bq{N  
C }bPv +t  
jaNH](V  
定义基本项 X)Ocn`|  
Dockerfile的基本项包括 FROM 原始镜像(比如Ubuntu)以及维护者姓名 MAINTAINER: fl!1AKSn@N  
<WgG=Kf)N  
":z@c,  
############################################################ 7TR' zW2W  
# 创建Python WSGI应用容器的Dockerfile Z#[>N,P  
# 基于Ubuntu %Ln?dF+  
############################################################ 739l%u }<  
W>VAbm  
B##C{^5A`  
# 设置Ubuntu为打底镜像 RNl\`>Cz  
FROM ubuntu jCam,$oE  
~F=#}6kg_  
E^'C "6  
# 文件作者/维护者 FC~|&  
MAINTAINER Maintaner Name ]Oig ..LJ  
m|(I} |kT3  
~ rQ4n9G  
更新默认的应用仓库 rZb_1E<  
# 添加软件资源库的URL #r-j.f}yx  
RUN echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list e=YO.HT  
8UjCX[v  
zvWO4\  
# 更新资源列表 k?z [hZg0  
RUN apt-get update z2"2tFK  
q^Q|.&_k /  
U+I3P  
安装基础工具 (mu{~@Hw  
RUN apt-get install -y tar git curl nano wget dialog net-tools build-essential fbi H   
~Q3WBOjn  
\5j22L9S  
注:上述的有些工具可能你用不到,不过为了以防万一还是都装进来先。 l;"ub^AH  
ghE?8&@ iq  
1e+h9|hGYw  
Python基础套装安装指南 ]Hv*^Bak  
一些Python需要的工具(pip)最好还是都先装起来。你的框架(WAF)和Web服务器(WAS)都需要有它们才能安装。 !W(/Y9g#  
gs^UR6 D,  
?w c3 +?\J  
RUN apt-get install -y python python-dev python-distribute python-pip dn:|m^<)  
g: H[#I  
PprQq_j  
部署应用 W]C_oh  
部署应用可以使用Docker的 ADD 命令直接复制源代码,也可以用 REQUIREMENTS 文件来一步到位。 B h.6:9{  
?];~N5<'  
@k#z &@b  
注:如果你打算用一个文件描述所有的代码位置,可以参考下面的文件结构。 uL qpbn  
q70YNk}  
Vj9`[1}1Z  
    文件结构示范 (STWAwK-  
)%nt61P\W  
o} bj!h]N  
    /my_application &~D.")Dz  
    | T3B |r<>I  
    |- requirements.txt  # 描述依赖项的文件 q]wn:%rX  
    |- /app              # 应用模块(你的应用应该在这个目录下) iZVT% A+q  
    |- app.py            # WSGI文件,里面应该包含“app”的实例名称(callable) e!L sc3@  
    |- server.py         # 可选,用于运行应用服务器(CherryPy) 'J&@jp  
WZDokSR  
b5iJ m-  
这个文件结构的创建过程在前面的章节中已经介绍过,这里不再赘述。总之,以上述文件结构为例,则再给Dockerfile末尾添加如下内容,将源代码复制到容器内: 0B!mEg  
*N&^bF"SF  
qH}62DP3  
ADD /my_application /my_application ?_<UOb*  
;d'O.i=  
t' _,9  
如果源代码是公网的git仓库,则可以使用如下内容: N5I W@?4  
[W7\c;Do  
a 7mKshY(  
RUN git clone [你的源码仓库URL]  Lqf#,J  
]#Z$jq{,  
|Jx2"0:M  
引导 l1.Aw|'D  
接下来,再从 requirements.txt 导入所有的依赖项: E6KBpQcd[  
Fr Q-v]c  
13NS*%~7[  
# 用pip来下载安装 requirements.txt 里面的东西 L-oPb)  
RUN pip install -r /my_application/requirements.txt c)P%O  
'~vSH9nx/  
ef1N#z%gt  
# 暴露端口 +'6ea+$  
EXPOSE 80 +cplM5X  
MRY)m@*+6  
c Dh4@V  
# 设置CMD运行的默认路径 V IRv  
WORKDIR /my_application ^`PSlT3<F  
9.w3VF_C  
#I@[^^Vw  
# 要运行的默认命令 R~mMGz  
# 该命令在新容器创建时开始执行 = ,E(!Sp  
# 比如启动CherryPy来运行服务 $hY]EB  
CMD python server.py Ss#{K;  
DB?PS^-2  
n<(5B|~y  
最终的Dockerfile ,EJ [I^  
现在,整个Dockerfile看起来应该是这样的: 6W#F Ss~  
HW%bx"r+4f  
4lo}-@j  
############################################################ #z54/T  
# Dockerfile to build Python WSGI Application Containers d4=u`2w  
# Based on Ubuntu _ .   
############################################################ JdNPfkOF  
>71w #K  
G&@RLht  
# Set the base image to Ubuntu ra#)*fG,~  
FROM ubuntu 0JWD] "  
IHX#BY>  
[tw<TV"\  
# File Author / Maintainer Ku\#Wj|YrP  
MAINTAINER Maintaner Name U=?"j-wN  
*[/Xhx"  
gJfL$S'w  
# Add the application resources URL x/q$RcDOm  
RUN echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list UDqKF85H  
BGYm]b\j[  
@<{ #v.T  
# Update the sources list @x>2|`65Y  
RUN apt-get update #)eJz1~  
D`@U[`Sw  
G:s:NXy^  
# Install basic applications HbVV]y  
RUN apt-get install -y tar git curl nano wget dialog net-tools build-essential <(lSNGv5N  
J0 z0%p   
6_ 0w>  
# Install Python and Basic Python Tools =ZL}Av}  
RUN apt-get install -y python python-dev python-distribute python-pip 5} aC'j\  
VNot4 62L  
l\y*wr`  
# Copy the application folder inside the container ="e um7  
ADD /my_application /my_application \ } Szb2  
h>Pg:*N,(  
;|%JvptwW%  
# Get pip to download and install requirements: 7anpz%  
RUN pip install -r /my_application/requirements.txt ~7H.<kJt  
W5uI(rS<6  
+Y[+2=lO  
# Expose ports i^KYZ4/%  
EXPOSE 80 ?b$zuJ]  
-+Dvyr  
R?Q-@N>wE  
# Set the default directory where CMD will execute 9\0 K%LL  
WORKDIR /my_application nU *fne?  
4>#^Pk?Ra  
LK5H~FK  
# Set the default command to execute     *G=AhH$t  
# when creating a new container sYgnH:t X  
# i.e. using CherryPy to serve the application JH;DVPX9z  
CMD python server.py <}1%">RA  
9Q1GV>j>B  
6p{x2>2y[  
按 CTRL+X 再按 Y 键,保存退出。 c!T{|'?  
cyE2=  
?@(H. D6'v  
使用Dockerfile进行自动化的容器创建 g7F Z -  
在之前的基础教程部分我们提到过,Dockerfile的工作方式利用到了 docker build 命令。 Xlw=R2`)~  
AUV$ S2  
ge8zh/`  
我们通过Dockerfile指示docker从包含源代码的路径复制内容到容器内部,因此在构建之前务必要确认Dockerfile与代码路径的相对位置。 ".ZiR7Z:$Y  
FCPRg^=<!~  
bb/MnhB  
这样一个Docker镜像可以快速创建起来一个可以运行我们的Python应用的容器,我们需要做的只是输入这样一行指令: dY.uOafr  
6vA 5;a@  
uy{KV"%"^g  
sudo docker build -t my_application_img . uSjMqfK  
L]}|{< 3\  
7:%K-LeaQu  
我们把这个镜像命名为 my_application_img 。为要从这个镜像启动一个新的容器,只需要输入下面的命令: V:J6eks_  
2ZeL  
Hyg?as>}u  
sudo docker run -name my_application_instance -p 80:80 -i -t my_application_img 7 d5x4^EYE  
GAlO<Mu  
78-:hk  
然后就可以在浏览器里输入你VPS的IP地址,访问应用了。 -~k2Gy;E  
8=9sIK2  
opC11c/  
有关Docker安装的更多教程(包括在其他发行版上安装Docker),可以查阅我们在docker.io上的文档docker installation documentation。 TW0^wSm  
'5--eYG  
[ 此帖被寒喵在2018-12-29 19:19重新编辑 ]
本人不是云栖社区工作人员。
无论您在使用中遇到什么问题,不要出言不逊!谢谢合作!
发表主题 回复主题
« 返回列表上一主题下一主题

限100 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
验证问题: 75 - 56 = ?
上一个 下一个
      ×
      全新阿里云开发者社区, 去探索开发者的新世界吧!
      一站式的体验,更多的精彩!
      通过下面领域大门,一起探索新的技术世界吧~ (点击图标进入)