阿里云
阿里云大学认证0元起
发表主题 回复主题
  • 107阅读
  • 0回复

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

级别: 论坛版主
发帖
370
云币
639

前言 WpmypkJA#  
Web应用随时可能被攻击者利用来夺取整个主机的权限,这是很常见也是很恐怖的一件事。为了更高的安全性,就需要将不同应用之间进行隔离(尤其是在这些应用属于不同的用户的情况下),然而这种隔离的实现一直是个挑战。到目前为止,隔离性的实现方法已经有了很多,然而它们要么太过昂贵(时间的层面以及资源的层面),要么太过复杂(无论对开发者还是对管理员)。 L;BYPZR  
br'~SXl  
U*6-Y%7  
本文将讨论如何让“容器化”的Python Web应用跑在安全的沙箱里,严格的坚守在其各的环境中(当然,除非你指定它们与其他应用进行“连接”)。我将一步一步的介绍如何创建一个Docker容器,如何用这个容器来跑我们的Python Web应用,以及如何用一个Dockerfile来描述整个构建过程以实现完整的自动化。 1noFXzeU3  
sPd5f2'  
?*4]LuK6  
目录 T-<^mX[}  
1. Docker概述 `w~ 9/sty  
2. 在Ubuntu上安装Docker kMI\GQW  
3. 基本的Docker命令 v $ pA Rt  
Docker的守护进程与命令行 3QXGbu}:h!  
Docker命令 59EAqz[:  
4. 创建Docker容器作为Python WSGI应用的沙箱 c 6?5?_ne  
在Ubuntu里创建打底Docker容器 ` 0\hm`  
安装前的准备工作 *b.>pY?2|  
安装Python工具 y()#FRp7  
安装我们的Web应用以及其依赖项 hs/nM"V  
配置我们的Python WSGI应用 5_`.9@eh.  
5. 创建Dockerfile以实现镜像创建的自动化 5[Q44$a{  
Dockerfile概述 ]k,fEn(  
Dockerfile命令一览 I7[+:?2  
创建Dockerfile 7Y!^88,f.  
定义基本项 <-lz_  
更新默认的应用仓库 b!`:|!7r'  
安装基础工具 LW2Sko?Yo  
Python基础套装安装指南 xQmk2S` y  
部署应用 Y %<B,3  
引导 !Noabt  
最终的Dockerfile g[eI-J+F  
使用Dockerfile进行自动化的容器创建 bk>M4l61  
Docker概述 g5Hs=c5=\  
Docker项目提供了一些可以搭配使用的上层工具,这些工具基于Linux内核的一些功能创建。整个项目的目标是帮助开发者和系统管理员门无痛的迁移应用(以及它们所涉及的所有依赖项),让应用在各种系统和机器上都能欢快的跑起来。 .#+rH}=Z  
q=R=z$yr  
O %)+ w  
实现这个目标的关键在于一个叫做docker容器的运行环境,这个环境实际上是一个具备安全属性的LXC(Linux Containers)。容器的创建使用了Docker镜像,Docker镜像可以手动敲命令创建,也可以通过Dockerfiles实现自动化创建。 ?rv+ydR/q  
!(o)*S  
K zM\+yC  
注:关于Docker的基础知识(守护进程、CLI、镜像等等),可参阅本系列的第一篇文章Docker Explained: Getting Started。 d<Z`)hI{K  
>iG`  
6.By)L  
在Ubuntu上安装Docker }Y-f+qX*  
最新版本的Docker(译注:本文撰写时间为2013年12月17日,当时的Docker最新版本为0.7.1)可以在Ubuntu/Debian和CentOS/RHEL等多个Linux发行版上部署(你也可以使用DigitalOcean上现成的Docker镜像,该镜像基于Ubuntu 13.04创建)。 7p~@S4  
9OTw6  
Ky$ <WZs  
下面快速介绍一下Ubuntu上的安装流程。 y2<g96  
{&2$1p/9'  
}}Q|O]e  
在Ubuntu上安装Docker 73]%^kx=  
更新系统: 3J [P(G>Q  
f[dwu39k  
"+)ey> _  
sudo aptitude    update v#nFPB=z  
sudo aptitude -y upgrade 4q~l ?*S  
GLk7# Y  
%r|fuwwJO  
检查系统是否支持aufs: y`\/eX  
n#x{~oQc  
AWf zMJ;VS  
sudo aptitude install linux-image-extra-`uname -r` ~(yh0V  
fTH?t_e  
WM>9sJf  
往apt-key添加Docker仓库的密钥(用于软件包的验证):  Q.cxen  
n*-#VKK^  
B8;ZOLAU  
sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -" ~v<r\8`OI2  
h~F uuL  
Q <78< #I  
往aptitude软件源添加Docker仓库: ,Q}/#/  
^]Gt<_  
 snN1  
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\ > m5j.GP;  
> /etc/apt/sources.list.d/docker.list" W'6*$Ron  
o 'yR^`  
Ebp8})P/~  
添加之后再更新一次系统: Que)kjp  
wd1*wt  
46$u}"E  
sudo aptitude update ;rk}\M$+  
/e\} qq  
;9;.!4g/T  
最后,下载并安装Docker: Imv kB~8N  
%PyU3  
;r`[6[AG  
sudo aptitude install lxc-docker ( XE`,#  
SHh g&~B  
OlV>zam  
Ubuntu默认的防火墙(UFW)的默认设置是拒绝一切转发(forwarding),但是Docker需要转发,所以也需要设置一下UFW。 i(YP(8  
|w\D6d]o  
Z1q '4h=F.  
用nano编辑器打开UFW配置文件: AbfLV942  
@.MM-  
lOZ.{0{f,  
sudo nano /etc/default/ufw 17nWrTxR$  
EB>laZy>  
,`H=%#  
找到DEFAULT_FORWARD_POLICY这一行,将 ku`'w;5jT  
U,g!KN3P  
M*0&3Y Z  
DEFAULT_FORWARD_POLICY="DROP" ts)0+x  
jixU9]  
Tk+\Biq   
替换为: m>UJ; F  
oYOf<J  
(|bht0  
DEFAULT_FORWARD_POLICY="ACCEPT" >-oa`im+  
|nocz]yU$  
s31^9a  
按 CTRL+X 再按 Y 键,保存退出。 ^3*gf}  
pz-`Tp w  
v*#Z{)r  
最后,把UFW重启一下: S;*,V |#QD  
>,1'[) _  
W%Um:C\I  
sudo ufw reload !.p!  
> %d]"]  
to,=Q8 )0  
基本的Docker命令 mflI>J=g  
在正式开始之前,我们还是先复习一下上次在基础篇中介绍过的一些基本命令。 RV&2y=eb  
>} aykz*g  
_+^3<MT  
Docker的守护进程与命令行 t,MK#Ko  
一般来说,Docker守护进程在你安装完成了之后就已经在后台运行,等待接收来自Docker命令行的指令。不过有的时候我们也需要手动启动Docker守护进程: 5X~ko>  
/mr&Y}7T  
}KZ/>Z;^  
sudo docker -d & %zX'u.}8#  
$ar:5kif  
rhL<JTS  
Docker命令行的基本语法如下: q2,@>#  
w*bVBuX s  
RRq*CLj  
sudo docker [option] [command] [arguments] D Zh6/n#q  
faJ5f.  
2RM1-j ($  
注:Docker的运行需要sudo权限。 oWJ}]ip  
Ppx*  
 W#??fae  
