在开发中应用Docker
本文是一个简单的python容器部署工作流,按照「Docker开发指南」一书实践。
案例是采用Flask实现的一个简单web程序,仅用于展示Docker工作流程。
简单的Web服务代码
示例程序名字是
identidock,创建程序目录
mkdir -p identidock/app
cd identidock/app
vi identidock.py创建Web服务
按照以下目录结构
]$ tree identidock/
identidock/
└── app
└── identidock.pyidentidock.py代码内容如下
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello Docker!\n'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')在
identidock目录下创建Dockerfile内容如下:
如果要使用最新版本,可以在上述Dockerfile中不指定版本
以上Dockerfile使用Python 3的官方基础镜像,并在镜像基础之上安装 Flask ,然后复制代码进去,并运行identidock代码。
许多流行的编程语言,例如 Python、Go 和 Ruby,它们的官方仓库中都有多个变种镜像以供不同用途:
slim - 这种镜像是标准镜像的精简版本。它们缺少很多常见的软件包和库。适合在生产环境部署,但是不适合开发环境(缺少标准镜像中的工具软件包等)
onbuild - 这种镜像使用 Dockerfile 的 ONBUILD 指令,它会把某些命令延后至继承这个 onbuild 镜像的“子镜像”中执行,而执行的时刻便是新建这个子镜像的时候。
构建运行
运行
-d参数表示后台运行启动容器
-p固定端口映射,如果使用-p 5000则会把容器内的5000端口动态随机映射到host上。通常我们用于在host上运行大量容器,则采用随机动态端口映射。这里没有指定容器的名字(
--name),也没有指定容器内运行的主机名(--hostname),所以会随机生成一个容器名称
上述运行的容器对外5000端口是容器内flash的端口,可以直接通过浏览器访问 http://127.0.0.1:5000 (或者host主机的IP地址),或者用命令行检测:
uWSGI
由于容器提供了隔离,所以在部署Python服务时可以不使用virtualenv。不过,这种情况适用于真正采用了容器的轻量级部署(serverless)。如果还是部署以前的完整操作系统,则会抵消掉容器的灵活性和轻量级特性,此时再使用virtualenv隔离应用也可作为补充。
但是,依然建议真正使用容器来做隔离,抛弃以往既定的服务器部署思维。
uWSGI 是一个可以用于生产环境的应用服务器,并且可以部署在Web服务器如Nginx后端。
请参考以下关于uWSGI部署方法:
改进Dockerfile,引入uWSGI:
添加uWSGI
运行uWSGI监听9090端口的http服务,并从
/app/identidock.py运行app应用在9191启动一个数据统计服务
构建容器镜像
注意:这里再次使用了同名的
identidock作为构建 容器镜像 的名字。那么docker会如何处理重名的镜像呢?是报错么?不是,docker构建了新的同名镜像,并且把老的镜像改名成
<none>
启动容器
同样测试
使用curl localhost:9191可以看到统计信息
注意:上述docker容器中运行uWSGI是使用root身份运行的,这是一个安全漏洞。需要在Dockerfile中指定运行服务的用户身份:
注意在任何Dockerfile中都要注意配置正确的USER设置以便能够以正确的身份运行服务!!!
在docker run指令中加上-P参数,则不绑定主机端口,会随机选择高端口,并自动将它们映射到容器每个声明的EXPOSE端口。不过,此时要访问容器服务前,先要检查容器随机选择的输出端口:
测试环境和生产环境的切换
为了能够适用于开发环境和生产环境,可以采用脚本来判断环境变量来采用不同的启动命令:
将上述脚本保存成cmd.sh就可以修改Dockerfile如下
然后执行如下命令启动容器
Last updated
Was this helpful?