zabbix通过企业微信应用发送告警消息

本文参考大佬们的方法整理记录

首先注册申请(http://work.weixin.qq.com/?spm=5176.11156381.0.0.43bb71b2a3RojM)微信企业号
登录企业微信web后台,在【我的企业】选择【企业信息】,查看CorpID
在【企业应用】选择【创建应用】,完成后记录AgentId和Secret

未分类

TIPS

可以通过接口调试工具(http://work.weixin.qq.com/api/devtools/devtool.php?spm=5176.11156381.0.0.43bb71b2a3RojM)测试是否可以成功返回access_token

参考官方API说明发送应用(https://work.weixin.qq.com/api/doc?spm=5176.11156381.0.0.43bb71b2MZpcTD#10167)

配置自定义脚本

这里引用Zhang Sir’s (https://www.zhsir.org/article/134.html?spm=5176.11156381.0.0.43bb71b2MZpcTD)脚本,下载到zabbix_server.conf中设置的自定义告警脚本存放目录下,也可以参考GitHub上微信报警项目(https://github.com/X-Mars/Zabbix-Alert-WeChat?spm=5176.11156381.0.0.43bb71b29DyTuu)

# grep alertscripts /etc/zabbix/zabbix_server.conf 
AlertScriptsPath=/usr/lib/zabbix/alertscripts
# wget http://download.zhsir.org/Zabbix/weixin_linux_amd64
# mv weixin_linux_amd64 wechat
# chmod 755 wechat 
# chown  zabbix:zabbix wechat
# ./wechat -h
Usage of ./wechat:
  -agentid string
        agentid
  -author string
        http://www.oneoaas.com
  -corpid string
        corpid
  -corpsecret string
        corpsecret
  -msg string
        Send Message
  -user string
        which user to send msg
# ./wechat --corpid=CorpID --agentid=企业应用ID --corpsecret=企业应用Secret --msg="告警消息" --user=消息接收者的企业微信账号  
{"errcode":0,"errmsg":"ok","invaliduser":""}  #命令行测试是否可以发信

zabbix server端脚本定义完成后,可以应用到已经接入的主机,直接更新告警媒介即可

【管理/Adminastration】—>【媒介类型/Media Types】—>【创建媒体类型/Create Media Types】

未分类

添加用户告警的媒介并更新
【管理/Adminastration】—>【用户/Users】—>【媒介/Media】

未分类

添加主机后将主机加入用户和组,并创建监控项和触发器及动作
【配置/Configuration】—>【主机/host】—>【监控项】—>【触发器】
注意触发器的严重性需设置和action中定义的触发条件一致

未分类

【配置/Configuration】—>【动作/Actions】—>【创建动作/Create action】
定义告警的触发条件,以及告警默认信息,持续时间

未分类

未分类

Zabbix agent安装(源码包)

1、创建zabbix用户和组

# groupadd zabbix
# useradd -g zabbix zabbix -s /sbin/nologin

2、安装支持的类库

# yum -y install pcre*    //它是一个用C语言编写的正则表达式函数库

3、解压zabbix源码包并编译安装

# tar -xf zabbix-3.4.8.tar.gz
# cd /opt/zabbix-3.4.8
# ./configure --prefix=/usr/local/zabbix-agent --enable-agent
# make 
# make install

4、拷贝zabbix客户端启动脚本到/etc/init.d目录下

# cp misc/init.d/tru64/zabbix_agentd /etc/init.d/
# chmod +x /etc/init.d/zabbix_agentd

5、修改zabbix_agentd启动脚本

# vim /etc/init.d/zabbix_agentd

1)#!/bin/sh下面添加两行 #使其支持chkconfig配置服务

#chkconfig: 345 95 95
#description: Zabbix_Server

2)将DAEMON启动命令路径修改为安装时指定的路径。

DAEMON=/usr/local/sbin/zabbix_agentd      # 默认脚本启动服务的路径                

修改为:

DAEMON=/usr/local/zabbix-agent/sbin/zabbix_agentd     #安装时指定的路径

# 脚本启动服务的这个路径根据安装时指定的路径来设定;

6、设置zabbix_agentd服务开机启动

# chkconfig --add zabbix_agentd

# systemctl start zabbix_agentd       //启动zabbix
# systemctl status zabbix_agentd

# systemctl enable zabbix_agentd        //设置开机自启

7、编辑zabbix_agent配置文件

# egrep -v "^#|^$" /usr/local/zabbix-agent/etc/zabbix_agentd.conf
LogFile=/var/log/zabbix/zabbix_agentd.log
Server=10.103.1.191
ListenIP=10.103.1.170
ServerActive=10.103.1.191:10051
Hostname=Oracle-10-103-1-170

8、创建日志目录,并设置权限

# mkdir -p /var/log/zabbix

# chmod -R 755 /var/log/zabbix/
# chown -R zabbix. /var/log/zabbix/

# chmod -R 755 /usr/local/zabbix-agent/
# chown -R zabbix. /usr/local/zabbix-agent/

9、启动zabbix_agentd服务

# systemctl restart zabbix_agentd

10、查看zabbix_agentd服务是否启动成功

# netstat -nltp | grep zabbix
tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      65870/zabbix_agentd 
tcp        0      0 0.0.0.0:10051           0.0.0.0:*               LISTEN      53020/zabbix_server

到此,zabbix_agend端已安装完成!

Zabbix agent批量自动部署

废话:系统大批量上线时,我们一个个去装agent,有点枯燥,这里分享个expect结合上一篇《zabbix自动发现》,可以省不少工时。

准备工作:

1、下载客户端去吧https://www.zabbix.com/download_agents

2、跑脚本的主机192.168.2.100

1)下载的客户端放在了/opt下面
2)需要安装agent的(ip)和(passwd)信息,放在了ip_list.sh文件中

