Dockerfile搭建环境并打包应用

在上一章Docker构建nginx+uwsgi+flask镜像(一)的学习中,我们学会用命令行一句一句在alpine环境中搭建nginx+uwsgi+flask服务,但这体现不了Docker为我们带来的便利,而本章,我们将通过Dockerfile来制作基础镜像和打包应用,因此会有两个Dockerfile文件。

我们先来写第一个Dockerfile文件,这个文件负责搭建运行环境,运行环境需要包括:nginx、uwsgi、Python3:

# 配置基础镜像
FROM alpine:3.8 # 添加标签说明
LABEL author="moshangguang" email="XXX@qq.com" purpose="nginx+uwsgi+Python3基础镜像" # 配置清华镜像地址
RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.8/main/" > /etc/apk/repositories # 更新升级软件
RUN apk add --update --upgrade # 安装软件
RUN apk add --no-cache nginx python3 uwsgi uwsgi-python3 # 升级pip,这一步同时会在/usr/bin/目录下生成pip可执行文件
RUN pip3 install --no-cache-dir --upgrade pip # 建立软链接
RUN ln -s /usr/bin/python3 /usr/bin/python

     

上面的安装软件相比之前少了个vim,因为之前我们是在容器内部编辑配置文件,所以需要这个命令,但现在我们的配置文件都是预先在容器之外编辑好在通过docker拷贝到容器内部,所以也就无需安装vim。另外建立软连接时,我们只建立了从python到python3的软连接,没有建立pip到pip3的软链接,因为/usr/bin/pip在安装软件时已经生成。

执行docker build命令,生成镜像,执行docker images命令可以看到生成nginx_uwsgi_py3镜像,标签为alpine3.8:

