基于Docker的工作流

这次我们创建一个Hello world的web服务器。

一 

mkdir -p identidock/app   #首先创建一个新的multiidentidock来存放我们的项目,在这个目录下面,创建一个app目录来存放Python代码。
touch app/identidock.py  #在app目录下创建identidock.py
# 编辑identidock.py的内容
from flask import Flask
app = Flask(__name__)  #初始化Flask和设置应用对象
@app.route('/')     #创建一个与URL关联的路由,当这个URL被请求,它会调用hello_world函数。
def hello_world():
        return "Hello Docker!\n"
if __name__ == '__main__':
        app.run(debug=True,host='0.0.0.0')  #初始化Python web服务器,使用0.0.0.0作为主机参数绑定了所有的网络接口

#现在我们需要一个存放Python代码的容器然后运行它。在identidock目录下面创建一个Dockerfile文件,并且编辑如下内容
FROM python:3.4
RUN pip install Flask==0.10.1
WORKDIR /app
COPY app /app
CMD ["python" "identidock.py"]

现在我们可以构建我们的简单镜像了

docker build -t identidock .
……
docker run -d -p 5000:5000 identidock
-d 代表在后台运行容器
-p 代表我们想转发主机的5000端口到容器的5000端口
curl localhost:5000    #进行测试
Hello World!

但是有一些问题存在:每次代码的改变,我们都需要重新构建镜像然后重启这个容器

对此,有一个简单的解决方案,我们可以绑定主机的源代码文件夹到内部容器文件夹中。

docker stop $(docker ps -ql)  #停止最近创建的容器
docker rm $(docker ps -lq)    #删除最近创建的容器
docker run -d -p 5000:5000 -v $(pwd)/app:/app identidock
-v $(pwd)/app:/app 参数绑定app目录到容器的/app。 它会覆盖容器内/app的内容,同时对于容器内部也是可写的(你也可以挂载为只读模式)-v 参数必须是绝对路径。
curl localhost:5000  #测试
Hello world!

现在我们可以在主机上编辑文件看看

sed -i 's/World/Docker/' app/identidock.py  #使用sed快速替换World为Docker,你也可以使用正常的文本编辑器。
curl localhost:5000
Hello Docker!

现在除了容器内容封装的一些依赖关系,我们就拥有了一个相对正常的开发环境了。然而这里还有一个问题,那就是我们不能在生产环境使用这个容器,因为它正在运行的是默认的Flask webserver,它只适用于开发者,在生产环境中则效率低下并且不安全。一个好的解决方法就是采纳Docker减少开发环境和生产环境的区别,现在让我们在看一下怎么处理吧。

uWSGI是一个为生产环境准备的应用服务器,它也可以位于类似于Nginx的web server后面。使用uWSGI代替Flask webserver会提供我们一个灵活的容器,方便我们进行设置。我们可以转换这个容器到使用uwSGI容器只需要修改Dockerfile中的两行。

FROM python:3.4
RUN pip install Flask==0.10.1 uWSGI==2.0.8 
WORKDIR /app
COPY app /app
CMD ["uwsgi", "--http", "0.0.0.0:9090", "--wsgi-file", "/app/identidock.py", \
     "--callable", "app", "--stats", "0.0.0.0:9191"]

docker build -t identidock  #构建这个镜像,然后运行它我们可以看到其中的不同
……
docker run -d -p 9090:9090 -p 9191:9191 identidock
curl localhost:9090
Hello Docker!

你可以使用docker logs来看一下日志uWSGI的日志信息。当然我们也可以在http://localhost:9191中看到一些uWSGI暴露的状态信息。

但是实际上,上面会提示一个安全问题,我们使用root来运行服务了。我们可以在Dockerfile中很容易的修复这个问题,同时我们在声明一下容器监听的端口。

FROM python:3.4
RUN groupadd -r uwsgi && useradd -r -g uwsgi uwsgi
RUN pip install Flask==0.10.1 uWSGI==2.0.8
WORKDIR /app
COPY app /app
COPY cmd.sh /
EXPOSE 9090 9191
USER uwsgi
CMD ["uwsgi","--http","0.0.0.0:9090","--wsgi-file","/app/identidock.py", \
"--callable","app","--stats","0.0.0.0:9191"]
docker build -t identidock . #重建这个镜像
...
docker run identidock whoami 
uwsgi

#你最好在你的所有的Dockerfile中设置用户,或者在ENTRYPOINT或CMD脚本中改变用户。

现在在容器呢把的命令不是以root来运行了,让我们运行一下这个容器试试。。