# vim /opt/ip_list.sh
192.168.2.1:123456
192.168.2.2:123456
192.168.2.3:123456
192.168.2.4:123456
192.168.2.5:123456

3)脚本agent_install.sh也放在了/opt下面

3、注意修改Zabbix Server IP、跑脚本的IP(我标红了)

环境信息:

  • 跑脚本的IP:192.168.2.100
  • Zabbix Server IP:192.168.2.201
  • agent安装路径:/usr/local/zabbix
  • agent日志:/tmp下面
  • 设置了开启启动
#!/bin/bash

# User:zgd
# https://www.zabbix.com/download_agents
# Install_URL:/usr/local/zabbix
# DATE:20180622
# Version:V2.3

rm -rf /root/.ssh/known_hosts
for i in {1..5}
do
 host=`sed -n "${i}p" /opt/ip_list.txt |awk -F ":" '{print $1}'`
 passwd=`sed -n "${i}p" /opt/ip_list.txt |awk -F ":" '{print $2}'`
  expect << EOF
  set timeout 300
  spawn ssh root@$host
  expect "yes/no" { send "yesr" }
  expect "password" { send "${passwd}r" }
  expect "#" { send "groupadd zabbixr" }
  expect "#" { send "useradd -g zabbix zabbix -s /sbin/nologinr" }
  expect "#" { send "mkdir /usr/local/zabbixr" }
  expect "#" { send "scp 192.168.2.100:/opt/zabbix_agents_3.2.0.linux2_6.amd64.tar.gz /usr/local/zabbixr" }
  expect "yes/no" { send "yesr" }
  expect "password" { send "123456r" }
  expect "#" { send  "cd /usr/local/zabbixr" }
  expect "#" { send "tar xf zabbix_agents_3.2.0.linux2_6.amd64.tar.gzr" }
  expect "#" { send "sed -i '91c Server=192.168.2.201' /usr/local/zabbix/conf/zabbix_agentd.confr" }
  expect "#" { send "sed -ri "/^Hostname/s/.*/Hostname=\${HOSTNAME%%.*}/" /usr/local/zabbix/conf/zabbix_agentd.confr" }
  expect "#" { send "/usr/local/zabbix/sbin/zabbix_agentd -c /usr/local/zabbix/conf/zabbix_agentd.confr" }
  expect "#" { send "chmod -R 755 /usr/local/zabbixr" }
  expect "#" { send "chown -R zabbix. /usr/local/zabbixr" }
  expect "#" { send "rm -rf /usr/local/zabbix/zabbix_agents_3.2.0.linux2_6.amd64.tar.gzr" }
  expect "#" { send "echo "/usr/local/zabbix/sbin/zabbix_agentd -c /usr/local/zabbix/conf/zabbix_agentd.conf" >> /etc/rc.localr" }
  expect "#" { send "exitr" }
