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

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

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

前言 2s 6Vy  
Web应用随时可能被攻击者利用来夺取整个主机的权限,这是很常见也是很恐怖的一件事。为了更高的安全性,就需要将不同应用之间进行隔离(尤其是在这些应用属于不同的用户的情况下),然而这种隔离的实现一直是个挑战。到目前为止,隔离性的实现方法已经有了很多,然而它们要么太过昂贵(时间的层面以及资源的层面),要么太过复杂(无论对开发者还是对管理员)。 `+zr PpX  
Vs07d,@w>  
>Q+EqT  
本文将讨论如何让“容器化”的Python Web应用跑在安全的沙箱里,严格的坚守在其各的环境中(当然,除非你指定它们与其他应用进行“连接”)。我将一步一步的介绍如何创建一个Docker容器,如何用这个容器来跑我们的Python Web应用,以及如何用一个Dockerfile来描述整个构建过程以实现完整的自动化。 a~XNRAh  
SxH}/I|W  
bJBx~  
目录 }qlz^s  
1. Docker概述 <:&w/NjbI  
2. 在Ubuntu上安装Docker zcZr )Oh  
3. 基本的Docker命令 ]e"NJkcm  
Docker的守护进程与命令行 k8*=1kl"  
Docker命令 w[|!$J?  
4. 创建Docker容器作为Python WSGI应用的沙箱 }y[o[>  
在Ubuntu里创建打底Docker容器 HQUL?URt  
安装前的准备工作 5Cz:$-+  
安装Python工具 ;\&7smE[  
安装我们的Web应用以及其依赖项 )?TJ{'m  
配置我们的Python WSGI应用 ]\3dJ^q|%  
5. 创建Dockerfile以实现镜像创建的自动化 zzW^ AvR  
Dockerfile概述 @wa/p`gj5w  
Dockerfile命令一览 hQet?*diU  
创建Dockerfile { _ 1q`5o  
定义基本项 oNEU?+  
更新默认的应用仓库 _*`AGda  
安装基础工具 OVivJx  
Python基础套装安装指南  XG^  
部署应用 S%T1na^x  
引导 (h%wO  
最终的Dockerfile j5HOdy2  
使用Dockerfile进行自动化的容器创建 nC*/?y*9  
Docker概述 {Rz`)qqE  
Docker项目提供了一些可以搭配使用的上层工具,这些工具基于Linux内核的一些功能创建。整个项目的目标是帮助开发者和系统管理员门无痛的迁移应用(以及它们所涉及的所有依赖项),让应用在各种系统和机器上都能欢快的跑起来。 %%3ugD5i!  
(>Yii_Cd  
+_ G'FD  
实现这个目标的关键在于一个叫做docker容器的运行环境,这个环境实际上是一个具备安全属性的LXC(Linux Containers)。容器的创建使用了Docker镜像,Docker镜像可以手动敲命令创建,也可以通过Dockerfiles实现自动化创建。 8t7hN?,t  
WW_X:N~~e\  
x*)Wl!  
注:关于Docker的基础知识(守护进程、CLI、镜像等等),可参阅本系列的第一篇文章Docker Explained: Getting Started。 4t+88e  
Df4n9m}E  
K:{Q~+   
在Ubuntu上安装Docker &\(YmY  
最新版本的Docker(译注:本文撰写时间为2013年12月17日,当时的Docker最新版本为0.7.1)可以在Ubuntu/Debian和CentOS/RHEL等多个Linux发行版上部署(你也可以使用DigitalOcean上现成的Docker镜像,该镜像基于Ubuntu 13.04创建)。 r94BEC 2  
~KNxAxyVi  
8q0 .yhb  
下面快速介绍一下Ubuntu上的安装流程。 nDo|^{!L`  
QJTC@o  
j IW:O  
在Ubuntu上安装Docker C8jZcs#4  
更新系统: V]8fn MH  
ruW6cvsvet  
YA|*$$  
sudo aptitude    update p 2i5/Ly  
sudo aptitude -y upgrade ox*Ka]  
urN&."c  
.xD-eWw3R  
检查系统是否支持aufs: y^XwJX-f  
r({(;  
Du{]r[[C  
sudo aptitude install linux-image-extra-`uname -r` Gmwn:  
r9%W?fEBp  
);6zV_^!  
往apt-key添加Docker仓库的密钥(用于软件包的验证): `?$R_uFh:  
x O)nS _I  
dYsqF 3f  
sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -" EbW7Av  
wVPq1? 9  
7OZ s~6(  
往aptitude软件源添加Docker仓库: *= D$  
_S[H:b$?  
AiyjrEa%  
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main\ kSJWQ  
> /etc/apt/sources.list.d/docker.list" +]__zm/^  
vS X 6~m  
Sb`>IlT\#  
添加之后再更新一次系统: 0>'1|8+`(z  
tQ)8HVKF  
+-oXW>`&  
sudo aptitude update -r,J>2`l  
|%tR#!&[:g  
Ri,UHI4 W  
最后,下载并安装Docker: mr/^lnO  
T.{I~_  
Zj}, VB*T  
sudo aptitude install lxc-docker E:i3 /Ep?  
sFGXW  
bc&:v$EGy  
Ubuntu默认的防火墙(UFW)的默认设置是拒绝一切转发(forwarding),但是Docker需要转发,所以也需要设置一下UFW。 ;hg]5r_  
l"MEX/   
~U^0z|.  
用nano编辑器打开UFW配置文件: |mK d5[$  
IUZsLNW  
+J^}"dG  
sudo nano /etc/default/ufw vI+PL(T@  
O@ "6)/  
")LF;e  
找到DEFAULT_FORWARD_POLICY这一行,将 xF,J[Aj  
~gV|_G  
;[6u79;I  
DEFAULT_FORWARD_POLICY="DROP" z cA"\  
]];7ozS)X  
N),Zb^~nw  
替换为: <H 3}N!  
)ei+ewVZ  
>#V8l@IH  
DEFAULT_FORWARD_POLICY="ACCEPT" lh5k@\X  
Dm5UQe  
pZWp2hj{X  
按 CTRL+X 再按 Y 键,保存退出。 ."H5.'  
=XYfzR  
|D^[]*cEH  
最后,把UFW重启一下: *M8 4Dry`y  
;id  
>`lf1x  
sudo ufw reload M r@M~ -  
Y@pa+~[{h3  
htkyywv  
基本的Docker命令 l\(t~Q  
在正式开始之前,我们还是先复习一下上次在基础篇中介绍过的一些基本命令。 tBf u{oC  
W`;E-28Dg  
5:AAqMa  
Docker的守护进程与命令行 d2 d^XMe!  
一般来说,Docker守护进程在你安装完成了之后就已经在后台运行,等待接收来自Docker命令行的指令。不过有的时候我们也需要手动启动Docker守护进程: @5kN L~2  
TX 12$p\  
O[8Lp?  
sudo docker -d & Pl 5+Oo  
@@! R Iq!  
Q}1PPi,  
Docker命令行的基本语法如下: |"ck;.)  
PAqziq.  
8T1`TGSFC  
sudo docker [option] [command] [arguments] / P{f#rV5  
; xs?^N|  
#%x4^A9 q  
注:Docker的运行需要sudo权限。 [y'jz~9c  
H,?AaM[V  
IoA"e@~t  
Docker命令 ?SS?I  
下面列出了目前可用的Docker命令(译注:可以参考InfoQ中文站文章深入浅出Docker(二):Docker命令行探秘): 9WHkw@<R+  
ogPxj KSI  
in%+)`'nH7  
attach    附着到一个运行的容器上 lMlXK4-  
build     从一个Dockerfile建立镜像 BPC$ v\a  
commit    将一个变更后的容器创建为一个新镜像 & 8e~<  
cp        在容器和本地文件系统之间复制文件/目录 Kw'A%7^e  
create    创建一个新的容器 \ar.(J  
diff      检测容器文件系统的变更 -B@jQg@ >  
events    从服务获取实时事件 @aBZ|8  
exec      在一个运行中的容器内执行命令 ,A_itRHH  
export    将一个容器的文件系统输出为tar压缩包 PN<Y&/fB  
history   显示一个镜像的历史 o.sa ?*  
images    列出镜像列表 \z<'6,b  
import    从tarball压缩包导入内容以创建一个文件系统镜像 jz/@Zg",  
info      显示系统信息 RN!oflb  
inspect   返回容器或镜像的底层信息 $yOfqr  
kill      杀死一个运行中的容器 AEEy49e  
load      从一个tar压缩包或STDIN加载一个镜像 2W|j K  
login     登入Docker注册表(Docker registry) #{<Jm?sU  
logout    从Docker注册表登出 E7y<iaA{~  
logs      抓取一个容器的日志 u\>Ed9^  
network   管理Docker网络  c~dX8+  
pause     暂停一个容器内的所有进程 .lRO; D  
port      列出该容器的所有端口映射或指定端口映射 e8P |eK  
ps        列出容器列表 {Uu7@1@n  
pull      从注册表拉取一个镜像或仓库 wgI$'tI  
push      往注册表推送一个镜像或仓库 %!x\|@C  
rename    重命名容器 p`XI(NI  
restart   重启容器 ]xV7)/b5G  
rm        删除一个或多个容器 6`F_js.a  
rmi       删除一个或多个镜像 S1zV.]  
run       在一个新的容器中运行一条命令 t3G%}d?  
save      将镜像保存至tar压缩包 \'j%q\Bl;  
search    在Docker Hub搜索镜像 sL[,J[AN;  
start     启动一个或多个容器 5jkW@  
stats     显示容器资源使用情况的实时信息流 dH?;!sJ  
stop      停止一个运行中的容器 L +-B,466  
tag       向注册表标记一个镜像 c5^i5de  
top       显示一个容器下运行的进程 /q(+r5k \  
unpause   恢复运行一个容器里所有被暂停的进程 %vn rLt$  
update    更新容器的资源 oZP:}= F  
version   显示Docker版本信息 4z?6[Cg<  
volume    管理Docker卷 5U%u S^%DP  
wait      阻塞对指定容器的其他调用方法,直到容器停止后退出阻塞。 yn4Xi@9Pri  
S yX>zN!  
d\xh>o  
创建Docker容器作为Python WSGI应用的沙箱 =<R77rnY&  
我们已经完成了Docker的安装,也熟悉了基本的命令,现在可以为我们的Python WSGI应用创建Docker容器了。 rzY7f: '  
L 'H1\' o  
,8EeSnI  
注:本章介绍的方法主要是练习用,并不适合于生产环境。生产环境下适用的自动化流程将在后续章节中介绍。 /?HRq ?n  
v"=^?5B  
&c?-z}=G  
在Ubuntu里创建打底Docker容器 A]ciox$AjW  
Docker的run指令会基于Ubunt镜像创建一个新的容器。接下来,我们要用 -t 标识给这个容器附着(attach)一个终端,并运行一个 bash 进程。 pO GVD  
{.;MsE  
&2#<6=}  
我们将暴露这个容器的80端口用于从外部访问。以后在更加复杂的环境中,你可能需要给多个实例做负载均衡,把不同的容器“连接”起来,再用一个反向代理容器去访问它们。 S\s1}`pNm  
6^}GXfJAc  
Nl PP|=o  
sudo docker run -i -t -p 80:80 ubuntu /bin/bash BX2&tQSp  
x-(?^g  
qEX59v  
注:运行这个命令时,Docker可能需要先下载一个Ubuntu镜像,下载完毕后才创建新容器。 lg;`ItX]  
Fl^.J<Dz  
9akCvY#Q  
注意:你的终端会“附着”(attach)在新创建的容器上。要与容器分离并回到之前的终端访问点,可以按 CTRL+P 接着 CTRL+Q 执行脱离操作。“附着”在一个Docker容器上,基本上相当于从一个VPS内部访问另一个VPS。 .lTU[(qwu  
l*xA5ObV  
rh/3N8[6  
从脱离的状态想要回到附着的状态,需要执行如下步骤: ZXe[>H  
Ui'~d(F  
dV.)+X7<  
用 sudo docker ps 列出所有运行中的容器 p"JITH :G  
找到之前创建的那个容器的ID y @h^  
执行 sudo docker attach [id] 完成当前终端到该容器的附着 \d]&}`'4{f  
注意:我们在容器内部做的一切操作都将仅限于在容器内部执行,对宿主机是完全没有影响的。 ;m@>v?zE  
Cf2rRH  
kVe}_[{m  
安装前的准备工作 R qOEQ*k  
要在容器内部署Python WSGI应用(以及我们所需要的工具),首先我们需要对应的软件仓库。然而在Docker默认的Ubuntu镜像里并没有提供仓库(Docker的设计者认为这样有利于保持事物的简化),因此我们需要给我们这个打底镜像添加Ubuntu的universe软件仓库: M\>y&'J-  
, N5Rdgzk  
W^P%k:anK  
echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list 3eFD[c%mN  
/QD}_lh;,  
&=K-~!?  
更新一下软件列表: K;gm^  
HC+(FymV  
%pe7[/  
apt-get update daY^{u3  
]'DtuT?Z  
Eki7bT@/  
再给我们的容器安装一些必要的工具: <),FI <~  
]e7D""  
([`-*Hy  
apt-get install -y tar \ 'R,1Jmx  
                   git \ 8!S="_  
                   curl \ (E\7Ui0 Q  
                   nano \ r]kLe2r:B  
                   wget \ a:H}c9 $%  
                   dialog \ T[~ak"M  
                   net-tools )TVyRYZ1  
                   build-essential x]Nq|XK  
hdfNXZ{A"  
vEW;~FLd  
安装Python工具 y85GKysT  
本文将用一个简单的Flask应用作为示范。如果你用的是其他框架也没关系,安装部署的方法都是一样的。 ){L`hQ*=w  
Q0Dw2>~_K  
^A;v|U  
再提醒一次:以下所有的命令都是在容器内部执行的,不会影响到宿主机。你可以想象成自己在一个全新的VPS上进行操作。 3:dQN;=  
|JnJ=@-y  
"<txg%j\J  
安装Python和pip: oT_k"]~Q~2  
Y]^[|e8  
r }pYm'e  
# 安装pip依赖:setuptools Nr uXXd  
apt-get install -y python python-dev python-distribute python-pip CdC&y}u  
lH T?  
&NB[:S =  
安装Web应用以及其依赖项 A ElNf:  
安装我们的应用之前,还是让我们再确认一下所有的依赖都已经就绪。首先是我们的框架——Flask。 f.,S-1D]h  
!xA;(<K[^  
"qMd%RP  
因为我们已经装好了pip,所以就直接用pip来安装Flask: f*p=]]y  
AL3zE=BL  
X3<<f`X  
pip install flask $:{uF#  
gdNEMT  
LmseY(i N  
装好了Flask,创建一个“my_application”文件夹: M,3sK!`>  
'HH[[9Q  
9p9:nx\  
mkdir my_application NcwZ_*sqj  
j^Bo0{{  
o~*% g.  
cd my_application @'7'3+ c  
P!0uAkt9C  
<;=?~QK%-  
注:如果你想直接部署自己的应用(而不是这里的示范应用),可以参看下面的“小贴士”部分。 Jx.Jx~  
TMT65X!  
?2E@)7  
我们的示范应用是一个单页面的“Hello World” Flask应用。下面用nano来创建app.py: gcQ>:m i  
)xoIH{  
q~ T*R<S  
nano app.py MOJKz!%  
oDrfzm|[Y  
zw_Xh~4"b  
把下面这些内容复制到新创建的文件里:  &)T5V  
T9}G:6  
f)Z$ ,&  
from flask import Flask -2{NI.-Xd  
app = Flask(__name__) bLhTgss](  
7b_t%G"  
RplLU7  
@app.route("/") 5N@k9x  
def hello(): =e$<[ "  
    return "Hello World!" *GH` u*C_  
iV58 m  
V|13%aE_v  
if __name__ == "__main__": G3 rTzMO  
    app.run() Nj rF":'Y  
&)zNu  
gFizw:l  
按 CTRL+X 再按 Y 键,保存退出。 >E;kM B  
7jL+c~  
X ^8@T  
或者,你也可以使用“requirements.txt”来定义应用的依赖项(比如Flask)。我们还是用nano来创建文件: _~/F-  
't.I YBHx  
/99S<U2ej  
nano requirements.txt `<2k.aW4e8  
#.L9/b(  
VHyH't_&s  
在文件输入你所有的依赖项(下面只列出两个,如果你需要别的请自行添加): ,h,OUo]LIY  
l25_J.e  
<:/Lap#D^  
flask ^RE[5h6^q  
cherrypy }vU^g PH  
f 8\DAN  
~z^49Ys:  
按 CTRL+X 再按 Y 键,保存退出。 #)#J`s1R  
Q;ZV`D/FA  
B8unF=u  
注:你可以用pip来生成自定义的依赖项列表。具体的操作方法可以参考这篇Common Python Tools: Using virtualenv, Installing with Pip, and Managing Packages。 Y[|9 +T  
ly69:TR7I  
B}P!WRNmln  
最后,我们这个应用的文件组织结构是这样的: <`WDNi$Y  
D^xg2D  
] *U+nG  
/my_application &1Y7Ne  
    | JC`;hY  
    |- requirements.txt  # 描述依赖项的文件 /eT9W[a  
    |- /app              # 应用模块(你的应用应该在这个目录下) ecx_&J@D  
    |- app.py            # WSGI文件,里面应该包含“app”的实例名称(callable) @#*{* S8  
    |- server.py         # 可选,用于运行应用服务器(CherryPy) |'lNR)5  
M;W&#Fz%  
v-8{mK`9\  
注:关于“server.py”,请参阅下面的章节“配置我们的Python WSGI应用”。 mq}UUk@  
MskO Pg  
[?=DPE%  
注意:上面这些应用的文件、目录都是在容器内部创建的。如果你要在宿主机上自动化构建镜像(这个过程将在下面有关Dockerfile的章节中介绍),则你的宿主机上放置Dockerfile的目录下也需要同样的文件结构。 mhM;`dl  
Bp5 %&T k  
QkWEVL@uM  
小贴士:部署自己的应用 |z8_]o+|r1  
在容器内部搞定应用所需的软件仓库和依赖项 :#\jx  
上述步骤描述了在容器内创建应用目录的过程。然而在真实场景下,我们往往需要从软件仓库拉取源代码。 c}!`tBTm  
Q-A_8  
eoFG$X/PO  
要把你的软件仓库复制到容器内部,有几个方法可以实现。下面介绍其中的两个: V6+:g=@U-l  
_j4 K  
?%%vQ ?  
# 方法1 Sj:c {jyJd  
# 用git下载源代码 A/&u /?*C  
# 用法:git clone [源代码所在的URL] I*f@M}  
# 示范: ,Y#f0  
git clone https://github.com/mitsuhiko/flask/tree/master/examples/flaskr  $C,` ^n'  
!]9qQ7+R%  
gv&Hu$ ca  
# 方法2 |MN2v[y  
# 下载源代码压缩文件 &4%78K\  
# 用法:wget [源代码压缩文件所在的URL] \ [M4[Qlq  
# 示范:(用真实的URL替换掉下面这个假的) WRRR"Q$  
wget http://www.github.com/example_usr/application/tarball/v.v.x |Om9(xT  
bSQj=|h1  
tkff\W[JU  
# 解压缩文件 oA:`=f%\  
# 用法:tar vxzf [文件名 .tar (.gz)] U ]B-B+-  
# 示范:(用真实的文件名替换掉下面这个假的) I.>8p]X  
tar vxzf application.tar.gz #s#BYbF  
{$ pi};  
Q'hs,t1<  
# 用pip下载安装应用依赖 '*Tt$0#o  
# 下载 requirements.txt (可以用 pip freeze output 生成),再用pip全部安装: [jxh$}?P  
# 用法:curl [requirements.txt 文件的URL] | pip install -r - 0bD\`Jiv,  
# 示范:(用真实的URL替换掉下面这个假的) F7/%,vf  
curl http://www.github.com/example_usr/application/requirements.txt | pip install -r - qP zxP @4  
C[l5[DpH  
sPl3JP&s  
配置我们的Python WSGI应用 '#oH1$W]  
要运行这个应用,我们需要一个Web服务器。运行这个WSGI应用的Web服务器需要安装在代码所在的同一台容器中,作为该Docker容器运行的进程。 Okd.  ~  
] r%fAm j  
b/\l\\$-  
注:我们在示范中将使用CherryPy自带的HTTP Web服务器,这是一个比较简单而且可以用在生产环境的选择。你也可以用Gunicorn甚至uSWGI(可以让它们跑在Nginx的后面),我们其他的教程中介绍过这种用法。 rJB/)4 mE  
ka{!' ^  
0zsmZ]b5E  
用pip下载安装CherryPy: ytb1hFs  
RSw; b.t7  
NO/5pz}1  
pip install cherrypy p;D {?H/  
CL?=j| Ea  
bweAmSs  
创建“server.py”,用于服务“app.py”里面的Web应用: Z Y5Pf 1  
Y:Jgr&*,z  
YUyYVi7clq  
nano server.py W@%g_V}C*  
o{l]n*  
I*g[Y=  
把下面的内容复制粘贴到server.py里: 0,8RA_Ca}  
9%0^fhrJ  
hM=X# ;  
# 导入应用的语法: }^b  
# from app import application sheCwhV  
# 示范: 6TXTJ]er  
)wdd"*hv  
:2XX~|  
from app import app "5EL+z3v  
PeLzZ'$D  
-3m!970  
# 导入 CherryPy ^V]IPGV  
import cherrypy ~0}d=d5g  
6['o^>\}f  
D^U?!S&4~  
if __name__ == '__main__': <7gv<N6BQf  
hDBo XIK  
|8)\8b|VuC  
    # 挂载应用 <,U$Y>  
    cherrypy.tree.graft(app, "/") Fr(;C>  
1xO-tIp/  
wLvM<p7OX  
    # 从默认服务器上分离 1S yG  
    cherrypy.server.unsubscribe() CW.T`F  
,"YTG*ky  
;Sp/N4+  
    # 实例化一个新的服务器对象 %c8@  
    server = cherrypy._cpserver.Server() ),^pi?  
0\!v{A> I'  
k-)Ls~#+  
    # 配置该服务器对象 +wI<w|!  
    server.socket_host = "0.0.0.0" yW"[}L h4  
    server.socket_port = 80 0F 2p4!@W  
    server.thread_pool = 30 /a6i`  
~mv5{C  
*9EW &Ek  
    # SSL相关配置 .nEiYS|T  
    # server.ssl_module            = 'pyopenssl' OGG9f??  
    # server.ssl_certificate       = 'ssl/certificate.crt' 0]^gT'  
    # server.ssl_private_key       = 'ssl/private.key' Wr'1Y7z  
    # server.ssl_certificate_chain = 'ssl/bundle.crt' aP"!}*  
agQD d8oX  
Qd>\{$N  
    # 订阅这个服务器对象 O%px>rdkY  
    server.subscribe() )CgH|z:=b  
io@f5E+?  
o^r\7g6\  
    # 启动服务器引擎 a>Zp?*9  
\0&F'V  
t6lwKK  
    cherrypy.engine.start() 3e1P!^'\  
    cherrypy.engine.block() l kyK  
Eh$1p iJG  
|IS$Om  
完成!现在我们就有了一个“Docker化”的Python Web应用,安全的跑在自己专属的沙箱里。只要输入下面的一行命令,它就可以给成千上万个客户端请求提供服务: {faIyKtW  
;WgUhA ;q  
7:<A_OLi  
python server.py .N`*jT  
yT~x7,  
c]/S<w<  
这是让服务器在前台运行的指令。按下 CTRL+C 终止运行。如果想在后台运行服务器,可输入下面的指令: R'" c  
2<n@%'OQp  
mkl^2V13~  
python server.py & [1O{yPV3s  
gYe6(l7m  
5G$5d:[(  
后台运行的应用需要用进程管理器(比如htop)来终止运行(kill或stop)。 <XN=v!2;  
vo%"(!  
DJAKF  
注:有关CherryPy上跑Python应用的配置,可参阅这篇教程:How to deploy Python WSGI apps Using CherryPy Web Server。 ./L)BLC i  
\-f/\P/ w  
ww #kc!'  
简单的测试一下应用的运行状态(以及端口的分配状态):在浏览器中访问 http://[容器所在的VPS的IP地址] ,应该能够看到“Hello World!”。 1vtC4`  
5pK _-:?  
QHc([%oV  
创建Dockerfile以实现镜像创建的自动化 VqxK5  
上面简单的说过,手动创建容器的这个方法并不适合用于生产环境的部署。生产环境里应该用Dockerfile进行构建流程自动化。 q6<P\CSHy<  
Vjw u:M  
bdG@%K',  
我们已经知道了如何在容器内部进行外部资源的下载和安装,那么Dockerfile其实也是一样的原理。一个Dockerfile定义了Docker要如何生成一个镜像,这个镜像可以直接用来跑我们的Python应用。 "?<h,Hvi  
P{yb%@I~J  
_l"nwEs  
先了解一下Dockerfile的基本功能。 9y<h.T  
&;=/^~EG  
 K[LuvS  
Dockerfile概述 C,GZ  
Dockerfile是一种脚本文件,其中包含了一系列顺序执行的命令,Docker通过执行这些命令就可以创建一个新的Docker镜像。这极大的方便了部署。 ra>2<  
c&FOt  
Ak8Y?#"wz  
Dockerfile一般会先用 FROM 命令定义一个打底的镜像,然后执行一系列的动作,动作全部执行完毕之后就形成了最终的镜像,并将完成的镜像提交给宿主机。 Z# bO}!  
C/'w  
o]<9wc:FZ  
使用: %:zu68Q[  
 qLP/z  
.T3 m%n  
# 在当前位置用Dockerfile创建一个镜像 :O$bsw:3w<  
# 将生成的镜像标记为 [name] (比如nginx) ,&qC R sw  
# 示范:sudo docker build -t [name] . q=V'pML  
sudo docker build -t nginx_img . 7(N+'8  
B4wRwrVI>  
K,$rG%c zX  
注:我们还有一篇专门介绍dockerfile的文章可供查阅:Docker Explained: Using Dockerfiles to Automate Building of Images l{>j8Ln  
}v4dOGc?  
`fTM/"  
Dockerfile命令一览 nP]!{J]  
### Add 7t:tS7{}  
从宿主机复制文件到容器 lg~7[=%k#  
lM{ fld  
. R/y`:1:W  
y!.jpF'uI  
Jk6}hUH,  
### CMD s&(;  
设置要执行或者要发给ENTRYPOINT的默认命令 Vm>EF~r  
cgSN:$p(R  
E3]WRF;l  
NX.xE W@  
(r kg0  
### ENTRYPOINT p2{7+m  
设置容器内默认要启动的应用 eY5mwJ0K  
4]ni-u0*  
-6HwG fU  
O9(z"c  
EN2SI+  
### ENV ,_I rE  
设置环境变量(key = value) hEQyaDD;  
L2ydyXIsd  
!}#> ky!t  
### EXPOSE dD=$$( je  
暴露一个端口 7RL J  
E,}{iqAb  
At4\D+J{Vs  
### FROM KBmOi  
设置打底镜像(base) >8>!wi9U  
)Y7H@e\1  
7"!b5(4=  
### MAINTAINER % /VCjuV  
设置Dockerfile的作者/所有者信息 :*M?RL@j  
Yi*F;V   
fY[Fwjj3  
### RUN d +D~NA[M  
执行一条命令并提交执行后的(容器)镜像 5@w6pda  
si]VM_w6  
~oa}gJl:}-  
### USER wtY)(k a  
设置从镜像运行容器的用户名 )8@-  
pj$JA  
\yr9j$  
### VOLUME Jr2yn{s=S  
从宿主机加载一个目录给容器 K381B5_h  
&zdS9e-fF  
QnWE;zN[7A  
### WORKDIR $r/$aq=K  
设置CMD运行时所在的目录 "GO!^ZG]  
fp' '+R[   
SK}sf9gTv  
创建Dockerfile MA`nFkVK  
在当前路径下用nano编辑器创建Dockerfile: Z-PB CU  
`Nx@MPo  
xsZG(Tz  
sudo nano Dockerfile e*7O!Z=O  
1 An. A1y  
注:下面的内容需要按顺序添加到Dockerfile中。 D&%8JL  
NN*L3yx  
v-}f P  
定义基本项 L 4j#0I]lq  
Dockerfile的基本项包括 FROM 原始镜像(比如Ubuntu)以及维护者姓名 MAINTAINER: W{F)YyR{.  
$hhXsu=  
 XIInI  
############################################################ r mX*s} B  
# 创建Python WSGI应用容器的Dockerfile Q,KNZxT,q  
# 基于Ubuntu .-Lrrk)R+  
############################################################ d&+]@ Ii  
# e? B  
9\Jc7[b  
# 设置Ubuntu为打底镜像 1K Fd ~U  
FROM ubuntu @_ %RQO_X  
/wJ#-DZ  
gi!_Nz  
# 文件作者/维护者 YV.' L  
MAINTAINER Maintaner Name q} e#L6cM  
EF)BezG5y  
_E C7r>V&  
更新默认的应用仓库 t2d sYU/  
# 添加软件资源库的URL fd'kv  
RUN echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list [7I:Dm  
l U/Xi  
)\1>)BJq  
# 更新资源列表 XDPR$u8hM  
RUN apt-get update 5 A0]+)5E8  
syX?O'xJ  
AU9C#;JD  
安装基础工具 F$t]JM  
RUN apt-get install -y tar git curl nano wget dialog net-tools build-essential VIAq$iu7  
eK7A8\;e  
5M5Bm[X  
注:上述的有些工具可能你用不到,不过为了以防万一还是都装进来先。 4/(#masIL  
ZXnacc~s  
yj:@Fg-3g  
Python基础套装安装指南 $Tbsre\MJ  
一些Python需要的工具(pip)最好还是都先装起来。你的框架(WAF)和Web服务器(WAS)都需要有它们才能安装。 IW\^-LI.  
mx9vjW fy  
9lq5\ tL-  
RUN apt-get install -y python python-dev python-distribute python-pip {!2K-7;  
c+FTt(\8.  
!<];N0nt#  
部署应用 /9_%NR[  
部署应用可以使用Docker的 ADD 命令直接复制源代码,也可以用 REQUIREMENTS 文件来一步到位。 ~R|9|k  
2;Z 0pPR&  
=;Q/bD->  
注:如果你打算用一个文件描述所有的代码位置,可以参考下面的文件结构。 d|R-K7 ~~  
y(|#!m?@  
GN_L"|#)=  
    文件结构示范 z6`0Uv~  
7hk<{gnr  
fw&*;az  
    /my_application ()aCE^C  
    | 63E6nW M  
    |- requirements.txt  # 描述依赖项的文件 T<*)Cdid  
    |- /app              # 应用模块(你的应用应该在这个目录下) )WoH>D  
    |- app.py            # WSGI文件,里面应该包含“app”的实例名称(callable) c0o]O[  
    |- server.py         # 可选,用于运行应用服务器(CherryPy) {Z c8,jm  
/l<(i+0  
y,:WLk~  
这个文件结构的创建过程在前面的章节中已经介绍过,这里不再赘述。总之,以上述文件结构为例,则再给Dockerfile末尾添加如下内容,将源代码复制到容器内: |:C0_`M9  
,=+t2Bn  
6 /<Hx@r (  
ADD /my_application /my_application mh8fJ6j29N  
(xo`*Q,+  
LcGKYl(\K  
如果源代码是公网的git仓库,则可以使用如下内容: !; >s.]  
@XJ7ff&  
eKOEOm+  
RUN git clone [你的源码仓库URL] >N#Nz 0|(  
az ZtuDfv  
a{xJ#_/6  
引导 E3 % ~!ZC  
接下来,再从 requirements.txt 导入所有的依赖项: e%e.|+  
s~{rC{9X  
?3~t%Q`  
# 用pip来下载安装 requirements.txt 里面的东西 ymm]+v5S.]  
RUN pip install -r /my_application/requirements.txt \:+\H0Bz  
w1I07 (  
&pY '  
# 暴露端口 1 3 ]e< '  
EXPOSE 80 ;j9%D`u<  
[2,D]e  
RNc:qV<H  
# 设置CMD运行的默认路径 g)6>=Qo`8E  
WORKDIR /my_application I3 "6"  
<%YW/k"o  
sgO au\E  
# 要运行的默认命令 rQl9SUs  
# 该命令在新容器创建时开始执行 4^r6RS@z  
# 比如启动CherryPy来运行服务 x_~_/&X5  
CMD python server.py :h(RS ;  
DY#195H  
)Lz =[e  
最终的Dockerfile 9 C)VW  
现在,整个Dockerfile看起来应该是这样的: EmaS/]X[  
J.R]) &CB  
8XYxyOl  
############################################################ &wlD`0v  
# Dockerfile to build Python WSGI Application Containers Vz0(D  
# Based on Ubuntu 0UJ6> Rj  
############################################################ '4M{Xn}@  
cO]w*Hti  
b_`h2dUq  
# Set the base image to Ubuntu @U!&XZ]h  
FROM ubuntu E G+/2o+W  
C7F\Y1Wj  
K6-)l isf  
# File Author / Maintainer {J)%6eL?  
MAINTAINER Maintaner Name 9n is8  
OK v2..8  
C-A? mIC  
# Add the application resources URL c BqbbZyUk  
RUN echo "deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -sc) main universe" >> /etc/apt/sources.list [R1|=kGU  
XY{N"S8  
 omg#[  
# Update the sources list [ >mH  
RUN apt-get update Y2tVq})!  
Y!45Kio  
EUs9BJFP  
# Install basic applications va_u4  
RUN apt-get install -y tar git curl nano wget dialog net-tools build-essential sN8pwRjb  
@]IRB1X  
3 1c*^ZE.  
# Install Python and Basic Python Tools ;Q,t65+Am  
RUN apt-get install -y python python-dev python-distribute python-pip %\-E R !b  
"f 89   
?\8  
# Copy the application folder inside the container s<"|'~<n  
ADD /my_application /my_application ECi;o1hda  
bK!h{Rr  
cH*")oD  
# Get pip to download and install requirements: '*L6@e#U  
RUN pip install -r /my_application/requirements.txt ip<VRC5`5  
 :QP1!  
c*7|>7C$i  
# Expose ports P<Bx1H-z-  
EXPOSE 80 vGlVr.)  
pTi7Xy!Cw  
niCK(&z  
# Set the default directory where CMD will execute BFw_T3}zn  
WORKDIR /my_application D|Q7dIZm  
:8eI_X  
Lu6g`O:['  
# Set the default command to execute     JDR_k  
# when creating a new container Z@dVK`nD  
# i.e. using CherryPy to serve the application b MD|  
CMD python server.py w>9d^kU'  
XxMZU(5  
UJh;Hp:  
按 CTRL+X 再按 Y 键,保存退出。 4@{?4k-cq  
ws9IO ?|&G  
2<B'PR-??y  
使用Dockerfile进行自动化的容器创建 8cOft ;|qB  
在之前的基础教程部分我们提到过,Dockerfile的工作方式利用到了 docker build 命令。 'I/_vqp@  
2`riI*fQ  
b9X*2pnWJ  
我们通过Dockerfile指示docker从包含源代码的路径复制内容到容器内部,因此在构建之前务必要确认Dockerfile与代码路径的相对位置。 Dh8'og)7  
.\_RavW23  
`K5*Fjx  
这样一个Docker镜像可以快速创建起来一个可以运行我们的Python应用的容器,我们需要做的只是输入这样一行指令: s.bo;lk  
;DK%!."%  
3E*m.jX  
sudo docker build -t my_application_img . O%kUj&h^  
WqF,\y%W*  
pAatv;Ex  
我们把这个镜像命名为 my_application_img 。为要从这个镜像启动一个新的容器,只需要输入下面的命令: 3<W%z]k@M  
HuTtp|zM>  
q 7%p3  
sudo docker run -name my_application_instance -p 80:80 -i -t my_application_img O_1[KiZ  
wxvi)|)  
u|t l@_  
然后就可以在浏览器里输入你VPS的IP地址,访问应用了。 A/<u>cCW  
ErNYiYLi]  
cw!,.o%cD  
有关Docker安装的更多教程(包括在其他发行版上安装Docker),可以查阅我们在docker.io上的文档docker installation documentation。 $!>.h*np  
!-7n69:G  
[ 此帖被寒喵在2018-12-29 19:19重新编辑 ]
本人不是云栖社区工作人员。
无论您在使用中遇到什么问题,不要出言不逊!谢谢合作!
发表主题 回复主题
« 返回列表上一主题下一主题

限100 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
验证问题: 阿里云官网域名是什么? 正确答案:www.aliyun.com
上一个 下一个