Docker命令 J-X5n 3I&  
下面列出了目前可用的Docker命令(译注:可以参考InfoQ中文站文章深入浅出Docker(二):Docker命令行探秘): OFUN hbg  
O<%U*:B  
e348^S&rG  
attach    附着到一个运行的容器上 \HH|{   
build     从一个Dockerfile建立镜像 ClfpA?vv  
commit    将一个变更后的容器创建为一个新镜像 $_)f|\s  
cp        在容器和本地文件系统之间复制文件/目录 .h*&$c/l  
create    创建一个新的容器 /M'b137  
diff      检测容器文件系统的变更 0@xuxm/i  
events    从服务获取实时事件 Ye )(9  
exec      在一个运行中的容器内执行命令 r#{lpF,3Ib  
export    将一个容器的文件系统输出为tar压缩包 )6AOP-M.9  
history   显示一个镜像的历史 _$Fi]l!f  
images    列出镜像列表 huN(Q{fj  
import    从tarball压缩包导入内容以创建一个文件系统镜像 1B WuFYB  
info      显示系统信息 WG^D$L:  
inspect   返回容器或镜像的底层信息 ]|732Z  
kill      杀死一个运行中的容器 B8IfE`  
load      从一个tar压缩包或STDIN加载一个镜像 ? X:RrZ:/  
login     登入Docker注册表(Docker registry) eueXklpg+  
logout    从Docker注册表登出 E!Ng=}G&_  
logs      抓取一个容器的日志 &1Az`[zKGW  
network   管理Docker网络 ? 8~$du$  
pause     暂停一个容器内的所有进程 =jG3wf*  
port      列出该容器的所有端口映射或指定端口映射 !C/`"JeYL  
ps        列出容器列表 -7+Fb^"L  
pull      从注册表拉取一个镜像或仓库 7l:H~"9r  
push      往注册表推送一个镜像或仓库 7IIM8/BI  
rename    重命名容器 t@4vEKw?.X  
restart   重启容器 WcUeWGC>  
rm        删除一个或多个容器 w=f8UtY9@A  
rmi       删除一个或多个镜像  m+vwp\0  
run       在一个新的容器中运行一条命令 1hMk\ -3S  
save      将镜像保存至tar压缩包 s5z@`M5'm  
search    在Docker Hub搜索镜像 gjs-j{*  
start     启动一个或多个容器 >>!+Ri\@  
stats     显示容器资源使用情况的实时信息流 r+Z+x{  
stop      停止一个运行中的容器 T]i~GkD\  
tag       向注册表标记一个镜像 $/d~bk@=l  
top       显示一个容器下运行的进程 ||_F /AD  
unpause   恢复运行一个容器里所有被暂停的进程 "#JoB X@yE  
update    更新容器的资源 LLU>c]a  
version   显示Docker版本信息 h{TnvI/"  
volume    管理Docker卷 _c #P  
wait      阻塞对指定容器的其他调用方法,直到容器停止后退出阻塞。 9(B)  
=0v{+ #}  
[S9nF  
创建Docker容器作为Python WSGI应用的沙箱 JHMj4Zkp  
我们已经完成了Docker的安装,也熟悉了基本的命令,现在可以为我们的Python WSGI应用创建Docker容器了。 }M9'N%PU  
c76^x   
pYa<u,>pN  
注:本章介绍的方法主要是练习用,并不适合于生产环境。生产环境下适用的自动化流程将在后续章节中介绍。 wYF)G;[wM  
E3KP jK  
Q2#)Jx\6!  
在Ubuntu里创建打底Docker容器 2OZdj  
Docker的run指令会基于Ubunt镜像创建一个新的容器。接下来,我们要用 -t 标识给这个容器附着(attach)一个终端,并运行一个 bash 进程。 N4D_ 43jz  
5N[Y2  
AM}OL Hj  
我们将暴露这个容器的80端口用于从外部访问。以后在更加复杂的环境中,你可能需要给多个实例做负载均衡,把不同的容器“连接”起来,再用一个反向代理容器去访问它们。 ho:,~ A;k  
"iKK &%W  
DSIa3! 0  
sudo docker run -i -t -p 80:80 ubuntu /bin/bash w}2yi#E[  
* dNMnZ@Y  
OrRve$U*|  
注:运行这个命令时,Docker可能需要先下载一个Ubuntu镜像,下载完毕后才创建新容器。 4frZ .r;V  
pFG~XW  
:r~?Z6gK  
注意:你的终端会“附着”(attach)在新创建的容器上。要与容器分离并回到之前的终端访问点,可以按 CTRL+P 接着 CTRL+Q 执行脱离操作。“附着”在一个Docker容器上,基本上相当于从一个VPS内部访问另一个VPS。 aH >.o 1;  
"%Rx;xw|  
!AMPA*  
从脱离的状态想要回到附着的状态,需要执行如下步骤: nH_A`m3%/  
66BsUA.h  
,qr)}s-  
用 sudo docker ps 列出所有运行中的容器 k,&W5zBKe  
找到之前创建的那个容器的ID t qER;L  
执行 sudo docker attach [id] 完成当前终端到该容器的附着 *X)OdU  
注意:我们在容器内部做的一切操作都将仅限于在容器内部执行,对宿主机是完全没有影响的。 c[;I\g  
Cvl"")ZZ`  
_PRm4 :  
安装前的准备工作 LAvAjvRc  
要在容器内部署Python WSGI应用(以及我们所需要的工具),首先我们需要对应的软件仓库。然而在Docker默认的Ubuntu镜像里并没有提供仓库(Docker的设计者认为这样有利于保持事物的简化),因此我们需要给我们这个打底镜像添加Ubuntu的universe软件仓库: ~o8$/%Oeb/  
U3Dy:K[  
swJwy~  
echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list .rMGI "  
wv*r}{%7g[  
2R1W[,Ga!  
更新一下软件列表: WM"I r1  
b. t]p  
8 {QvB"w  
apt-get update K1$Z=]a+  
S]9xqiJW  
5^5h%~)}  
再给我们的容器安装一些必要的工具: &KD m5p  
OgzPX^q/=  
iKdC2m  
apt-get install -y tar \ fa6L+wt4O  
                   git \ :oZ30}  
                   curl \ S[%86(,*gP  
                   nano \ #2`tsZ]=I  
                   wget \ LUCpZ3F1  
                   dialog \ $A-b-`X  
                   net-tools 3<'n>'  
                   build-essential }5% !: =  
bS0LjvY9g  
"rX`h  
安装Python工具 \75%[;.  
本文将用一个简单的Flask应用作为示范。如果你用的是其他框架也没关系,安装部署的方法都是一样的。 ++FMkeHZ  
6T)D6;@L  
u9?85  
再提醒一次:以下所有的命令都是在容器内部执行的,不会影响到宿主机。你可以想象成自己在一个全新的VPS上进行操作。 '|6j1i0x  
jaDZPX-yS  
Qn6&M  
安装Python和pip: x2 tx{Z  
3s$m0  
~s !+9\Fi  
# 安装pip依赖:setuptools "Z,'NL>&  
apt-get install -y python python-dev python-distribute python-pip 8_:jPd! 3  
=b6Q2s,i  
*O+N4tq  
安装Web应用以及其依赖项 NB LOcRSh  
安装我们的应用之前,还是让我们再确认一下所有的依赖都已经就绪。首先是我们的框架——Flask。 7Xw #  
I*'QD)  
(m@({  
因为我们已经装好了pip,所以就直接用pip来安装Flask: SB]|y -su  
qex.}[  
z m_mLk$4H  
pip install flask gx #TRp}-  
 O'_D*?  
;ML21OjgN  
装好了Flask,创建一个“my_application”文件夹: z}kD:A)a  
<@JK;qm>S  
gzi~ BJ  
mkdir my_application |r6<DEg  
6 Rg{^ERf  
St'3e<  
cd my_application ,US]  
F~&bgl[YZ  
v=@Z,-  
注:如果你想直接部署自己的应用(而不是这里的示范应用),可以参看下面的“小贴士”部分。 !,|yrB&`S  
wzF/`z&0?6  
]iYjS  
我们的示范应用是一个单页面的“Hello World” Flask应用。下面用nano来创建app.py: "Bn!<h}mg  
tP7l ;EX4  
@G^ l`%  
nano app.py B`9'COw  
O cd ^{u  
MejM(o_kk  
把下面这些内容复制到新创建的文件里: O~trv,?)  
%Q]m6ciAM  
6 [w_ /X"  
from flask import Flask R$_#7>3  
app = Flask(__name__) \"|E8A6/  
0LN"azhz  
FUiEayM  
@app.route("/") gT?:zd=;  
def hello(): AEp|#H' >  
    return "Hello World!" R~PD[.\u  
r3{Cuz  
Q6]SsV?x  
if __name__ == "__main__": {f<2VeJ  
    app.run() *FmY4w  
y)CnH4{  
'QeCJ5p]  
按 CTRL+X 再按 Y 键,保存退出。 sWa`-gc  
Z vM~]8m  
M4~^tML>Ey  
或者,你也可以使用“requirements.txt”来定义应用的依赖项(比如Flask)。我们还是用nano来创建文件: )E;B'^RVR  
W; P8=q  
P uYAoKG  
nano requirements.txt "**Tw'  
#R-l2OO^]  
p.~hZ+ x_  
在文件输入你所有的依赖项(下面只列出两个,如果你需要别的请自行添加): (kCzz-_\  
8Qd*OO  
:2ILN.&  
flask {(Jbgsxm  
cherrypy ps[HvV"  
R6eKI,y\"  
mmRxs1 0$  
按 CTRL+X 再按 Y 键,保存退出。 ' d' Dlg  
sVWOh|O[W  
g3B%}!|  
注:你可以用pip来生成自定义的依赖项列表。具体的操作方法可以参考这篇Common Python Tools: Using virtualenv, Installing with Pip, and Managing Packages。 AAuH}W>n  
z_nv|5"  
rr~O6Db  
最后,我们这个应用的文件组织结构是这样的: v'=$K[_  
8vR Q_  
GO4IAUA  
/my_application uC$!|I  
    | :O)\+s-  
    |- requirements.txt  # 描述依赖项的文件 _Fe%Ek1Yy  
    |- /app              # 应用模块(你的应用应该在这个目录下) Z#uxa  
    |- app.py            # WSGI文件,里面应该包含“app”的实例名称(callable) U</Vcz  
    |- server.py         # 可选,用于运行应用服务器(CherryPy) KJ (|skO  
8/gA]I 6=#  
}B1f_T  
注:关于“server.py”,请参阅下面的章节“配置我们的Python WSGI应用”。 x_L5NsO:  
+6~ut^YiM.  
OKi}aQ2R*  
注意:上面这些应用的文件、目录都是在容器内部创建的。如果你要在宿主机上自动化构建镜像(这个过程将在下面有关Dockerfile的章节中介绍),则你的宿主机上放置Dockerfile的目录下也需要同样的文件结构。 n Nu~)X  
D*0[7:NSO  
= q \TWz  
小贴士:部署自己的应用 :Eb=jWA  
在容器内部搞定应用所需的软件仓库和依赖项 Nhf@Y}Cu  
上述步骤描述了在容器内创建应用目录的过程。然而在真实场景下,我们往往需要从软件仓库拉取源代码。 E5iNuJj=f  
KwAc Ga}J  
_|jEuif  
要把你的软件仓库复制到容器内部,有几个方法可以实现。下面介绍其中的两个: `_"loPu  
I_k/lwBD  
(4f]<Qt  
# 方法1 _~Id~b  
# 用git下载源代码 kY?w] lS)t  
# 用法:git clone [源代码所在的URL] Yj"{aFK#u@  
# 示范: mswAao<y&x  
git clone https://github.com/mitsuhiko/flask/tree/master/examples/flaskr KOhK#t>H@0  
[zJ|61^  
`;Od0uh  
# 方法2 zFi)R }Ot  
# 下载源代码压缩文件 gT_tR_g  
# 用法:wget [源代码压缩文件所在的URL] */'j[uj  
# 示范:(用真实的URL替换掉下面这个假的) <s=i5t My5  
wget http://www.github.com/example_usr/application/tarball/v.v.x J7pF*2  
H-iCaXT  
:@4+}  
# 解压缩文件 7I/a  
# 用法:tar vxzf [文件名 .tar (.gz)] {%Rntb  
# 示范:(用真实的文件名替换掉下面这个假的) &|fPskpy  
tar vxzf application.tar.gz qDS~|<Y5  
a9_KoOa.H  
M{t/B-'4  
# 用pip下载安装应用依赖 NOSL b];  
# 下载 requirements.txt (可以用 pip freeze output 生成),再用pip全部安装:  CH$K_\  
# 用法:curl [requirements.txt 文件的URL] | pip install -r - ^U9b)KA  
# 示范:(用真实的URL替换掉下面这个假的) NT=)</v  
curl http://www.github.com/example_usr/application/requirements.txt | pip install -r - MX"M2>"pT  
3Yf~5csY  
Y )68  
配置我们的Python WSGI应用 e}NB ,o  
要运行这个应用,我们需要一个Web服务器。运行这个WSGI应用的Web服务器需要安装在代码所在的同一台容器中,作为该Docker容器运行的进程。 R$x(3eyx  
f5z*AeI  
soOfk!b  
注:我们在示范中将使用CherryPy自带的HTTP Web服务器,这是一个比较简单而且可以用在生产环境的选择。你也可以用Gunicorn甚至uSWGI(可以让它们跑在Nginx的后面),我们其他的教程中介绍过这种用法。 R8>17w.  
Mtaky=l8~I  
[(; .D  
用pip下载安装CherryPy: e$`;z%6y  
e7yn"kd  
DfjDw/{U3L  
pip install cherrypy JLGC'mbJ  
=j%ORD[  
JMfv|>=  
创建“server.py”,用于服务“app.py”里面的Web应用: TB_OFbI2  
x<5;#  
79uAsI2-Y  
nano server.py MKh}2B#S  
bo#?,80L}`  
[5PQrf~Mo  
把下面的内容复制粘贴到server.py里: ikb;,Js  
(g>&ov(d  
l'1_Fb  
# 导入应用的语法: XzW\p8D^u  
# from app import application je74As[  
# 示范: nj#kzD[n>  
7g4IAsoD  
/&em%/  
from app import app U9XOs)^  
#iT3 aou  
6u,w  
# 导入 CherryPy ~3$:C#"Dl  
import cherrypy }-@h H(  
#.2} t0*]5  
L;U?s2&Y  
if __name__ == '__main__': 2E.D0E Cu  
+;a\ gF^  
#TIlM]5%  
    # 挂载应用 /BrbP7  
    cherrypy.tree.graft(app, "/") |H%,>r`9S  
CtHsi8m  
}0 Fu  
    # 从默认服务器上分离 X CHN'l'  
    cherrypy.server.unsubscribe() Np?/r}  
RWZjD#5%Z  
BAy)P1  
    # 实例化一个新的服务器对象 lGEfI&1%!  
    server = cherrypy._cpserver.Server() 8p]Krs:  
%.s"l6 W  
Sj;:*jk!h  
    # 配置该服务器对象 {qFAX<{D  
    server.socket_host = "0.0.0.0" gFxaUrZA  
    server.socket_port = 80 Zzv,p  
    server.thread_pool = 30 R}$A>)%dx  
30QQnMH3  
%`j2?rn  
    # SSL相关配置 dLw,dg  
    # server.ssl_module            = 'pyopenssl' Zv8G[(  
    # server.ssl_certificate       = 'ssl/certificate.crt' *KPNWY9!W  
    # server.ssl_private_key       = 'ssl/private.key' Ekz)Nh)vGR  
    # server.ssl_certificate_chain = 'ssl/bundle.crt' rlkg.e6  
&z"yls  
;CA7\&L>  
    # 订阅这个服务器对象 ^S^7 u  
    server.subscribe() Lu~M=Fh  
1y.!x~Pi,  
T]?QCf  
    # 启动服务器引擎 lLZ?&z$  
`BY&&Bv#?  
EYU3Pl%  
    cherrypy.engine.start() X-5&c$hv  
    cherrypy.engine.block() -;U3$[T,J7  
^/jALA9!  
U=ie| 3  
完成!现在我们就有了一个“Docker化”的Python Web应用,安全的跑在自己专属的沙箱里。只要输入下面的一行命令,它就可以给成千上万个客户端请求提供服务: R^GLATM  
u )KtvC!  
%I;iP|/  
python server.py 3EX41)u  
}'Yk#Q  
+FYhDB~m  
这是让服务器在前台运行的指令。按下 CTRL+C 终止运行。如果想在后台运行服务器,可输入下面的指令: z_en .  
{1]Of'x'  
/yL:_6c-  
python server.py & ' Y.s}Duj  
VTxLBFK;  
F anA~  
后台运行的应用需要用进程管理器(比如htop)来终止运行(kill或stop)。 ahm@ +/2  
m_r_4BP  
j?P8&Fm<  
注:有关CherryPy上跑Python应用的配置,可参阅这篇教程:How to deploy Python WSGI apps Using CherryPy Web Server。 &B>YiA  
"K-2y ^Dl  
R(F+Xg je  
简单的测试一下应用的运行状态(以及端口的分配状态):在浏览器中访问 http://[容器所在的VPS的IP地址] ,应该能够看到“Hello World!”。 #[ hJm'G  
U)gr C8 C  
i:,37INMt  
创建Dockerfile以实现镜像创建的自动化 *27*&&=)H  
上面简单的说过,手动创建容器的这个方法并不适合用于生产环境的部署。生产环境里应该用Dockerfile进行构建流程自动化。 `Hq)g1a7q  
gDjs:]/YR  
oyY0!w,Y  
我们已经知道了如何在容器内部进行外部资源的下载和安装,那么Dockerfile其实也是一样的原理。一个Dockerfile定义了Docker要如何生成一个镜像,这个镜像可以直接用来跑我们的Python应用。 $@:z4S(  
Ga} &%  
c`h/x>fa  
先了解一下Dockerfile的基本功能。 N5:muh \  
@}@J$ g  
f")*I  
Dockerfile概述 &GH ,is  
Dockerfile是一种脚本文件,其中包含了一系列顺序执行的命令,Docker通过执行这些命令就可以创建一个新的Docker镜像。这极大的方便了部署。 ['rqz1DL5  
=e$6o2!'}  
naoH685R4  
Dockerfile一般会先用 FROM 命令定义一个打底的镜像,然后执行一系列的动作,动作全部执行完毕之后就形成了最终的镜像,并将完成的镜像提交给宿主机。 = A;B-_c  
pn6!QpV5  
yp:_W@  
使用: _P*<T6\J>  
K@z zseQ}=  
7J@D})si  
# 在当前位置用Dockerfile创建一个镜像 xl~%hwBd  
# 将生成的镜像标记为 [name] (比如nginx) gr")Jw7  
# 示范:sudo docker build -t [name] . r&t)%R@q  
sudo docker build -t nginx_img . *n=NBkq%/!  
Ll !J!{  
2So7fZa^wg  
注:我们还有一篇专门介绍dockerfile的文章可供查阅:Docker Explained: Using Dockerfiles to Automate Building of Images Qpc+1{BQ  
N{<=s]I%x  
Xbb('MoI63  
Dockerfile命令一览 1&@s2ee4   
### Add -  zQ  
从宿主机复制文件到容器 "38ya2*  
@]H:=Q'gj  
:+SpZ>  
t$z FsFTQ  
;O2r+n  
### CMD 5Q.bwl:  
设置要执行或者要发给ENTRYPOINT的默认命令 / ` 7p'i  
pA*cF!tq 7  
: qKxm(  
>~5>)yN_a1  
$#dPM*E  
### ENTRYPOINT /?jAG3"  
设置容器内默认要启动的应用 Gv!* Qk4  
XTHy CK  
0.+"K}  
Cr,UP8MO  
|-hzvuSX  
### ENV F(8>"(C  
设置环境变量(key = value) 3+;}2x0-F  
Y) >GwFK$  
{iqH 27\E  
### EXPOSE $e;_N4d^  
暴露一个端口 ;K:)R_H  
@' DfNka  
i51~/ R  
### FROM Z4Nl{  6  
设置打底镜像(base) Ch`XwLY9  
+'H_sMmi{  
h$p]#]uMb  
### MAINTAINER 1.0S>+^JE  
设置Dockerfile的作者/所有者信息 l K%pxqx  
j5ZeYcQ-  
Da!A1|"  
### RUN bR@ e6.<i  
执行一条命令并提交执行后的(容器)镜像 g]R }w@nJ  
uh3%}2'P  
+qe!KPk2  
### USER w: ~66 TCI  
设置从镜像运行容器的用户名 * c] :,5  
t5#IiPp  
Ns2M8  
### VOLUME <Brq7:n|  
从宿主机加载一个目录给容器 5Ya TE<G  
JS r& S[  
A^2VH$j]+  
### WORKDIR L,| 60*  
设置CMD运行时所在的目录 0b9K/a%sQv  
jEsP: H(0^  
zR(}X8fP  
创建Dockerfile d6-a\]gF  
在当前路径下用nano编辑器创建Dockerfile: y]aV7 `]  
|B njT*_9  
ps"DL4*  
sudo nano Dockerfile v!T%xUb0  
1 8[U1{s:J  
注:下面的内容需要按顺序添加到Dockerfile中。 3'6%P_S  
{,tEe'H7  
~U#afGH$  
定义基本项 Iodk1Y;  
Dockerfile的基本项包括 FROM 原始镜像(比如Ubuntu)以及维护者姓名 MAINTAINER: "qUUH4mR`  
`uy)][j-  
<Yu}7klJE  
############################################################ .{x-A{l  
# 创建Python WSGI应用容器的Dockerfile 7udMF3;>  
# 基于Ubuntu WY#A9i5Ge  
############################################################ @dQIl#  
Ro$'|}(+A  
C1^=se  
# 设置Ubuntu为打底镜像 Mib(J+Il  
FROM ubuntu [ps5;  
LO<R<zz  
| ?3\xw  
# 文件作者/维护者 J`a$"G B.  
MAINTAINER Maintaner Name `q7O\  
MW8GM}Ho[  
w~hO)1c],:  
更新默认的应用仓库 FjqoO.  
# 添加软件资源库的URL 6/Y3#d  
RUN echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list ra=U,  
St9W{  
fqA\Rp6Z  
# 更新资源列表 oBiJiPE=`  
RUN apt-get update Nw[TP G5  
E}Q'Wz|k  
XQ]noaU  
安装基础工具 ?U.+SQ  
RUN apt-get install -y tar git curl nano wget dialog net-tools build-essential @ofivCc<%  
0>Iy`>]  
L,c@Z@  
注:上述的有些工具可能你用不到,不过为了以防万一还是都装进来先。 fVx<f.xuW  
42E]&=Cet  
L#mf[a@pCn  
Python基础套装安装指南 $(B|$e^:(  
一些Python需要的工具(pip)最好还是都先装起来。你的框架(WAF)和Web服务器(WAS)都需要有它们才能安装。 ZN#mu]jC?  
Wsya:9|  
N|-M|1w96  
RUN apt-get install -y python python-dev python-distribute python-pip <5(P4cm9  
!qk+>6~A,  
VWf&F`^B(  
部署应用 vFm8T58 7  
部署应用可以使用Docker的 ADD 命令直接复制源代码,也可以用 REQUIREMENTS 文件来一步到位。 5e=9~].7  
? cU9~=  
/W\@/b,  
注:如果你打算用一个文件描述所有的代码位置,可以参考下面的文件结构。 lWr=79  
y(/"DUx  
EYWRTh  
    文件结构示范 KSkT6_<  
6BK-(>c(6  
j<|I@0  
    /my_application =y+gS%o$  
    | "IQ' (^-P  
    |- requirements.txt  # 描述依赖项的文件 f_v@.vnn.  
    |- /app              # 应用模块(你的应用应该在这个目录下) }2c)UQD8  
    |- app.py            # WSGI文件,里面应该包含“app”的实例名称(callable) ramYSX@  
    |- server.py         # 可选,用于运行应用服务器(CherryPy) 5hN)y-4@  
7L3:d7=MIW  
K|[p4*6  
这个文件结构的创建过程在前面的章节中已经介绍过,这里不再赘述。总之,以上述文件结构为例,则再给Dockerfile末尾添加如下内容,将源代码复制到容器内: &h^E_]P  
,F}\njL  
iQs^2z#Bd  
ADD /my_application /my_application e=uElp'%  
V$wW?+V  
t<=Ru*p  
如果源代码是公网的git仓库,则可以使用如下内容: ]mIcK  
_mSDz=!Z3  
WEy$SN+P  
RUN git clone [你的源码仓库URL] I_h u s  
ZAATV+Z  
8(d Hn  
引导 3XykIj1  
接下来,再从 requirements.txt 导入所有的依赖项: Vx'82CIC  
1M@OBfB8  
 vVvx g0  
# 用pip来下载安装 requirements.txt 里面的东西 &.W,Hh  
RUN pip install -r /my_application/requirements.txt Qc4r?7S<  
>- S?rXO  
HrOq>CSR  
# 暴露端口 4)Jtc2z7Z\  
EXPOSE 80 aMv?D(Meb  
}+mIP:T  
AS1#_f C  
# 设置CMD运行的默认路径 (U_`Q1Jo  
WORKDIR /my_application ht>C6y  
JRgrg &#  
h D5NX  
# 要运行的默认命令 Fw{:fFZC[  
# 该命令在新容器创建时开始执行 5:R$xgc  
# 比如启动CherryPy来运行服务 rgo#mTQ_  
CMD python server.py qb$&BZj]|  
z6'Cz}%EP'  
6DkFIkS  
最终的Dockerfile D;1?IeS  
现在,整个Dockerfile看起来应该是这样的: =Ff _)k  
r!+..c  
^uiQZ%;  
############################################################ gDN7ly]6M  
# Dockerfile to build Python WSGI Application Containers F o k%  
# Based on Ubuntu 8(3n v[  
############################################################ ^5'pJ/BV  
-s3q(SH  
ZA1:Y{ V  
# Set the base image to Ubuntu Ei HQ&u*  
FROM ubuntu AONEUSxJ  
~:krJ[=  
M&[bb $00j  
# File Author / Maintainer WWEZTFL:j  
MAINTAINER Maintaner Name vZiuElxKi  
!jQj1QZR`  
W(jOD,QMB  
# Add the application resources URL WEaG/)y  
RUN echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list FG:t2ea  
?W 6 :$  
oBS m>V  
# Update the sources list )FdS;]  
RUN apt-get update $xU)t&Df  
tE8aL{<R  
O7"16~ a  
# Install basic applications @=ro/.  
RUN apt-get install -y tar git curl nano wget dialog net-tools build-essential d=nv61]  
5i@WBa  
%y{'p:  
# Install Python and Basic Python Tools <*Gd0 v%  
RUN apt-get install -y python python-dev python-distribute python-pip *t{^P*pc  
Lcz`  
29HyeLB@  
# Copy the application folder inside the container G"F)t(iX  
ADD /my_application /my_application gy`WBg(7x  
gF>t+"+ x  
2C Fgit  
# Get pip to download and install requirements: it$w.v+W7V  
RUN pip install -r /my_application/requirements.txt zCdcwTe  
I=pFGU  
Xqy9D ZIn  
# Expose ports gX|We}H  
EXPOSE 80 :V0sKg|sS  
ffQm"s:P  
L.s$|%  
# Set the default directory where CMD will execute +-!2nk`"a  
WORKDIR /my_application {%oxzdPc  
onU\[VvM  
- i#Kpf  
# Set the default command to execute     'Rb tcFb   
# when creating a new container ?J@P0(M#  
# i.e. using CherryPy to serve the application OWc~=Cr  
CMD python server.py CjGQ  
(DkfLadB  
c2u*<x  
按 CTRL+X 再按 Y 键,保存退出。 n%6ba77  
[]$L"?]0uk  
OH13@k  
使用Dockerfile进行自动化的容器创建 v~A*?WU;n  
在之前的基础教程部分我们提到过,Dockerfile的工作方式利用到了 docker build 命令。 |s,y/svp  
|=:<[FU  
{TZV^gT4  
我们通过Dockerfile指示docker从包含源代码的路径复制内容到容器内部,因此在构建之前务必要确认Dockerfile与代码路径的相对位置。 q?qH7={,eu  
L6"V=^Bq  
je`Inn<  
这样一个Docker镜像可以快速创建起来一个可以运行我们的Python应用的容器,我们需要做的只是输入这样一行指令: [:zP]l.|  
?=im  ~  
p^1~o/  
sudo docker build -t my_application_img . _C)\X(;  
H*P[tyz$  
4t-l@zFWb  
我们把这个镜像命名为 my_application_img 。为要从这个镜像启动一个新的容器,只需要输入下面的命令: `pjB^--w  
_\gCdNrD  
F5y&"Y_  
sudo docker run -name my_application_instance -p 80:80 -i -t my_application_img Q ZC\%X8j  
CQPq5/@Y4  
y'!"GrbZ  
然后就可以在浏览器里输入你VPS的IP地址,访问应用了。 p=m:^9/  
e$Mvl=NYp\  
lL&U ioo}D  
有关Docker安装的更多教程(包括在其他发行版上安装Docker),可以查阅我们在docker.io上的文档docker installation documentation。 V%B~ q`4  
I_ AFHrj  
[ 此帖被寒喵在2018-12-29 19:19重新编辑 ]
本人不是云栖社区工作人员。
无论您在使用中遇到什么问题,不要出言不逊!谢谢合作!
发表主题 回复主题
« 返回列表上一主题下一主题

限100 字节
如果您在写长篇帖子又不马上发表,建议存为草稿
 
验证问题: 65 + 29 = ?
上一个 下一个