docker run -d -P --name port-test identidock
#-P 让Docker自动的映射一个大数字的本地主机端口到容器内部。

我们可以看下那个端口被映射了

docker port port-test 
9090/tcp -> 0.0.0.0:32769 
9191/tcp -> 0.0.0.0:32768
curl localhost:32769 #现在做个测试
Hello Docker!

现在还存在一个问题,那就是我们缺失了开发工具,例如调试输出和实时的代码重载。理想情况下,我们想要使用这个镜像既可以作为开发环境又可以作为生产环境。我们可以使用环境变量和一个简单的脚本来实现这个需求。

五 

在和Dockerfile相同的目录下创建cmd.sh,然后编辑如下内容

#!/bin/bash set -e
if [ "$ENV" = 'DEV' ]; then
  echo "Running Development Server"
  exec python "identidock.py" 
else
  echo "Running Production Server"
  exec uwsgi --http 0.0.0.0:9090 --wsgi-file /app/identidock.py \
             --callable app --stats 0.0.0.0:9191 
fi
chmod +x cmd.sh
#编辑Dockerfile
FROM python:3.4
RUN groupadd -r uwsgi && useradd -r -g uwsgi uwsgi
RUN pip install Flask==0.10.1 uWSGI==2.0.8
WORKDIR /app
COPY app /app
COPY cmd.sh /
EXPOSE 9090 9191
USER uwsgi
CMD ["/cmd.sh"]
docker stop $(docker ps -q)
docker rmr $(docker ps -aq)
docker build -t identidock .  #重建镜像
docker run -e "ENV=DEV" -p 5000:5000 identidock
Running in development environment.
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger pin code: 290-812-275
docker run -p 5000:5000 -v $(pwd)/app:/app -e "ENV=DEV" identidock #这时我们可以实时修改代码了

然后再不加ENV=DEV的情况下运行就是成产环境了。

小结:

上面依次展示了一些Docker生产中可能会存在的问题。并且提供了最后的解决方案。

原创文章,作者:艾贺,如若转载,请注明出处:http://www.178linux.com/11883

(1)
艾贺艾贺
上一篇 2016-03-01
下一篇 2016-03-03

相关推荐

  • 浅谈bash shell 变量

    一、简述 变量是指内存空间的命名,指向内存中一个或一组地址。bash shell中的变量属于弱类型变量,使用变量无需声明、不需要指定类型,默认为字符型变量。 二、变量命名、赋值、引用 (1)命名规则:     1.只能使用字母,数字,下划线;并且不能使用数字开头。     2.不…

    Linux干货 2016-08-15
  • AWK

    GNU awk 全称:Aho,Weiberger,Kernighan,是三个作者的名字,所以简称为awk awk:报告生成器,主要用来格式化文本输出的,它能够实现在处理文本文件时对文档中的字段有条件的显示,而且将显示的结果用非常美观的文本形式给予输出。我们所用的awk其实就是gawk,他是一个符号链接指向gawk的。 gawk – pattern…

    Linux干货 2016-09-23
  • 初学Linux的感受

    我是马哥25期的学员,之前从来没有接触过Linux,近几天学习Linux下来,收获很多,懂了一些基本命令,以及安装Linux系统. 我知道从一个什么也不懂的小白变成站在云端的大神,这之间需要付出多少的努力和汗水.开学典礼有幸见到马哥本人,也见到 我的授课教师老王,之前看到两位上课的视频,诙谐幽默,我很喜欢! 但愿我这四个月痛并快乐着. 努力,然后看到胜利的曙…

    Linux干货 2017-07-11
  • iptables总结

    iptables简称为包过滤型防火墙一般分为2种:     1,主机防火墙:主机防火墙是用来防止本主机内的应用服务被攻击所需要保护的防火墙     2,网络防火墙:做为想路由功能的防火墙凡是进过此服务器的数据包都要进行规则匹配 iptables的架构由功能和链组成  &…

    Linux干货 2016-12-05
  • 文本处理三剑客之grep及正则表达式

    文本处理三剑客之grep及正则表达式   文本处理工具:   Linux上处理文本三剑客:     Grep:文本过滤器工具(模式:pattern)工具;     Sed: stream editor,流编辑器;文本编辑工具;   &nbs…

    Linux干货 2016-08-12
  • 开篇

    test 新人报道

    Linux干货 2016-10-28

评论列表(1条)

  • stanley
    stanley 2016-03-03 09:40

    ENV=DEV的情况下运行就是成产环境了。 ==> 看到文章中有思考的地方了 赞