[root@ docker]# docker build -t nginx_uwsgi_py3:alpine3.8 .
Sending build context to Docker daemon 4.096 kB
……
Successfully built 63be35fe36ca
[root@ docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx_uwsgi_py3 alpine3.8 63be35fe36ca 5 minutes ago 60 MB

  

于是,我们完成了第一个Dockerfile文件,这个Dockerfile文件可以为我们搭建我们所需要的运行环境镜像。

我们可以把构建好的基础镜像推送到我们的Docker hub仓库,先用docker login登录之后

[root@ docker]# docker login -u moshangguang -p 123456
Login Succeeded

  

tips:上面登录密码是假的哈。

然后为我们的镜像打上tag,之后推送镜像。

[root@ docker]# docker tag 687445ba4c7f moshangguang/nginx_uwsgi_py3:alpine3.8
[root@ docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
moshangguang/nginx_uwsgi_py3 alpine3.8 63be35fe36ca 22 minutes ago 60 MB
nginx_uwsgi_py3 alpine3.8 63be35fe36ca 22 minutes ago 60 MB
[root@iZj6c0zloujsauztjjhyhgZ docker]# docker push moshangguang/nginx_uwsgi_py3:alpine3.8
The push refers to a repository [docker.io/moshangguang/nginx_uwsgi_py3]
……
alpine3.8: digest: sha256:412ec97c1c51dffeee6b924494bc size: 1154

  

有了基础镜像,我们就可以开始编写我们的应用了,这里先给出我们应用的目录结构(web_app在github上的地址):

[root@ docker]# tree web_app
web_app
├── app
│   ├── app.py
│   ├── requirements.txt
│   └── uwsgi.ini
├── Dockerfile
└── nginx.conf 1 directory, 5 files

  

最外层的web_app目录包含一个app目录,和两个文件,分别是Dockerfile、nginx.conf,注意,web_app下的Dockerfile文件和之前的Dockerfile文件不同,这里的Dockerfile文件是用来打包应用的。nginx.conf文件在打包应用时会拷贝到容器中,作为nginx启动的配置。

app目录下有三个文件,分别是:app.py、requirements.txt和uwsgi.ini。我们唯一不熟悉的就是requirements.txt,这个文件用来存放我们Python应用所需要的库,如flask、flask_sqlalchemy等等。在打包应用时会执行pip命令读取这个文件的内容,安装我们所需要的库。

这里,我们打印下requirements.txt的内容:

[root@ app]# cat requirements.txt
flask
flask_sqlalchemy

  

app.py文件也略做修改,新增两个路由/hello和/world:

from flask import Flask

app = Flask(__name__)

@app.route('/hello')
def hello():
return 'Hello!!!\n' @app.route('/world')
def world():
return 'World!!!\n' @app.route('/')
def hello_world():
return 'Hello World!!!\n' if __name__ == '__main__':
app.run()

  

上一章中,我们在uwsgi.ini文件中将uwsgi-socket配置绑定到本机的9000端口,同时在nginx.conf文件中设置uwsgi_pass,将请求转发到9000端口,这样的做法显得有些累赘,如果以后我不想用9000端口,意味着我需要改两个地方。那么,有没有办法让uwsgi自动获取绑定到一个端口,而nginx.conf又能获取到uwsgi所绑定的端口呢?肯定是有的:

uwsgi.ini

[uwsgi]
uwsgi-socket = /tmp/uwsgi.sock
chmod-socket = 777
callable = app
plugin = python3
wsgi-file = app.py
buffer-size = 65535
processes = %(%k * 2)
threads = %(%k * 20)
disable-logging = true

    

上面的uwsgi.ini文件中,我们不再将uwsgi-socket这个配置项绑定到特定的一个端口,而是指定了一个文件,这个文件是Unix套接字,即通过文件系统(而非网络地址)进行寻址和访问的套接字。配置uwsgi-socket之后,还需要配置chmod-socket,Unix socket是个文件,所以会受到Unix系统的权限限制,可以配置成660或者777,使得uwsgi客户端能够访问这个Unix socket文件,这里配置为777。

这里新增两个优化参数:processes和threads,分别是开启的进程数和线程数,而%k是魔数变量,代表CPU核数,如果我们是双核CPU,那这里的processes和threads分别为4和40,即有4个进程,每个进程有40个线程。disable-logging的意思一目了然,代表不记录请求信息的日志,只记录错误以及uwsgi内部消息到日志中。

最后,我们再来看下nginx.conf需要做改动的地方,其实也就是http模块下的server:

server {
listen 6666;
charset utf-8;
client_max_body_size 75M;
location / {
include uwsgi_params;
uwsgi_pass unix:///tmp/uwsgi.sock;
……
}
}

  

其实改动的地方也只有一个uwsgi_pass,原先我们是直接绑定在9000端口上,而现在我们要指向uwsgi-socket所指向的Unix套接字。这样,nginx就可以自动将请求转发给uwsgi所监听的套接字了。

这里给出nginx.conf全部的内容:

user  nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_rlimit_nofile 20480; events {
use epoll;
worker_connections 20480;
multi_accept on;
} http {
include /etc/nginx/mime.types;
default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#请求量级大建议关闭acccess_log
#access_log /var/log/nginx/access.log main; sendfile on;
#tcp_nopush on; keepalive_timeout 300s;
client_header_timeout 300s;
client_body_timeout 300s; gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_types text/html application/javascript application/json; include /etc/nginx/conf.d/*.conf; server {
listen 6666;
charset utf-8;
client_max_body_size 75M;
location / {
include uwsgi_params;
uwsgi_pass unix:///tmp/uwsgi.sock;
uwsgi_send_timeout 300;
uwsgi_connect_timeout 300;
uwsgi_read_timeout 300;
}
}
}

  

最后,我们来看下用于打包应用的Dockerfile:

# 使用基础镜像库
FROM moshangguang/nginx_uwsgi_py3:alpine3.8 # 创建工作路径
RUN mkdir /app # 指定容器启动时执行的命令都在app目录下执行
WORKDIR /app # 替换nginx的配置
COPY nginx.conf /etc/nginx/nginx.conf # 将本地app目录下的内容拷贝到容器的app目录下
COPY ./app/ /app/ # pip读取requirements.txt内容安装所需的库
RUN pip install -r /app/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple some-package --no-cache-dir # 启动nginx和uwsgi
ENTRYPOINT nginx -g "daemon on;" && uwsgi --ini /app/uwsgi.ini

  

上面的每一条命令都有注释,这里就不再多作介绍了。

现在,让我们来打包web_app应用吧!将工作目录移到web_app目录下,执行docker build命令,创建镜像:

[root@ web_app]# docker build -t web_app .
Sending build context to Docker daemon 24.58 kB
……
Successfully built 88212eefb0b4

查看刚刚创建的web_app镜像:

[root@ web_app]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
web_app latest 88212eefb0b4 About a minute ago 79.9 MB

  

根据镜像启动一个容器,容器内部的nginx监听的是6666端口,而宿主机则用9999端口接收请求,再转发到容器内部的6666端口:

[root@ web_app]# docker run -p 9999:6666 -d web_app
a8cd1104dfc994637011ebd9dd9160d62eab64b1c9bb6ceb9266c092eb425452

  

这里,测试容器内的应用是否能正常处理用户的请求:

到此为止,我们便完成了用Docker构建基础镜像,并打包应用了。

Docker构建nginx+uwsgi+flask镜像(二)的更多相关文章

  1. Docker构建nginx+uwsgi+flask镜像(一)

    前言 笔者之前是从事Java方面的工作,自从18年5月左右来到新的公司,接触到Python,被其简单优雅的语法风格深深吸引,同时,新公司也帮助笔者打开Docker世界的大门,让笔者体会到“一次打包,到 ...

  2. 使用 Docker 和 Nginx 打造高性能的二维码服务

    使用 Docker 和 Nginx 打造高性能的二维码服务 本文将演示如何使用 Docker 完整打造一个基于 Nginx 的高性能二维码服务,以及对整个服务镜像进行优化的方法.如果你的网络状况良好, ...

  3. Ubuntu下nginx+uwsgi+flask的执行环境搭建

    选择web framwork是个非常艰难的事情, 主要分为轻量级和重量级框架. 因为没有搭建站点这样的须要, 所以回避SSH, Django这样的框架, 而选择一个轻量级框架. 自己也比較青睐pyth ...

  4. 一次请求中,经过 nginx+uWSGI+flask应用程序搭建服务的执行过程

    Flask框架有自带的http server,但是缺点非常明显,并发能力,及时响应非常差,只适合开发时自测使用. 在我接触过的项目中,生产环境使用nginx+uWSGI+flask应用程序进行部署服务 ...

  5. nginx+uwsgi+flask 服务器配置

    注:每个机器,软件版本可能不一样,虽然网上有很多类似的帖子,但是我在搭建的时候遇到了不少的坑,此文仅供参考. 请求流程: 1.安装uwsgi uwsgi是一个应用服务器,非静态文件的网络请求就必须通过 ...

  6. Ubuntu下使用Nginx+uWSGI+Flask(初体验)

    Ubuntu 18.04,Nginx 1.14.0, uWSGI 2.0.17.1,Flask, 前言 Windows不支持uWSGI!为了上线自己的项目,只能选择Linux. 自己前面开发了一个Fl ...

  7. nginx+uwsgi+flask+supervisor 项目部署

    环境 - Linux: Ubuntu 16.04 - uWSGI 2.0.18 - Flask 1.0.2 - supervisor 3.2.0 - nginx/1.8.1 首先区分几个概念 WSGI ...

  8. 用Docker构建Nginx镜像

    1构建Nginx镜像 1建立工作目录 [root@localhost ]# mkdir 1nginx [root@localhost 1nginx]# cd 1nginx/ [root@localho ...

  9. 服务器配置:ECS+Nginx+uWSGI+Flask——各部分详细介绍

    希望在阿里云ECS上搭建一个flask框架的web应用,经典的形式便是flask+uWSGI+nginx模式 服务器:CentOS 7.3 python版本:3.8.0 先贴一张全局图,这张图很清楚的 ...

随机推荐

  1. WebRTC协议

    webrtc协议介绍 MDN webrtc协议 ICE 交互式连接建立Interactive Connectivity Establishment (ICE) 是一个允许你的浏览器和对端浏览器建立连接 ...

  2. Spring Boot入门程序

    创建第一个Spring Boot的入门程序. 带你一步一步的,搭建第一个Spring Boot 的入门程序,并成功运行,通过实践过程,初步认识和了解如何使用Spring Boot 创建应用程序. 一. ...

  3. Java中的字符集

    Java中的字符集 1.字符集概述 字符集是各国家文字与字符编码对照表.字符可以看成是计算机中展示的图案效果,每个字符集都对每一种图案进行编码,有着一对一的对应关系.因此进行字符输出时,都需要指定使用 ...

  4. graphql 数据增删改查分页及关联操作(三)

    说明: 接第二篇文章,代码也是在第二篇文章之上 本文只是针对mondodb来操作 一.添加相关的包 yarn add Mongoose 二.初始化Mongodb 修改server.ts 导入 impo ...

  5. [译文]PHP千年虫(y2k compliance)

    时钟将我们无情地逼近2000年的最后一年,第二年厄运塞耶斯都预言前所未有的电脑故障在每一个可以想象的领域.通常被称为2000年问题,或千年虫,这种 情况很容易解释.程序解释两位在形成XX日期19 XX ...

  6. log4net 简单配置

    <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigu ...

  7. bzoj2568 比特集合

    Description 比特集合是一种抽象数据类型(Abstract Data Type) ,其包含一个集合S,并支持如下几种操作: INS M : 将元素 M 插入到集合S中: DEL M : 将集 ...

  8. 学习MyBatis之简单入门HelloWorld

    转:https://blog.csdn.net/gaomb_1990/article/details/78299784 一.准备 Eclipse:Luna Service Release 1 (4.4 ...

  9. Android开发之动态创建多个按钮

    //获取屏幕大小,以合理设定 按钮 大小及位置 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDispl ...

  10. redis set类型