EOF
done

配置多个ssh密钥对并且永久多ssh管理

这两天捣腾SSH,一直对其使用一知半解,由于要把博客迁移,弄来弄去发现还是部署到国内的coding吧
之前也弄过,但是由于重新安装了git-for-windows客户端,所以一开始用hexo d命令部署的时候报错了
趁着这次迁移也好好弄了一下本地的ssh管理,虽然还有些问题,但是至少比之前清晰一些了,这里也记录一下过程中遇到的问题

我的目的,将hexo生成的静态文件同时部署到github与coding上

安装git-for-windows客户端

下载地址 https://git-scm.com/download/win
无论是github还是coding都需要上传你的公钥,这两个地方可以上传相同的公钥,但也可以像我这样闲的蛋疼上传不同的公钥。

创建密钥对

使用ssh-keygen 来创建密钥对,命令为 ssh-keygen -t rsa -C “[email protected]”,其实这里-C 后面的email地址无所谓,可以随便写,只是为了你方便而已。
输入完该命令以后,首先会让你给密钥文件起个名字,这个是文件名,叫什么随心情

未分类

接下来让你输入密码,我这里直接回车,不用密码
然后它就会生成一个密钥对,像我这个设置就会生成yyxtest和yyxtest_pub两个文件,yyxtest.pub是公钥,谁都可以给,但是你私钥要自已保存好,谁拿到了你私钥就呵呵了。

上传公钥到github与coding中

根据github上的提示将公钥上传到github上你的个人账户中的ssh中

未分类

同样的操作再生成一对密钥,将公钥上传到coding中,注意我这里是为了测试,你完全没有必要重新生成,你当然可以上传刚才生成的yyxtest.pub这个公钥,当然后面会有一些问题,之后再详细说明。

上传文件到github上

赶紧上传个文件到github上试试吧(使用hexo d 来部署),其实你可以先不用上传文件,可以用ssh -vT [email protected] 来查看一下信息
这里你不用试了,肯定是不行的…… 抗都被我踩了

未分类

提示Permission denied,原因是你现在用的私钥还是id_rsa,并不是刚才生成的yyxtest,
ssh默认使用id_rsa,如果连id_rsa都没有,那你还不赶紧生成一个默认的。

添加yyxtest私钥到git bash中

根据github上的提示generate SSH keys 先将yyxtest添加到git bash中,
使用ssh-add ~/.ssh/yyxtest ,然后顺利提交代码成功,但是在提交文件到coding时又不行了,提示

