Loading... <p>这次我们创建一个Hello world的web服务器。</p> <h3>一 </h3> <pre class="brush:bash;toolbar:false">mkdir -p identidock/app #首先创建一个新的multiidentidock来存放我们的项目,在这个目录下面,创建一个app目录来存放Python代码。 touch app/identidock.py #在app目录下创建identidock.py</pre> <pre class="brush:python;toolbar:false"># 编辑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作为主机参数绑定了所有的网络接口</pre> <p></p> <pre class="brush:bash;toolbar:false;">#现在我们需要一个存放Python代码的容器然后运行它。在identidock目录下面创建一个Dockerfile文件,并且编辑如下内容 FROM python:3.4 RUN pip install Flask==0.10.1 WORKDIR /app COPY app /app CMD ["python" "identidock.py"]</pre> <p></p> <p>现在我们可以构建我们的简单镜像了</p> <pre class="brush:bash;toolbar:false;">docker build -t identidock . …… docker run -d -p 5000:5000 identidock</pre> <pre class="brush:bash;toolbar:false">-d 代表在后台运行容器 -p 代表我们想转发主机的5000端口到容器的5000端口</pre> <pre class="brush:bash;toolbar:false">curl localhost:5000 #进行测试 Hello World!</pre> <p><strong>但是有一些问题存在:每次代码的改变,我们都需要重新构建镜像然后重启这个容器</strong>。</p> <p>对此,有一个简单的解决方案,我们可以绑定主机的源代码文件夹到内部容器文件夹中。</p> <h3>二</h3> <pre class="brush:bash;toolbar:false;">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 参数必须是绝对路径。</pre> <pre class="brush:bash;toolbar:false">curl localhost:5000 #测试 Hello world!</pre> <p>现在我们可以在主机上编辑文件看看</p> <pre class="brush:bash;toolbar:false">sed -i 's/World/Docker/' app/identidock.py #使用sed快速替换World为Docker,你也可以使用正常的文本编辑器。 curl localhost:5000 Hello Docker!</pre> <p>现在除了容器内容封装的一些依赖关系,我们就拥有了一个相对正常的开发环境了。<strong>然而这里还有一个问题,那就是我们不能在生产环境使用这个容器,因为它正在运行的是默认的Flask webserver,它只适用于开发者,在生产环境中则效率低下并且不安全</strong>。一个好的解决方法就是采纳Docker减少开发环境和生产环境的区别,现在让我们在看一下怎么处理吧。</p> <h3>三</h3> <p>uWSGI是一个为生产环境准备的应用服务器,它也可以位于类似于Nginx的web server后面。使用uWSGI代替Flask webserver会提供我们一个灵活的容器,方便我们进行设置。我们可以转换这个容器到使用uwSGI容器只需要修改Dockerfile中的两行。</p> <p></p> <pre class="brush:bash;toolbar:false">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"]</pre> <p></p> <pre class="brush:bash;toolbar:false">docker build -t identidock #构建这个镜像,然后运行它我们可以看到其中的不同 …… docker run -d -p 9090:9090 -p 9191:9191 identidock curl localhost:9090 Hello Docker!</pre> <p>你可以使用docker logs来看一下日志uWSGI的日志信息。当然我们也可以在http://localhost:9191中看到一些uWSGI暴露的状态信息。</p> <p>但是实际上,<strong>上面会提示一个安全问题,我们使用root来运行服务了。</strong>我们可以在Dockerfile中很容易的修复这个问题,同时我们在声明一下容器监听的端口。</p> <h3>四</h3> <pre class="brush:bash;toolbar:false">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"]</pre> <pre class="brush:bash;toolbar:false">docker build -t identidock . #重建这个镜像 ... docker run identidock whoami uwsgi</pre> <p><span style="text-decoration: underline"><strong>#你最好在你的所有的Dockerfile中设置用户,或者在ENTRYPOINT或CMD脚本中改变用户。</strong></span></p> <p>现在在容器呢把的命令不是以root来运行了,让我们运行一下这个容器试试。。</p> <pre class="brush:bash;toolbar:false">docker run -d -P --name port-test identidock #-P 让Docker自动的映射一个大数字的本地主机端口到容器内部。</pre> <p></p> <p>我们可以看下那个端口被映射了</p> <pre class="brush:bash;toolbar:false">docker port port-test 9090/tcp -> 0.0.0.0:32769 9191/tcp -> 0.0.0.0:32768</pre> <pre class="brush:bash;toolbar:false">curl localhost:32769 #现在做个测试 Hello Docker!</pre> <p><strong>现在还存在一个问题,那就是我们缺失了开发工具,例如调试输出和实时的代码重载。</strong>理想情况下,我们想要使用这个镜像既可以作为开发环境又可以作为生产环境。我们可以使用环境变量和一个简单的脚本来实现这个需求。</p> <h3>五 </h3> <p>在和Dockerfile相同的目录下创建cmd.sh,然后编辑如下内容</p> <pre class="brush:python;toolbar:false">#!/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</pre> <pre class="brush:bash;toolbar:false;">chmod +x cmd.sh</pre> <pre class="brush:bash;toolbar:false">#编辑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"]</pre> <pre class="brush:bash;toolbar:false">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</pre> <pre class="brush:bash;toolbar:false">docker run -p 5000:5000 -v $(pwd)/app:/app -e "ENV=DEV" identidock #这时我们可以实时修改代码了</pre> <p></p> <p>然后再不加ENV=DEV的情况下运行就是成产环境了。</p> <p></p> <h2>小结:</h2> <p>上面依次展示了一些Docker生产中可能会存在的问题。并且提供了最后的解决方案。</p> <p></p> 最后修改:2021 年 12 月 10 日 10 : 53 AM © 允许规范转载 赞赏 如果觉得我的文章对你有用,请随意赞赏 赞赏作者 支付宝微信