Error: [email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

没办法,再用刚才的ssh-add 命令将用于coding的私钥也添加到git bash中,这次coding也可以提交了

配置ssh本地的config文件

试试关掉这个git bash,然后再试着用hexo d 提交一些文件,这次又不行了,还是提示Permission denied,这怎么能行,总不能每次提交更新都输入ssh-add 添加各种私钥吧,这时就要用到config这个文件了。
如果git安装是默认的话,将会把生成的公钥保存在C:Usersusername.ssh目录中(我用的是windows,不丢人),里面如果没有config文件,自已生成一个,里面写一些配置信息,各种字段说明如下

Host:代码托管平台的别名,但是这个别名和后面要用到的ssh链接 [email protected]:xxx/xxx.git 中的 @ 符号后面的内容要一致,而一般来说github默认提供的就是[email protected],因此为了方便,github的Host写github.com即可,别取别名了
HostName:代码托管平台真正的IP地址或域名,写域名就行,
IdentityFile:对应的密钥文件路径。必须写绝对路径,windows下可以写 C:Usersxxx.sshyyxtest
PreferredAuthentications:配置登录时用什么权限认证。可设为publickey,password publickey,keyboard-interactive等
User:对应的用户名。

我这里有两个私钥,所以我的配置文件如下

Host git.coding.net
    HostName git.coding.net
    IdentityFile C:Userskevin.sshrsa_coding
    PreferredAuthentications publickey
    User yangyanxing
Host github.com
    HostName github.com
    IdentityFile C:Userskevin.sshyyx
    PreferredAuthentications publickey
    User kevinkelin

之前说过,你没有必要为不同的网站生成不同的密钥,用同一份也可以,如果用同一份,这里IdentityFile也要写一样的
保存之后先不用着急提交,使用ssh -vT 查看一下连接是否有问题
github 提示 Hi kevinkelin! You’ve successfully authenticated, but GitHub does not provide shell access.
coding提示 yangyanxing,你好,你已经通过 SSH 协议认证 Coding.net 服务,这是一个个人公钥
这样就可以直接使用hexo d来提交文件更新了!

注意的问题

  • config文件中的host 配置是区分大小写的,github.com 和github.COM是不同的,一定要写对
  • coding的host是git.coding.net 而不是coding.net

遗留问题

git bash客户端,如果在非C盘上右键的方式启动,那么还是不行,它会寻找当前盘的中的.ssh目录,根本不存在的目录,所有找私钥肯定也找不到,只能先启动git bash,然后cd 到操作的目录中,这个我再研究研究怎么回事。

使用saltstack部署zabbix-agent

使用saltstack批量部署服务是工作中一种常见的内容,对于一个服务的部署可以分为:前期准备(系统资源的设定、参数调整、软件包的下载)、安装、配置、启动这几个步骤。
本文以zabbix客户端的设定为例,向大家展示如何用saltstack部署服务。

部署步骤

1.首先利用pillar定义配置文件中一些关键的数据,例如zabbix server的IP(如果有需求还可以设置开放端口、客户端名称)。在整个部署开始之前,我们需要了解pillar和file的相关目录信息,在master的配置文件中:

file_roots:
  base:
    - /srv/salt/prod
  dev:
    - /srv/salt/dev/services
    - /srv/salt/dev/states
  prod:
    - /srv/salt/prod/services
    - /srv/salt/prod/states
以及:
pillar_roots:
  base:
    - /srv/pillar

file_roots以及pillar_roots里的base、dev和prod会在后续的配置中经常使用,默认情况下我们在每个base地址下创建一个top.sls文件。

2.pillar文件的配置

pillar的根文件top.sls:

[root@server2 pillar]# cat top.sls 
base:
  '*':
    - zabbix

指定了任何minion都包含zabbix.sls的静态数据,在zabbix.sls文件中我们指定了zabbix_server的ip地址:

[root@server2 pillar]# cat zabbix.sls 
zabbix-agent:
  Zabbix_Server: 192.168.42.129
  port: 10050

查看下pillar中定义的Zabbix_Server和port的值:

[root@server2 pillar]#  salt '*' pillar.items
minion-192.168.42.130:
    ----------
    zabbix_agent:
        ----------
        Zabbix_Server:
            192.168.42.129
        port:
            10050
minion-192.168.42.128:
    ----------
    zabbix_agent:
        ----------
        Zabbix_Server:
            192.168.42.129
        port:
            10050

3.zabbix服务配置

此示例中使用源码进行安装,请提前准备好zabbix 源码包以及配置文件的模板。

[root@server2 files]# pwd
/srv/salt/prod/zabbix/files
[root@server2 files]# ls
zabbix-3.2.1.tar.gz  zabbix_agentd.conf

查看file_roots目录(/srv/salt/prod)中的内容:

[root@server2 prod]# ls
top.sls  zabbix

首先编写top.sls文件:

[root@server2 prod]# cat top.sls 

base:
  '*':
    - zabbix.zabbix_agent

这里的base指的是file_roots定义目录中的base:

file_roots:
  base:
    - /srv/salt/prod

在这个目录中有一个zabbix目录,该目录中有一个zabbix_agent.sls文件,主要的配置都在该文件中:

[root@server2 zabbix]# cat zabbix_agent.sls 
include:
  - zabbix.common_install

create_zabbix_user:
  user.present:
    - name: zabbix
    - shell: /sbin/nologin
  group.present:
    - name: zabbix

zabbix_tar:
  file.managed:
    - name: /tmp/zabbix-3.2.1.tar.gz
    - source: salt://zabbix/files/zabbix-3.2.1.tar.gz
    - user: zabbix
    - group: zabbix
    - mode: 0644

/opt/app:
  file.directory:
    - user: zabbix
    - group: zabbix

zabbix_decompression:
  cmd.run:
    - name: tar xvf /tmp/zabbix-3.2.1.tar.gz -C /opt/app 
    - unless: test -d /opt/app/zabbix-3.2.1
    - require:
      - file: /tmp/zabbix-3.2.1.tar.gz

zabbix_install:
  cmd.run:
    - name: cd /opt/app/zabbix-3.2.1 && ./configure --enable-agent && make && make install
    - require:
      - cmd: zabbix_decompression

/usr/local/etc/zabbix_agented.conf:
  file.managed:
    - name: /usr/local/etc/zabbix_agentd.conf
    - source: salt://zabbix/files/zabbix_agentd.conf
    - user: zabbix
    - group: zabbix
    - mode: 0644
    - template: jinja
    - defaults:
      Server: {{pillar['zabbix_agent']['Zabbix_Server']}}
    - require:
      - cmd: zabbix_install
run_zabbix:
  cmd.run:
    - name: /usr/local/sbin/zabbix_agentd -c /usr/local/etc/zabbix_agentd.conf
    - require:
      - cmd: zabbix_install
    - watch:
      - file: /usr/local/etc/zabbix_agentd.conf

在该文件的开始有一个include操作,安装zabbix之前系统可能需要先安装相关软件包和编译工具,所以把这个操作放在单独的zabbix.common_install文件中,该文件也在/srv/salt/prod/zabbix目录。内容如下:

[root@server2 zabbix]# cat common_install.sls 
pkg-init:
  pkg.installed:
    - names:
      - gcc
      - gcc-c++
      - glibc
      - make
      - autoconf
      - openssl
      - openssl-devel

接下来的过程包括:
(1)zabbix用户和组的创建;
(2)zabbix源码包的拷贝;
(3)源码包的解压缩和配置安装;
(4)zabbix客户端配置文件(zabbix_agentd.conf)的部署;
(5)zabbix服务的开启;

4.执行过程:

-------------

[root@server2 zabbix]# salt '*' state.highstate

Succeeded: 15 (changed=3)
Failed:     0
-------------
Total states run:     15
Total run time:   26.597 s

python的加、减、乘、除、取整、取余计算

注意:所用版本是Python3.5.2。(因为Python2系列和Python3系列差距很大,特别提醒)

加法:

输入以下代码:

>>>1+1
>>>1.0+1

减法:

输入以下代码:

>>>1-2
>>>1.0-2

乘法:

输入以下代码:

>>>2*4
>>>2.0*4

除法:

输入以下代码:

>>>2/4
>>>2.0/4
>>>2//4
>>>2.0//4

取整:

输入以下代码:

>>>2//4
>>>2.0//4
>>>2.01//4

取余:

输入以下代码:

>>>10%2
>>>10%2.0

现象:

未分类

NGINX 如何实现读写限流的方法

这篇文章主要介绍了nginx 如何实现读写限流的方法的相关资料,这里提供实例代码及如何配置,需要的朋友可以参考下.

nginx 读写限流,万能的nginx,几行配置搞定。

先定义好规则,需要写在server外面

limit_req_zone $binary_remote_addr $uri zone=api_write:20m rate=10r/s; # 写
limit_req_zone $binary_remote_addr $uri zone=api_read:20m rate=50r/s; # 读

把需要限速的接口应用上上面的规则

写10/秒

location = /api/v1/trade {
limit_req zone=api_write burst=10;
proxy_pass http://api_server;
}

查询50/秒

location /api/v1/query {
limit_req zone=api_read burst=50;
proxy_pass http://api_server;
}

Nginx请求限制

连接频率限制:limit_conn_module
请求频率限制:limit_req_module

HTTP协议的连接与请求:

未分类

HTTP请求建立在一次TCP连接基础上

一次TCP请求至少产生一次HTTP请求,也可以产生多次。

1. 连接限制

Syntax: limit_conn_zone key zone=name:size;
Default: ——
Context: http
  • limit_conn_zone :开辟一块空间
  • key:以什么作为key存储,比如可以用ip作为限制,则ip为key
  • zone=name:size:name为申请空间的名字,方便后面其他调用,size表示大小
Syntax: limit_conn zone number;
Default: ——
Context: http,server,location
  • zone:表示空间名字
  • number:表示同一时间运行的并发个数

2. 请求限制

Syntax: limit_req_zone key zone=name:size rate=rate;
Default: ——
Context:http

前面部分的语法和前面类似,rate表示的是请求的速率。

Syntax: limit_req zone=name [burst=number][nodelay];
Default:——
Context:http,server,location

3. 测试

测试一:

# 设置空间名为req_zone 大小为1m,速率为每秒1个,地址的二进制的客户端地址用于节省空间
limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;
    location / {
        root /opt/app/code;
        limit_req zone=req_zone; 
        index  index.html index.htm;
    }

未分类

测试二:

# 设置空间名为req_zone 大小为1m,速率为每秒1个,地址的二进制的客户端地址用于节省空间
limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;
    location / {
        root /opt/app/code;
        limit_req zone=req_zone burst=3 nodelay; 
        index  index.html index.htm;
    }

burst为3表示有三个延迟响应,起到缓冲作用,其他直接返回。

未分类

测试三:

    limit_conn_zone $binary_remote_addr zone=conn_zone:1m;
    location / {
        root /opt/app/code;
        limit_conn conn_zone 1;
        index  index.html index.htm;
    }

未分类

nginx配置https的部署实践

http以明文的形式在浏览器和服务器之间交换数据,没有任何数据加密,攻击者可以在截取之间的信息并读懂,这明显不安全,所以现在浏览器浏览器都要求网站域名配置SSL域名证书,以https协议传输内容。

那问题来了:

未分类

HTTP与HTTPS

  • HTTP:超文本传输协议
  • HTTPS:超文本传输安全协议

简单来说,可以用这个公式:HTTPS = HTTP + SSL

  • SSL:安全套接层,一种安全协议

也就是说:

为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

未分类


未分类

申请ssl域名证书

登录腾讯云之后,找到SSL证书管理栏目,购买或者申请域名证书。

注意:

  • 免费证书有效期是一年,一年后手动重新申请即可
  • 域名需要备案

未分类

申请完了之后,就可以下载证书啦~

未分类

如图下载的域名证书,可以配置到Apache、Nginx、Tomcat等服务器上面。

未分类

nginx配置https步骤

好,接下来我们进入正题,给nginx配置域名证书嘿~

解压下载下来的域名证书,获取Nginx里面的两个文件。

未分类

  • crt文件是以PEM格式存在的证书,可以用于不同的程序和设备
  • key文件是授权文件

第一步

把crt和key文件上传到nginx的conf目录下。

未分类

第二步

nginx.conf或自定义配置文件上配置SSL证书。

未分类

HTTPS的默认端口是443,就像HTTP的默认端口80一样,从图中可以看到,这个服务最后代理的是8080端口的tomcat。

第三步

配置完了第二步已经完成一大半了,只要用户输入https://www.java-mindmap.com就可以访问我的社区网站,但是一般用户都懒得输入https://,而不输入的话默认就是发起http链接,所以,需要还需要配置http强制转换成https的链接。

未分类

这样,当用户访问http链接时候,强制转成了https的服务了。

未分类

至此,HTTPS配置成功~

未分类

部署 Django 项目背后的原理:为什么需要 Nginx 和 Gunicron这些东西?

相信用过 Django 的同学一定会被 “Very easy to setup” 惊艳到。只要一行命令,就可以在 admin 界面看到一个完整的登陆注册。但是到了部署的时候,你一定会被网上复杂的部署教程搞的头晕,为啥本地开发这么简单,到了服务器却需要又是 Nginx,又是 uWSGI 这种东西呢?

未分类
摘自The Full Stack Python Guide to Deployments 一书

本文试图解释这些程序在一个 Web 服务中扮演的角色,为什么部署 Python web程序需要它们。本文不介绍如何部署 Django 应用等,这一类教程网上有很多,读者可自行搜索。其中 Nginx 和 Apache 算是一类的,可以替换。Gunicorn 和 uWSGI 的角色是类似的。同理最后端的 Web 框架是一类的,比如 Django 和 Flask。本文的内容替换以上任意一个应该也适用。

如果你读了网上任意一篇教程,你应该知道一个完整的部署应该类似这样:

HTTP Server <-----> WSGI <-----> App

最后后面的 App 我们知道,只要 runserver 就可以访问了,但是 Django 的文档明确说明:

DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through security audits or performance tests. (And that’s how it’s gonna stay. We’re in the business of making Web frameworks, not Web servers, so improving this server to be able to handle a production environment is outside the scope of Django.)

即 Django 做的事情只是一个框架,不会去关心一些安全问题、HTTP 的性能问题等。所以我们需要一个专业的 HTTP 服务器。这就出现了 Nginx 或 Apache。那么如何将 HTTP 服务器和我们的应用连接起来呢?动态网站问世的时候,就出现了 CGI 协议。注意这是一个协议,定义了HTTP 服务器如何通过后端的应用获取动态内容。可以简单的理解成 HTTP 服务器通过CGI 协议调用后端应用吧!WSGI 可以理解成 Python 的 CGI。uWSGI 和 Gunicorn 是这种 WSGI 的一些实现。这样,就出现了上面提到的三层的部署。

但是,为什么我们还需要 Nginx 呢?这些 WSGI 程序本身不是也提供访问吗?

uWSGI 和 Gunicorn 本身就是一个便携的 web 服务器了,Nginx 作为一个经过更长时间验证的 HTTP 服务器来说,它有很多 uWSGI 没有支持的 feature。比如:

  1. 处理静态资源更加优秀,E-Tag 的设置,Gzip 压缩等
  2. 处理网络连接,降低网络负载。例如 reuqest_buffering ,加入部署一个 uWSGI 程序,如果有慢的请求存在,uWSGI 必须等待整个 HTTP 请求发过来之后才开始处理请求。但是如果前置 Nginx,那么 Nginx 会帮你收到整个 HTTP 请求之后才交给 uWSGI 处理,也就是说,uWSGI获得的永远会是完整的 HTTP 请求,不会占用一个线程在等待。
  3. 甚至缓存动态的内容,例如将博客的首页缓存 5 分钟
  4. 作为一个负载均衡的前置,这样每一层的实例数量可以横向扩展
  5. Nginx 本身是作为一个服务存在的,几乎在任何 Linux 版本上安装之后都可以用 initd 启动,就像 MySQL 那样。uWSGI 一般是需要自己将其配置成服务的。(虽然前置了 Nginx 依然是需要配置 uWSGI)
  6. ……

此外,这样分开的好处还是得,到达 uWSGI 和 Gunicorn 的请求的情况变得简单了很多,Nginx 处理了一层,将过滤和处理之后的请求交给 uWSGI 或 Gunicorn。这使得这些 WSGI 程序的实现简单了一些,简化了开发的工作。专业的事情交给专业的人去做。

当然,并不是所有的项目都需要这么复杂的部署,有一个可选的是将 WSGI 程序嫁接到 HTTP 服务器上,比如 Apache httpd + mod_wsgi, Nginx + mod_uwsgi 等。