使用ansible结合keepalived高可用,nginx反向代理部署小型企业环境

前言:

ansible作为一款灵活、高效、功能丰富的自动化部署工具在企业运维管理中备受推崇。本文演示使用ansible部署小型企业服务框架,实现高可用、负载均衡的目标。如有错误敬请赐教。
目标环境拓扑:
未分类

环境介绍:

前端代理层由两台nginx实现,并安装keepalived实现地址滑动达成高可用。
web层由两套Apache+PHP+WordPress 构建应用环境。数据层由一台mariadb组成,篇幅限制这里并没有做数据库主从复制、读写分离(实际环境数据库一定要实现这两项功能)。

IP一览:

未分类

环境准备:

1.管理端安装ansible,配置ssh秘钥使主机间实现基于秘钥的认证

ssh-keygen  -t rsa  #三次回车,中途的问题是问秘钥存放位置(默认/root/.ssh),是否加密秘钥。实验方便这里不加密
ssh-copy-id -i .ssh/id_rsa.pub [email protected] #将公钥发送给目标主机
ssh-copy-id -i .ssh/id_rsa.pub [email protected]
ssh-copy-id -i .ssh/id_rsa.pub [email protected]
ssh-copy-id -i .ssh/id_rsa.pub [email protected]
ssh-copy-id -i .ssh/id_rsa.pub [email protected]

2.编辑ansible的hosts文件,定义所有的主机
vim /etc/ansible/hosts
未分类
3.为所有主机同步时间

 ansible all -a 'ntpdate 172.18.0.1' #我这里是同步自己局域网的ntp服务器,实验的话选取同一台主机保证时间相同即可

4.创建ansible相关角色的目录

mkdir -pv /etc/ansible/roles/{mysql,web,nginx}/{files,tasks,templates,vars,handlers,meta}

配置web的playbook:

1.创建tasks文件

vim /etc/ansible/roles/web/task/main.yml
- name: install web pakgs
  yum: name={{ item }}
  with_items:
  - httpd
  - php
  - php-mysql
- name: config  web
  copy: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
  notify: restart the service # 注意这里要与handlers里定义的name相同
- name: copy wordpress
  synchronize: src=wordpress dest=/var/www/html/wordpress/
- name: restart the service
  service: name=httpd state=started

2.创建handles

vim /etc/ansible/roles/web/handlers/main.yml
- name: restart the service  #就这
  service: name=httpd state=restarted

3.添加要复制过去的配置文件
放在/etc/ansible/roles/web/files/下 ① WordPress目录 ② httpd.conf #从别的地方考过来
4.修改WordPress连接数据库的配置文件

 cd wordpress
 cp wp-sample-config.php  wp-config.php
 vim wp-config.php

未分类
5.添加web主剧本

vim /etc/ansible/web.yml
- hosts: web
  remote_user: root
  roles:
  - web

6.测试,没问题的话就下一步

ansible-playbook -C /etc/ansible/web.yml

配置代理层:

1.添加task任务

vim /etc/ansible/roles/nginx/tasks/main.yml
- name: install package
  yum: name={{ item }}
  with_items:
  - nginx
  - keepalived
- name: config keepalived
  template: src=keepalived.conf.j2 dest=/etc/keepalived/keepalived.conf
  notify: restart keepalived
- name: config nginx
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  notify: restart nginx
- name: start service
  service: name={{ item }} state=started enabled=true
  with_items:
  - keepalived
  - nginx

2.添加handlers

vim /etc/ansible/roles/nginx/handlers
- name: restart keepalived
  service: name=keepalived state=restarted
- name: restart nginx
  service: name=nginx state=restarted

3.准备template文件 ①keepalived.conf.j2 ②nginx.conf.j2
4.修改keepalived模板文件

global_defs {
   notification_email {
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id {{ansible_hostname}} #自带变量,通过ansible 主机IP -m setup 查询
   vrrp_mcast_group4 224.0.0.43
}

vrrp_instance VI_1 {
    state {{ state }} #已通过hosts文件定义变量
    interface ens33 #网卡名
    virtual_router_id 51
    priority {{ priority }}
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass lovelinux #设置密码
    }
    virtual_ipaddress {
        172.18.43.88 #虚拟IP
    }
}

5.修改nginx模板文件(定义在http段)

upstream web {                        #新增段
        server 172.18.43.61;
        server 172.18.43.62;
    }
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

    location / {                     #新增段
        proxy_pass    
        }
    }

6.添加nginx主剧本

vim /etc/ansible/nginx.yml
- hosts: nginx
  remote_user: root
  roles:
  - nginx

7.测试,没问题的话就下一步

ansible-playbook -C /etc/ansible/nginx.yml

配置mariadb:

1.配置mariadb的任务清单

roles/mysql/tasks/main.yml
- name: install mariadb
  yum: name=mariadb-server
- name: copy sql file
  copy: src=mysql.sql dest=/tmp/mysql.sql
- name: start mysql service
  service: name=mariadb state=started
- name: config mysql
  shell: "mysql < /tmp/mysql.sql"

2.设置files文件

vim roles/mysql/files/mysql.sql 
CREATE DATABASE wp;
GRANT ALL ON wp.* TO 'wpuser'@'%' IDENTIFIED BY 'lovelinux';

3.添加mysql主剧本

vim /etc/ansible/mysql.yml
- hosts: mysql
  remote_user: root
  roles:
  - mysql

4.测试,没问题的话就下一步

ansible-playbook -C /etc/ansible/mysql.yml

开始表演(执行剧本):

1.目录结构
未分类
2.分别执行

ansible-playbook  web.yml
ansible-playbook  nginx.yml
ansible-playbook  mysql.yml

3.访问页面http://172.18.43.88/wordpress
未分类

项目总结:

1.在定义web的playbook时复制wordpress时开始用的是copy模块执行总是不成功,报错ERROR! A worker was found in a dead state。在确认自己没有语法错误后,百度查找原因无果最后在Google上找到了答案(英文不好不要心虚,技术问题语法都很简单很容易看懂,个别单词查查有道词典就好了),所以有在IT技术的问题问Google准没错。用synchronize模块要比copy模块高效安全的多,synchronize采用rsync复制文件,所以系统必须安装rsync 包否则无法使用这个模块。使用该模块的优点有①增量复制(只复制与目标主机有差异的文件) ② 复制时采用压缩,对复制大文件支持优秀(用copy复制大文件会出错),以下整理了一些synchronize参数:
archive # 是否采用归档模式同步,即以源文件相同属性同步到目标地址
copy_links # 同步的时候是否复制连接
links # Copy symlinks as symlinks
delete # 删除源中没有而目标存在的文件(即以推送方为主)
dest= # 目标地址
dest_port # 目标接受的端口,ansible配置文件中的 ansible_ssh_port 变量优先级高于该 dest_port 变量
dirs # 以非递归的方式传输目录
2.如mysql主机曾经安装过mariadb可能会出现导入SQL命令失败的情况,这时要将mysql的数据库删掉,默认位置在/var/lib/mysql/下
3.编辑nginx代理时注意语句的位置不要写错
4.出现错误仔细看看错误日志,耐心点问题肯没想的那么难。

CentOS 7 下安装 Nginx

安装所需环境

Nginx 是 C语言 开发,建议在 Linux 上运行,当然,也可以安装 Windows 版本。

一. gcc 安装

安装 nginx 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,则需要安装:

yum install gcc-c++

二. PCRE pcre-devel 安装

PCRE(Perl Compatible Regular Expressions) 是一个Perl库,包括 perl 兼容的正则表达式库。nginx 的 http 模块使用 pcre 来解析正则表达式,所以需要在 linux 上安装 pcre 库,pcre-devel 是使用 pcre 开发的一个二次开发库。nginx也需要此库。命令:

yum install -y pcre pcre-devel

三. zlib 安装

zlib 库提供了很多种压缩和解压缩的方式, nginx 使用 zlib 对 http 包的内容进行 gzip ,所以需要在 Centos 上安装 zlib 库。

yum install -y zlib zlib-devel

四. OpenSSL 安装

OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及 SSL 协议,并提供丰富的应用程序供测试或其它目的使用。
nginx 不仅支持 http 协议,还支持 https(即在ssl协议上传输http),所以需要在 Centos 安装 OpenSSL 库。

yum install -y openssl openssl-devel

官网下载

下载.tar.gz安装包,地址:https://nginx.org/en/download.html

解压

依然是直接命令:

tar -zxvf nginx-1.10.1.tar.gz
cd nginx-1.10.1

配置

其实在 nginx-1.10.1 版本中你就不需要去配置相关东西,默认就可以了。当然,如果你要自己配置目录也是可以的。
1.使用默认配置

./configure

2.自定义配置(不推荐)

./configure 
--prefix=/usr/local/nginx 
--conf-path=/usr/local/nginx/conf/nginx.conf 
--pid-path=/usr/local/nginx/conf/nginx.pid 
--lock-path=/var/lock/nginx.lock 
--error-log-path=/var/log/nginx/error.log 
--http-log-path=/var/log/nginx/access.log 
--with-http_gzip_static_module 
--http-client-body-temp-path=/var/temp/nginx/client 
--http-proxy-temp-path=/var/temp/nginx/proxy 
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi 
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi 
--http-scgi-temp-path=/var/temp/nginx/scgi

注:将临时文件目录指定为/var/temp/nginx,需要在/var下创建temp及nginx目录

编译安装

make
make install

查找安装路径:

whereis nginx

未分类

启动、停止nginx

cd /usr/local/nginx/sbin/
./nginx 
./nginx -s stop
./nginx -s quit
./nginx -s reload

./nginx -s quit:此方式停止步骤是待nginx进程处理任务完毕进行停止。
./nginx -s stop:此方式相当于先查出nginx进程id再使用kill命令强制杀掉进程。

查询nginx进程:

ps aux|grep nginx

重启 nginx

1.先停止再启动(推荐):
对 nginx 进行重启相当于先停止再启动,即先执行停止命令再执行启动命令。如下:

./nginx -s quit
./nginx

2.重新加载配置文件:
当 ngin x的配置文件 nginx.conf 修改后,要想让配置生效需要重启 nginx,使用-s reload不用先停止 ngin x再启动 nginx 即可将配置信息在 nginx 中生效,如下:

./nginx -s reload

启动成功后,在浏览器可以看到这样的页面:
未分类

开机自启动

即在rc.local增加启动代码就可以了。

vi /etc/rc.local

增加一行 /usr/local/nginx/sbin/nginx
设置执行权限:

chmod 755 rc.local

未分类
到这里,nginx就安装完毕了,启动、停止、重启操作也都完成了,当然,你也可以添加为系统服务,我这里就不在演示了。

Gitlab使用非绑定的Nginx

1、编辑gitlab.rb

vi /etc/gitlab/gitlab.rb

配置如下:

nginx['enable'] = false
#nginx的用户
web_server['external_users'] = ['nginx']
#nginx服务器的地址
gitlab_rails['trusted_proxies'] = [ '192.168.1.0/24', '192.168.2.1', '2001:0db8::/32' ]

2、配置Nginx

vi /etc/nginx/conf.d/gitlab-omnibus-nginx.conf

添加以下内容:

## GitLab 8.3+
##
## Lines starting with two hashes (##) are comments with information.
## Lines starting with one hash (#) are configuration parameters that can be uncommented.
##
##################################
## CONTRIBUTING ##
##################################
##
## If you change this file in a Merge Request, please also create
## a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
##
###################################
## configuration ##
###################################
##
## See installation.md#using-https for additional HTTPS configuration details.

upstream gitlab-workhorse {
server unix:/var/opt/gitlab/gitlab-workhorse/socket;
}

## Normal HTTP host
server {
## Either remove "default_server" from the listen line below,
## or delete the /etc/nginx/sites-enabled/default file. This will cause gitlab
## to be served if you visit any address that your server responds to, eg.
## the ip address of the server (http://x.x.x.x/)n 0.0.0.0:80 default_server;
listen 0.0.0.0:80 default_server;
listen [::]:80 default_server;
server_name git.dream7788.com; ## Replace this with something like gitlab.example.com
server_tokens off; ## Don't show the nginx version number, a security best practice
root /opt/gitlab/embedded/service/gitlab-rails/public;

## See app/controllers/application_controller.rb for headers set

## Individual nginx logs for this GitLab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;

location / {
client_max_body_size 0;
gzip off;

## https://github.com/gitlabhq/gitlabhq/issues/694
## Some requests take more than 30 seconds.
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;

proxy_http_version 1.1;

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

proxy_pass http://gitlab-workhorse;
}
}

添加nginx用户到git用户组

usermod -a -G git nginx

3、重新配置gitlab

gitlab-ctl reconfigure
gitlab-ctl start

Zabbix监控nginx进程

本文将介绍:

  • Nginx开启状态模板
  • 创建Nginx检测脚本
  • 图形化导入Nginx模块

此操作均在Zabbix3.2.6

Nginx开启状态模板(agent端)

yum install nginx -y

vi /etc/nginx/conf.d/default.conf

    location /nginx_status{
        stub_status on;
        access_log on;
    allow 127.0.0.1;
        allow 192.168.31.0/24;   只允许192.168.31.0这个网段访问
        deny all;
}
## deny all , 拒绝除 allow 中的主机之外所有主机访问此 URL ,实现过程中如果遇到 403 ,有可能是你把自己测试的机器拒绝了!


nginx -t 检查语法
nginx -s reload 重新加载配置文件  

查看nginx 状态信息:

[root@localhost ~]#  curl http://127.0.0.1/nginx_status
Active connections: 1 
server accepts handled requests
 3721 3721 3714 
Reading: 0 Writing: 1 Waiting: 0

注解:
Active connections: 1 当前活动的连接数

server accepts handled requests

3721 3721 3714

3721 从启动到现在一共处理的连接数

3721 从启动到现在成功创建的握手的次数

3714 总共处理的请求数(requests)
请求的丢失数=(握手-连接)
connection 连接数,tcp连接 
request http请求,GET/POST/DELETE

Reading: 0 Writing: 1 Waiting: 0 
Reading: 0 读取客户端Header的信息数 请求头
Writing: 1 返回给客户端的header的信息数 响应头 
Waiting: 0 等待的请求数

创建Nginx检测脚本

mkdir /usr/local/zabbix/scripts -p
vi /usr/local/zabbix/scripts/nginx_status.sh 

#!/bin/bash 
#Time:2017-11-19
#Author: bks.com

#HOST=`/sbin/ifconfig eth0 | sed -n '/inet /{s/.*addr://;s/ .*//;p}'` 
HOST="127.0.0.1" 
PORT="80" 

# Functions to return nginx stats 
# 检测nginx进程是否存在
function ping {
    /sbin/pidof nginx | wc -l
}
function active { 
/usr/bin/curl "http://$HOST:$PORT/nginx_status" 2>/dev/null| grep 'Active' | awk '{print $NF}' 
} 
function reading { 
/usr/bin/curl "http://$HOST:$PORT/nginx_status" 2>/dev/null| grep 'Reading' | awk '{print $2}' 
} 
function writing { 
/usr/bin/curl "http://$HOST:$PORT/nginx_status" 2>/dev/null| grep 'Writing' | awk '{print $4}' 
} 
function waiting { 
/usr/bin/curl "http://$HOST:$PORT/nginx_status" 2>/dev/null| grep 'Waiting' | awk '{print $6}' 
} 
function accepts { 
/usr/bin/curl "http://$HOST:$PORT/nginx_status" 2>/dev/null| awk NR==3 | awk '{print $1}' 
} 
function handled { 
/usr/bin/curl "http://$HOST:$PORT/nginx_status" 2>/dev/null| awk NR==3 | awk '{print $2}' 
} 
function requests { 
/usr/bin/curl "http://$HOST:$PORT/nginx_status" 2>/dev/null| awk NR==3 | awk '{print $3}' 
} 
# Run the requested function 
$1

# 对脚本赋予执行权限

chmod +x /usr/local/zabbix/scripts/nginx_status.sh 


编辑agent配置文件,定义Key

vim /etc/zabbix/zabbix_agentd.conf

UserParameter=nginx.status[*],/usr/local/zabbix/scripts/nginx_status.sh $1

# $1表示[*]这里面的参数,在此为"active",如果命令有$存在,那么在$前面在加上一个$


配置完后一定记得重启:
/etc/init.d/zabbix-agent restart

图形化导入Nginx模块

server端测试:

[root@CentOS7 ~]# zabbix_get -s 192.168.31.155 -p 10050 -k "nginx.status[active]"
1
#有数字信息返回则表示配置正常


图形化操作:

    配置-->模板-->导入   
模板下载:
zbx_export_templates.xml
http://pan.baidu.com/s/1pLFUJc3 密码:1234


为对应的主机导入nginx模板
    配置-->主机-->模板-->添加

Nginx 504报错,PHP-FPM无响应的问题

问题

测试环境,压测接口中间件时遇到报错Nginx 504,查询nginx日志

2017/11/21 15:20:15 [error] 26954#0: *1835 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.46, server: 192.168.23.95, request: "POST /screenInterface/FunctionByTime.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "192.168.23.95:6010", referrer: "http://192.168.23.95:6010/screen2/"
2017/11/21 15:20:15 [error] 26954#0: *1821 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.46, server: 192.168.23.95, request: "POST /screenInterface/FUnctionByMobile.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "192.168.23.95:6010", referrer: "http://192.168.23.95:6010/screen2/"
2017/11/21 15:20:15 [error] 26954#0: *1836 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.46, server: 192.168.23.95, request: "POST /screenInterface/LeftGraph.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "192.168.23.95:6010", referrer: "http://192.168.23.95:6010/screen2/"

资料

分析与解决

初步推测为php-fpm无响应:

  • 能够成功访问nginx静态资源
  • 本地9000端口成功访问php资源php ./info.php
  • nginx error code 504

查询PHP-fpm的error日志发现报错:

[21-Nov-2017 12:28:30] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[21-Nov-2017 12:33:29] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[21-Nov-2017 14:10:57] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[21-Nov-2017 14:31:05] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[21-Nov-2017 14:57:54] ERROR: unable to bind listening socket for address '127.0.0.1:9000': Address already in use (98)
[21-Nov-2017 14:57:54] ERROR: FPM initialization failed
[21-Nov-2017 14:58:32] NOTICE: fpm is running, pid 26714
[21-Nov-2017 14:58:32] NOTICE: ready to handle connections
[21-Nov-2017 14:59:50] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[21-Nov-2017 15:20:12] NOTICE: Terminating ...
[21-Nov-2017 15:20:12] NOTICE: exiting, bye-bye!
[21-Nov-2017 15:20:25] NOTICE: fpm is running, pid 26972
[21-Nov-2017 15:20:25] NOTICE: ready to handle connections
[21-Nov-2017 15:20:44] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

推测原因为pm.max_children设置过小,将增大该值后重启中间件,问题解决。

反思

Nginx 502 & Nginx 504

  • Nginx 502 Bad Gateway的含义是请求的PHP-CGI已经执行,但是由于某种原因(一般是读取资源的问题)没有执行完毕而导致PHP-CGI进程终止。
  • Nginx 504 Gateway Time-out的含义是所请求的网关没有请求到,简单来说就是没有请求到可以执行的PHP-CGI。

关于pm.max_children

一个前提设置: pm = static/dynamic,这个选项是标识fpm子进程的产生模式:

  • static :表示在fpm运行时直接fork出pm.max_chindren个worker进程,
  • dynamic:表示,运行时fork出start_servers个进程,随着负载的情况,动态的调整,最多不超过max_children个进程。

一般推荐用static,优点是不用动态的判断负载情况,提升性能,缺点是多占用些系统内存资源。

max_chindren代表的worker的进程数。对于配置越多能同时处理的并发也就越多,则是一个比较大的误区:

  • 管理进程和worker进程是通过pipe进行数据通讯的。所以进程多了,增加进程管理的开销,系统进程切换的开销,更核心的是,能并发执行的fpm进程不会超过cpu个数。因此通过多开worker的个数来提升qps是错误的。
  • 但worker进程开少了,如果server比较繁忙的话,会导到nginx把数据打到fpm的时候,发现所有的woker都在工作中,没有空闲的worker来接受请求,从而导致502。

如何配置max_children及优化PHP-FPM

php-fpm.conf有两个至关重要的参数:一个是”max_children”,另一个是”request_terminate_timeout”.

  • request_terminate_timeout的值可以根 据你服务器的性能进行设定。一般来说性能越好你可以设置越高,20分钟-30分钟都可以。由于服务器PHP脚本需要长时间运行,有的可能会超过10分钟因此我设置了900秒,这样不会导致PHP-CGI死掉而出现502 Bad gateway这个错误。
  • max_children的值原则上是越大越好,php-cgi的进程多了就会处理的很快,排队的请求就会很少。设置”max_children” 也需要根据服务器的性能进行设定,一般来说一台服务器正常情况下每一个php-cgi所耗费的内存在20M左右,因此”max_children”我设置成40个,20M*40=800M也就是说在峰值的时候所有PHP-CGI所耗内存在800M以内,低于我的有效内存1Gb。而如果我 的”max_children”设置的较小,比如5-10个,那么php-cgi就会“很累”,处理速度也很慢,等待的时间也较长。如果长时间没有得到处 理的请求就会出现504 Gateway Time-out这个错误,而正在处理的很累的那几个php-cgi如果遇到了问题就会出现502 Bad gateway这个错误。
  • max_requests:每个进程若超过这个数目(跟php进程有一点点关系,关系不大),就自动杀死。

Linux 配置 nginx、mysql、php-fpm、redis 开机启动

Linux(CentOS)上配置 nginx、mysql、php-fpm、redis 开机启动,编写开机启动脚本。

系统环境: CentOS Linux

I、nginx开机启动

1. 在/etc/init.d/目录下创建脚本

vim  /etc/init.d/nginx

2. 更改脚本权限

chmod 775 /etc/init.d/nginx

3. 编写脚本内容

#!/bin/bash
# nginx Startup script for the Nginx HTTP Server
# it is v.0.0.2 version.
# chkconfig: - 85 15
# description: Nginx is a high-performance web and proxy server.
#              It has a lot of features, but it's not for everyone.
# processname: nginx
# pidfile: /var/run/nginx.pid
# config: /usr/local/nginx/conf/nginx.conf
nginxd=/usr/local/webserver/nginx/sbin/nginx
nginx_config=/usr/local/webserver/nginx/conf/nginx.conf
nginx_pid=/usr/local/webserver/nginx/logs/nginx.pid
RETVAL=0
prog="nginx"
# Source function library.
.  /etc/rc.d/init.d/functions
# Source networking configuration.
.  /etc/sysconfig/network
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
[ -x $nginxd ] || exit 0
# Start nginx daemons functions.
start() {
if [ -e $nginx_pid ];then
   echo "nginx already running...."
   exit 1
fi
   echo -n $"Starting $prog: "
   daemon $nginxd -c ${nginx_config}
   RETVAL=$?
   echo
   [ $RETVAL = 0 ] && touch /var/lock/subsys/nginx
   return $RETVAL
}
# Stop nginx daemons functions.
stop() {
        echo -n $"Stopping $prog: "
        killproc $nginxd
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && rm -f /var/lock/subsys/nginx /usr/local/webserver/nginx/logs/nginx.pid
}

reload() {
    echo -n $"Reloading $prog: "
    #kill -HUP `cat ${nginx_pid}`
    killproc $nginxd -HUP
    RETVAL=$?
    echo
}
# See how we were called.
case "$1" in
start)
        start
        ;;
stop)
        stop
        ;;
reload)
        reload
        ;;
restart)
        stop
        start
        ;;
status)
        status $prog
        RETVAL=$?
        ;;
*)
        echo $"Usage: $prog {start|stop|restart|reload|status|help}"
        exit 1
esac
exit $RETVAL

4. 设置开机启动

chkconfig nginxd on

II、设置mysql开机启动

将mysql安装目录下 support-files目录下的mysql.server文件拷贝到/etc/init.d/目录下并改名为mysqld,并更改权限

chmod 775 /etc/init.d/mysqld

设置开机启动

chkconfig mysqld on

III、php-fpm开机启动

1. 在/etc/init.d/目录下创建脚本

vim /etc/init.d/php-fpm

2. 更改脚本权限

chmod 775 /etc/init.d/php-fpm

3. 编写脚本内容

#!/bin/sh
#
# php-fpm - this script starts and stops the php-fpm daemin
#
# chkconfig: - 85 15
# processname: php-fpm
# config:      /usr/local/php/etc/php-fpm.conf

set -e

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="php-fpm daemon"
NAME=php-fpm
DAEMON=/usr/local/php/sbin/$NAME     //这里设成自己的目录
CONFIGFILE=/usr/local/php/etc/php-fpm.conf   //这里设成自己的目录
PIDFILE=/usr/local/php/var/run/$NAME.pid   //这里设成自己的目录
SCRIPTNAME=/etc/init.d/$NAME   //这里设成自己的目录

# If the daemon file is not found, terminate the script.
test -x $DAEMON || exit 0

d_start(){
    $DAEMON -y $CONFIGFILE || echo -n " already running"
}

d_stop(){
    kill -QUIT `cat $PIDFILE` || echo -n " no running"
}

d_reload(){
    kill -HUP `cat $PIDFILE` || echo -n " could not reload"
}

case "$1" in
    start)
        echo -n "Starting $DESC: $NAME"
        d_start
        echo "."
        ;;
    stop)
        echo -n "Stopping $DESC: $NAME"
        d_stop
        echo "."
        ;;
    reload)
        echo -n "Reloading $DESC configuration..."
        d_reload
        echo "Reloaded."
        ;;
    restart)
        echo -n "Restarting $DESC: $NAME"
        d_stop
        # Sleep for two seconds before starting again, this should give the nginx daemon some time to perform a graceful stop
        sleep 2
        d_start
        echo "."
        ;;
    *)
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload)" >&2
        exit 3
        ;;
esac
exit 0

4. 设置开机启动

chkconfig php-fpm on

Ⅳ、redis 开机启动

1. 在/etc/init.d/目录下创建脚本

vim /etc/init.d/redis

2. 更改脚本权限

chmod 775 /etc/init.d/redis

3. 编写脚本内容

###########################
PATH=/usr/local/bin:/sbin:/usr/bin:/bin

REDISPORT=6379
EXEC=/usr/local/bin/redis-server
REDIS_CLI=/usr/local/bin/redis-cli

PIDFILE=/var/run/redis.pid
CONF="/etc/redis.conf"

case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                $EXEC $CONF
        fi
        if [ "$?"="0" ]
        then
              echo "Redis is running..."
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $REDIS_CLI -p $REDISPORT SHUTDOWN
                while [ -x ${PIDFILE} ]
               do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
   restart|force-reload)
        ${0} stop
        ${0} start
        ;;
  *)
    echo "Usage: /etc/init.d/redis {start|stop|restart|force-reload}" >&2
        exit 1
esac
##############################

4. 设置开机启动

chkconfig redis on

至此,大功告成。

可以用命令 chkconfig 查看开机启动服务列表

chkconfig --list

附录:

1、nigx重启错误

bind() to 0.0.0.0:80 failed (98: Address already in use)

这个是nginx重启是 经常遇到的。 网上找了很多信息 都是没有啥用。说的乱七八糟的。 发现原来是nginx重复重启。自己占用了端口。 解决方法

killall -9 nginx

杀掉nginx 进程 然后重启就行了。

service nginx restart

2、php-fpm 启动 关闭

php-fpm 不再支持 php-fpm 补丁具有的 /usr/local/php/sbin/php-fpm (start|stop|reload)等命令,需要使用信号控制:

master 进程可以理解以下信号

  • SIGINT, SIGTERM 立刻终止
  • SIGQUIT 平滑终止
  • SIGUSR1 重新打开日志文件
  • SIGUSR2 平滑重载所有worker进程并重新载入配置和二进制模块

示例:

php-fpm 关闭:

kill -SIGINT `cat /usr/local/php/var/run/php-fpm.pid`

php-fpm 重启:

kill -SIGUSR2 `cat /usr/local/php/var/run/php-fpm.pid`

其次配置文件不再使用的xml 格式,改为了INI,但是配置参数几乎和以前一样,可参照xml格式的格式配置。

3、nginx 启动 关闭

  • nginx的启动 (nginx.conf文件基本上位于nginx主目录中的conf目录中)
nginx -c nginx.conf
  • nginx的停止 (nginx.pid文件基本上位于nginx主目录中的logs目录中)
ps -ef | grep nginx

可发现数个nginx进程,其中标有master的为主进程,其它为子进程, 停止nginx主要就是对主进程进行信号控制.

从容停止

kill -QUIT `cat nginx.pid`

快速停止

kill -TERM `cat nginx.pid`

or

kill -INT `cat nginx.pid`

强制停止

kill -9 `cat nginx.pid`

nginx的平滑重启

首先要验证新的配置文件是否正确:

nginx -t -c nginx.conf

成功后向主进程发送HUP信号即可: [/shell]kill -HUP cat nginx.pid[/shell]

4、nginx 平滑升级

  1. 备份好旧的可执行文件,使用新版本替换旧版本

  2. kill -USR2 旧版本的主进程PID 进行平滑升级, 此时新老版本共存

  3. kill -WINCH 旧版本的主进程PID 逐步关闭旧主进程的工作进程

  4. 当旧主进程产生的工作进程全部关闭后, 可以决定是否使用新版本还是旧版本.(需要使用kill命令来杀死新或旧主进程)

#!/bin/sh
BASE_DIR='/usr/local/'
${BASE_DIR}nginx/sbin/nginx -t -c ${BASE_DIR}nginx/conf/nginx.conf >& ${BASE_DIR}nginx/logs/nginx.start
info=`cat ${BASE_DIR}nginx/logs/nginx.start`
if [ `echo $info | grep -c "syntax is ok" ` -eq 1 ]; then
if [ `ps aux|grep "nginx"|grep -c "master"` == 1 ]; then
kill -HUP `cat ${BASE_DIR}nginx/logs/nginx.pid`
echo "ok"
else
killall -9 nginx
sleep 1
${BASE_DIR}nginx/sbin/nginx
fi
else
echo "######## error: ########"
cat ${BASE_DIR}nginx/logs/nginx.start
fi

5、CentOS修改系统环境变量

我这里拿php作为一个例子,我的php安装在/usr/local/webserver/php下,没有把php加入环境变量时,你在命令行执行

# 查看当前php的版本信息
[root@CentOS ~]# php -v

会提示你此命令不存在。

下面详细说说linux下修改环境变量的方法

方法一:

在/etc/profile文件中添加变量【对所有用户生效(永久的)】
用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久的”。

[root@CentOS ~]# vim /etc/profile

在文件末尾加上如下两行代码

PATH=/usr/local/webserver/php/bin:$PATH
export PATH

如:

# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}

if [ -x /usr/bin/id ]; then
    if [ -z "$EUID" ]; then
        # ksh workaround
        EUID=`id -u`
        UID=`id -ru`
    fi
    USER="`id -un`"
    LOGNAME=$USER
    MAIL="/var/spool/mail/$USER"
fi

# Path manipulation
if [ "$EUID" = "0" ]; then
    pathmunge /sbin
    pathmunge /usr/sbin
    pathmunge /usr/local/sbin
else
    pathmunge /usr/local/sbin after
    pathmunge /usr/sbin after
    pathmunge /sbin after
fi

HOSTNAME=`/bin/hostname 2>/dev/null`
HISTSIZE=1000
if [ "$HISTCONTROL" = "ignorespace" ] ; then
    export HISTCONTROL=ignoreboth
else
    export HISTCONTROL=ignoredups
fi

export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL

# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
if [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then
    umask 002
else
    umask 022
fi

for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null 2>&1
        fi
    fi
done

unset i
unset pathmunge

PATH=/usr/local/webserver/php/bin:$PATH
export PATH

要是刚才的修改马上生效,需要执行以下代码

[root@CentOS ~]# source /etc/profile

这时再查看系统环境变量,就能看见刚才加的东西已经生效了

[root@CentOS ~]# echo $PATH
/usr/local/webserver/php/bin:/usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

现在就能直接使用php命令了(而不是像之前写很长一串/usr/local/webserver/php/bin/php -v),例如查看当前php的版本

[root@CentOS ~]# php -v
PHP 5.3.8 (cli) (built: Jun 27 2012 14:28:20)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies

方法二:

在用户目录下的.bash_profile文件中增加变量【对单一用户生效(永久的)】
用VI在用户目录下的.bash_profile文件中增加变量,改变量仅会对当前用户有效,并且是“永久的”。具体操作和方法1一样,这里就不在列举代码了。

方法三:

直接运行export命令定义变量【只对当前shell(BASH)有效(临时的)】

在shell的命令行下直接使用[export变量名=变量值]定义变量,该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。例如

export PATH=/usr/local/webserver/php/bin:$PATH

Linux下安装配置OpenResty,并测试在Nginx中使用Lua编程

一、简介

OpenResty,也被称为“ngx_openresty”,是一个以Nginx为核心同时包含很多第三方模块的Web应用服务器。借助于Nginx的事件驱动模型和非阻塞IO,可以实现高性能的Web应用程序。 OpenResty不是Nginx的分支,它只是一个软件包。主要有章亦春维护。

OpenResty默认集成了Lua开发环境,而且提供了大量组件如Mysql、Redis、Memcached等,使得在Nginx上开发Web应用更方便简单。

二、安装OpenResty

[root@hbase31 src]# wget https://openresty.org/download/openresty-1.11.2.5.tar.gz
[root@hbase31 src]# tar -zxvf openresty-1.13.6.1.tar.gz
[root@hbase31 openresty-1.13.6.1]# ./configure --prefix=/usr/local/openresty --user=www --group=www --with-http_stub_status_module --with-http_ssl_module --with-openssl=/usr/local/ssl --with-pcre=/usr/local/src/pcre-8.38 --add-module=/usr/local/src/ngx_cache_purge-2.3 --with-http_gzip_static_module --with-luajit
[root@hbase31 openresty-1.13.6.1]# make && make install

注:关于这里的编译参数可以认为是在Nginx的编译参数的基础上添加了其他组件的参数。如需查看更多参数可以使用以下命令:

[root@hbase31 openresty-1.13.6.1]# ./configure --help

配置nginx的启动脚本:

[root@hbase31 openresty-1.13.6.1]# vim /etc/init.d/nginx

添加如下内容:

#!/bin/bash
# nginx Startup script for the Nginx HTTP Server
# it is v.1.3.0 version.
# chkconfig: - 85 15
# description: Nginx is a high-performance web and proxy server.
#              It has a lot of features, but it's not for everyone.
# processname: nginx
# pidfile: /var/run/nginx.pid
# config: /usr/local/openresty/nginx/conf/nginx.conf
nginxd=/usr/local/openresty/nginx/sbin/nginx
nginx_config=/usr/local/openresty/nginx/conf/nginx.conf
nginx_pid=/usr/local/openresty/nginx/logs/nginx.pid
RETVAL=0
prog="nginx"
# Source function library.
.  /etc/rc.d/init.d/functions
# Source networking configuration.
.  /etc/sysconfig/network
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
[ -x $nginxd ] || exit 0
# Start nginx daemons functions.
start() {
if [ -e $nginx_pid ];then
   echo "nginx already running...."
   exit 1
fi
   echo -n $"Starting $prog: "
   daemon $nginxd -c ${nginx_config}
   RETVAL=$?
   echo
   [ $RETVAL = 0 ] && touch /var/lock/subsys/nginx
   return $RETVAL
}
# Stop nginx daemons functions.
stop() {
        echo -n $"Stopping $prog: "
        killproc $nginxd
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && rm -f /var/lock/subsys/nginx $nginx_pid
}
reload() {
    echo -n $"Reloading $prog: "
    #kill -HUP `cat ${nginx_pid}`
    killproc $nginxd -HUP
    RETVAL=$?
    echo
}
# See how we were called.
case "$1" in
start)
        start
        ;;
stop)
        stop
        ;;
reload)
        reload
        ;;
restart)
        stop
        start
        ;;

status)
        status $prog
        RETVAL=$?
        ;;
*)
        echo $"Usage: $prog {start|stop|restart|reload|status|help}"
        exit 1
esac
exit $RETVAL

添加可执行权限:

[root@hbase31 openresty-1.13.6.1]# chmod a+x /etc/init.d/nginx

启动nginx:

[root@hbase31 openresty-1.13.6.1]# service nginx start

三、在Nginx中使用Lua脚本

[root@hbase31 vhost]# cd /usr/local/openresty/nginx/conf
[root@hbase31 conf]# mkdir lua vhost

(1)测试在Nginx中使用Lua脚本

[root@hbase31 nginx]# vim /usr/local/openresty/nginx/conf/vhost/lua.conf

其内容如下:

server {
    server_name localhost;
    listen 3000;
    index index.html index.htm index.jsp;

    location / {
        root /usr/local/openresty/nginx/html;
    }

    location /lua {
        default_type text/plain;
        content_by_lua 'ngx.say("hello,lua!")';
    } 

    limit_conn perip 1000;
    access_log logs/access_rua.log;
}

测试是否可以访问:

[root@hbase31 nginx]# service nginx reload

然后访问:http://192.168.1.31:3000/lua

如果输出以下内容则证明在Nginx中可以执行Lua脚本:

hello,lua!

(2)在Nginx中使用Lua脚本访问Redis

i)连接Redis集群,然后添加测试参数:

192.168.1.30:7000> set '123' '456'

ii)添加连接Redis的Lua脚本:

[root@hbase31 nginx]# vim /usr/local/openresty/nginx/conf/lua/redis.lua

其内容如下:

local redis = require "resty.redis"
local conn = redis.new()
conn.connect(conn, '192.168.1.30', '7000')
local res = conn:get("123")
if res==ngx.null then
    ngx.say("redis集群中不存在KEY——'123'")
    return
end
ngx.say(res)

iii)在上面的lua.conf配置文件中添加以下location:

    location /lua_redis {
        default_type text/plain;
        content_by_lua_file /usr/local/openresty/nginx/conf/lua/redis.lua;
    }
1
2
3
4
    location /lua_redis {
        default_type text/plain;
        content_by_lua_file /usr/local/openresty/nginx/conf/lua/redis.lua;
    }

iv)测试是否可以访问:

[root@hbase31 nginx]# service nginx reload

然后访问:http://192.168.1.31:3000/lua_redis

如果输出以下内容则证明可以访问redis:

456

Openresty最佳案例 | 第1篇:Nginx介绍

Nginx 简介

Nginx是一个高性能的Web 服务器,同时是一个高效的反向代理服务器,它还是一个IMAP/POP3/SMTP
代理服务器。

由于Nginx采用的是事件驱动的架构,能够处理并发百万级别的tcp连接,高度的模块化设计和自由的BSD许可,使得Nginx有着非常丰富的第三方模块。比如Openresty、API网关Kong。

BSD开源协议是一个给予使用者很大自由的协议。基本上使用者可以”为所欲为”,可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。

Nginx的优点

  • 高并发响应性能非常好,官方Nginx处理静态文件并发5w/s
  • 反向代理性能非常强。(可用于负载均衡)
  • 内存和cpu占用率低。(为Apache的1/5-1/10)
  • 对后端服务有健康检查功能。
  • 支持PHP cgi方式和fastcgi方式。
  • 配置代码简洁且容易上手。

Nginx的安装

Centos系统安装,请参考这里http://www.linuxidc.com/Linux/2016-09/134907.htm。先复制粘贴下它的文章。

1. gcc 安装

安装 nginx 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,则需要安装:

yum install gcc-c++

2. PCRE pcre-devel 安装

PCRE(Perl Compatible Regular Expressions) 是一个Perl库,包括 perl 兼容的正则表达式库。nginx 的 http 模块使用 pcre 来解析正则表达式,所以需要在 linux 上安装 pcre 库,pcre-devel 是使用 pcre 开发的一个二次开发库。nginx也需要此库。命令:

yum install -y pcre pcre-devel

3. zlib 安装

zlib 库提供了很多种压缩和解压缩的方式, nginx 使用 zlib 对 http 包的内容进行 gzip ,所以需要在 Centos 上安装 zlib 库。

yum install -y zlib zlib-devel

4. OpenSSL 安装

OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及 SSL 协议,并提供丰富的应用程序供测试或其它目的使用。
nginx 不仅支持 http 协议,还支持 https(即在ssl协议上传输http),所以需要在 Centos 安装 OpenSSL 库。

yum install -y openssl openssl-devel

5. 官网下载

(1). 直接下载.tar.gz安装包,地址:https://nginx.org/en/download.html

(2). 使用wget命令下载(推荐)。

wget -c https://nginx.org/download/nginx-1.10.1.tar.gz

6. 解压

依然是直接命令:

tar -zxvf nginx-1.10.1.tar.gz 
cd nginx-1.10.1

7. 配置

其实在 nginx-1.10.1 版本中你就不需要去配置相关东西,默认就可以了。当然,如果你要自己配置目录也是可以的。
使用默认配置

./configure

8. 编译安装

make 
make install

查找安装路径:

whereis nginx

Nginx的模块组成

Nginx的模块从结构上分为核心模块、基础模块和第三方模块:

  • 核心模块:HTTP模块、EVENT模块和MAIL模块
  • 基础模块:HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块,
  • 第三方模块:HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块。

Nginx的高并发得益于其采用了epoll模型,与传统的服务器程序架构不同,epoll是linux内核2.6以后才出现的。Nginx采用epoll模型,异步非阻塞,而Apache采用的是select模型。

  • Select特点:select 选择句柄的时候,是遍历所有句柄,也就是说句柄有事件响应时,select需要遍历所有句柄才能获取到哪些句柄有事件通知,因此效率是非常低。
  • epoll的特点:epoll对于句柄事件的选择不是遍历的,是事件响应的,就是句柄上事件来就马上选择出来,不需要遍历整个句柄链表,因此效率非常高。

Nginx常用命令

nginx 环境变量配置:

export PATH=$PATH:/usr/servers/nginx/sbin
  • 查看nginx进程
    ps -ef|grep nginx

  • 启动nginx
    nginx
    启动结果显示nginx的主线程和工作线程,工作线程的数量跟nginx.conf中的配置参数worker_processes有关。

  • 平滑启动nginx
    kill -HUP cat /var/run/nginx.pid
    或者
    nginx -s reload

  • 强制停止nginx
    pkill -9 nginx

  • 检查对nginx.conf文件的修改是否正确
    nginx -t

  • 停止nginx的命令
    nginx -s stop或者pkill nginx

  • 查看nginx的版本信息
    nginx -v

  • 查看完整的nginx的配置信息
    nginx -V

Nginx的配置

通常情况下,Nginx的配置在Ngix的安装目录下的/conf/config.default 文件里,基本配置如下:

worker_process # 表示工作进程的数量,一般设置为cpu的核数

worker_connections # 表示每个工作进程的最大连接数

server{} # 块定义了虚拟主机
    listen # 监听端口
    server_name # 监听域名
    location {} # 是用来为匹配的 URI 进行配置,URI 即语法中的“/uri/”
    location /{} # 匹配任何查询,因为所有请求都以 / 开头
        root # 指定对应uri的资源查找路径,这里html为相对路径,完整路径为
        # /opt/nginx-1.7.7/html/
        index # 指定首页index文件的名称,可以配置多个,以空格分开。如有多
        # 个,按配置顺序查找。

location 常用配置如下:

未分类

Nginx的常用配置非常多,以下内容摘自于布尔教育课件,仅供参考:

#定义Nginx运行的用户和用户组
user  www www;
#启动进程,通常设置成和cpu的数量相等
worker_processes  8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
#为每个进程分配cpu,上例中将8个进程分配到8个cpu,当然可以写多个,或者将一个进程分配到多个cpu。
worker_rlimit_nofile 102400;
#这个指令是指当一个nginx进程打开的最多文件描述符数目,理论值应该是最多打
#开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀
#,所以最好与ulimit -n的值保持一致。

#全局错误日志及PID文件
error_log  /usr/local/nginx/logs/error.log; 
#错误日志定义等级,[ debug | info | notice | warn | error | crit ]
pid        /usr/local/nginx/nginx.pid;

#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀.
#所以建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

#工作模式及连接数上限
events {
    use   epoll;                #epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能
    worker_connections  102400; #单个后台worker process进程的最大并发链接数 (最大连接数=连接数*进程数)
    multi_accept on; #尽可能多的接受请求
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
    #设定mime类型,类型由mime.type文件定义
    include       mime.types;
    default_type  application/octet-stream;
    #设定日志格式
    access_log    /usr/local/nginx/log/nginx/access.log;
     sendfile      on;
    #sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用必须设为 on
    #如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.
    #autoindex  on;  #开启目录列表访问,合适下载服务器,默认关闭。
    tcp_nopush on; #防止网络阻塞
    keepalive_timeout 60;
    #keepalive超时时间,客户端到服务器端的连接持续有效时间,当出现对服务器的后,继请求时,keepalive-timeout功能可避免建立或重新建立连接。
    tcp_nodelay   on; #提高数据的实时响应性
   #开启gzip压缩
   gzip on;
    gzip_min_length  1k;
    gzip_buffers     4 16k;
    gzip_http_version 1.1;
    gzip_comp_level 2; #压缩级别大小,最大为9,值越小,压缩后比例越小,CPU处理更快。
    #值越大,消耗CPU比较高。
    gzip_types       text/plain application/x-javascript text/css application/xml;
    gzip_vary on;
    client_max_body_size 10m;      #允许客户端请求的最大单文件字节数
    client_body_buffer_size 128k;  #缓冲区代理缓冲用户端请求的最大字节数,
    proxy_connect_timeout 90;      #nginx跟后端服务器连接超时时间(代理连接超时)
    proxy_send_timeout 90;         #后端服务器数据回传时间(代理发送超时)
    proxy_read_timeout 90;         #连接成功后,后端服务器响应时间(代理接收超时)
    proxy_buffer_size 4k;          #设置代理服务器(nginx)保存用户头信息的缓冲区大小
    proxy_buffers 4 32k;           #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
    proxy_busy_buffers_size 64k;   #高负荷下缓冲大小(proxy_buffers*2)

    #设定请求缓冲
    large_client_header_buffers  4 4k;
    client_header_buffer_size 4k;
    #客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求的头部大小不会超过1k
    #不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。
    open_file_cache max=102400 inactive=20s;
    #这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。
    open_file_cache_valid 30s;
    #这个是指多长时间检查一次缓存的有效信息。
    open_file_cache_min_uses 1;
    #open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive
    #包含其它配置文件,如自定义的虚拟主机
    include vhosts.conf;
}

配置详解2如下:

    #这里为后端服务器wugk应用集群配置,根据后端实际情况修改即可,tdt_wugk为负载均衡名称,可以任意指定
    #但必须跟vhosts.conf虚拟主机的pass段一致,否则不能转发后端的请求。weight配置权重,在fail_timeout内检查max_fails次数,失败则剔除均衡。
    upstream tdt_wugk {
        server   127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=30s;
        server   127.0.0.1:8081 weight=1 max_fails=2 fail_timeout=30s;
    }
   #虚拟主机配置
    server {
        #侦听80端口
        listen       80;
        #定义使用www.wuguangke.cn访问
        server_name  www.wuguangke.cn;
        #设定本虚拟主机的访问日志
        access_log  logs/access.log  main;
            root   /data/webapps/wugk;  #定义服务器的默认网站根目录位置
        index index.php index.html index.htm;   #定义首页索引文件的名称
        #默认请求
        location ~ /{
          root   /data/www/wugk;      #定义服务器的默认网站根目录位置
          index index.php index.html index.htm;   #定义首页索引文件的名称
          #以下是一些反向代理的配置.
          proxy_next_upstream http_502 http_504 error timeout invalid_header;
          #如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。
          proxy_redirect off;
          #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
          proxy_set_header Host $host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass  http://tdt_wugk;     #请求转向后端定义的均衡模块
       }

        # 定义错误提示页面
            error_page   500 502 503 504 /50x.html;  
            location = /50x.html {
            root   html;
        }
        #配置Nginx动静分离,定义的静态页面直接从Nginx发布目录读取。
        location ~ .*.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
        {
            root /data/www/wugk;
            #expires定义用户浏览器缓存的时间为3天,如果静态页面不常更新,可以设置更长,这样可以节省带宽和缓解服务器的压力。
            expires      3d;
        }
        #PHP脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
        location ~ .php$ {
            root /root;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME /data/www/wugk$fastcgi_script_name;
            include fastcgi_params;
        }
        #设定查看Nginx状态的地址
        location /NginxStatus {
            stub_status  on;
        }
     }
}

Nginx 内置绑定变量

未分类

  • documenturi|与uri相同; 比如 /test2/test.php

  • host|请求信息中的”Host”,如果请求中没有Host行,则等于设置的服务器名hostname | 机器名使用 gethostname系统调用的值

  • httpcookie|cookie信息http_referer | 引用地址

  • httpuseragent|客户端代理信息http_via | 最后一个访问服务器的Ip地址。

  • http_x_forwarded_for | 相当于网络访问路径is_args | 如果请求行带有参数,返回“?”,否则返回空字符串

  • limitrate|对连接速率的限制nginx_version |当前运行的nginx版本号

  • pidworker|进程的PIDquery_string | 与args相同realpath_root | 按root指令或alias指令算出的当前请求的绝对路径。其中的符号链接都会解析成真是文件路径,使用 Nginx 内置绑定变量

  • 207remoteaddr|客户端IP地址remote_port | 客户端端口号

  • remoteuser|客户端用户名,认证用request | 用户请求

  • requestbody|这个变量(0.7.58+)包含请求的主要信息。在使用proxypass或fastcgipass指令的location中比较有意义
    request_body_file | 客户端请求主体信息的临时文件名

  • requestcompletion|如果请求成功,设为”OK”;如果请求未完成或者不是一系列请求中最后一部分则设为空request_filename | 当前请求的文件路径名,比如/opt/nginx/www/test.php

  • requestmethod|请求的方法,比如”GET”、”POST”等request_uri | 请求的URI,带参数

  • scheme|所用的协议,比如http或者是httpsserver_addr | 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费)

  • servername|请求到达的服务器名server_port | 请求到达的服务器端口号

  • serverprotocol|请求的协议版本,”HTTP/1.0”或”HTTP/1.1”uri| 请求的URI,可能和最初的值有不同,比如经过重定向之类的。

Nginx+uwsgi 安装配置

在前面的章节中我们使用 python manage.py runserver 来运行服务器。这只适用测试环境中使用。
正式发布的服务,我们需要一个可以稳定而持续的服务器,比如apache, Nginx, lighttpd等,本文将以 Nginx 为例。

安装基础开发包

Centos 下安装步骤如下:

未分类

CentOS 自带 Python 2.4.3,但我们可以再安装Python2.7.5:

未分类

安装Python包管理

easy_install 包 https://pypi.python.org/pypi/distribute

安装步骤:

未分类

pip 包: https://pypi.python.org/pypi/pip

安装 pip 的好处是可以用 pip list、pip uninstall 管理 Python 包, easy_install 没有这个功能,只有 uninstall。

安装 uwsgi

uwsgi:https://pypi.python.org/pypi/uWSGI
uwsgi 参数详解:http://uwsgi-docs.readthedocs.org/en/latest/Options.html

未分类

测试 uwsgi 是否正常:
新建 test.py 文件,内容如下:

未分类

然后在终端运行:

未分类

在浏览器内输入:http://127.0.0.1:8001,查看是否有”Hello World”输出,若没有输出,请检查你的安装过程。

安装 Django

未分类

测试 django 是否正常,运行:

未分类

在浏览器内输入:http://127.0.0.1:8002,检查django是否运行正常。

安装 Nginx

安装命令如下:

未分类

你可以阅读 Nginx 安装配置 了解更多内容。

uwsgi 配置

uwsgi支持ini、xml等多种配置方式,本文以 ini 为例, 在/ect/目录下新建uwsgi9090.ini,添加如下配置:

未分类

Nginx 配置

找到nginx的安装目录(如:/usr/local/nginx/),打开conf/nginx.conf文件,修改server配置:

未分类

你可以阅读 Nginx 安装配置 了解更多内容。

设置完成后,在终端运行:

未分类

在浏览器输入:http://127.0.0.1,你就可以看到 django 的 “It work” 了。

Nginx错误日志分析及防护脚本

  • 关于iptables定时策略、crontab设置请自行去了解,建议使用”nohup &”方式执行crontab任务;

  • 该脚本可以扩展对iptables日志进行分析、某个IP在1天(或1小时)内出现多次被限制则进行更长时间限制或永久拒绝访问;

  • 对于nginx error日志可以做大小限制进行截断以减少脚本读取日志文件耗时。

# !/bin/bash
# 脚本用于Nginx错误日志检测,若30秒内来源IP地址超出10次错误视为攻击源并自动加入防火墙
# sh -x weblog_black.sh 进行跟踪调试

NGLOG="/data/nginx/log/error.log"
LOG1="/data/shell/$(date +%Y%m%d)_w$$.txt0"
LOG2="/data/shell/$(date +%Y%m%d)_w$$.txt1"
LOG3="/data/shell/$(date +%Y%m%d)_w$$.txt2"
IPTAB="/data/shell/w$$_iptables"
SHLOG="/data/shell/$(date +%Y%m%d)_w$$.run"

find /data/shell/ -type f -name "*.*" -mmin +3 -exec rm -f {} ;
grep -v -i '/undefined' $NGLOG | grep "[error]" | cut -d',' -f2 | cut -d':' -f2 | sort -b | uniq -cd | sort -nr > $LOG1
sleep 30
grep -v -i '/undefined' $NGLOG | grep "[error]" | cut -d',' -f2 | cut -d':' -f2 | sort -b | uniq -cd | sort -nr > $LOG2

#for line in `cat "$LOG2"`
cat $LOG2 | while read line
  do
    ip=`echo $line | awk -F" " '{print $2}'`
    nume=`echo $line | awk -F" " '{print $1}'`        #结束访问次数
    nums=`grep $ip $LOG1 | awk -F" " '{print $1}'`    #开始访问次数
    num30=`expr $nume - $nums`
    #num30=$((nume - nums)) || num30=$[ nume - nums ]
    echo $ip $nume $nums $num30 >> $SHLOG
  if [ "$num30" -gt 10 ]; then
    /sbin/iptables -nvL IN_NGBLACK
    if [ "$?" -eq 1 ]; then
      /sbin/iptables -N IN_NGBLACK
      /sbin/iptables -I INPUT -j IN_NGBLACK
    else
      chain_sum=`/sbin/iptables -nvL IN_NGBLACK | tail -n +3 | wc -l`
      if [ "$chain_sum" -gt 100 ]; then
        /sbin/iptables -D IN_NGBLACK $chain_sum
        /sbin/iptables -D IN_NGBLACK `expr $chain_sum - 1`
      fi
    fi

    /sbin/iptables -nvL IN_NGBLACK | grep $(echo $ip) | grep DROP
    if [ "$?" -eq 1 ]; then
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m time --timestart `date +%H:%M` --timestop `date -d '+10 min' +%H:%M` -j DROP
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m limit --limit 10/min --limit-burst 10 -j ACCEPT
      #/sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -j DROP
      #sleep 600 && /sbin/iptables -D IN_NGBLACK -s $ip -p tcp -m multiport --dports 80,443 -j DROP && /sbin/iptables -D IN_NGBLACK -s $ip -p tcp -m multiport --dports 80,443 -m limit --limit 10/min --limit-burst 10 -j ACCEPT & #主进程会在后台等待子进程执行完成后退出
    else
      chain_num=`/sbin/iptables -nvL IN_NGBLACK --line-numbers | grep $(echo $ip) | grep DROP | cut -d' ' -f1`
      /sbin/iptables -D IN_NGBLACK $chain_num
      /sbin/iptables -D IN_NGBLACK `expr $chain_num - 1`
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m time --timestart `date +%H:%M` --timestop `date -d '+15 min' +%H:%M` -j DROP
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m limit --limit 10/min --limit-burst 10 -j ACCEPT
    fi
    /sbin/iptables-save > $IPTAB
  fi
done

sleep 30
grep -v -i '/undefined' $NGLOG | grep "[error]" | cut -d',' -f2 | cut -d':' -f2 | sort -b | uniq -cd | sort -nr > $LOG3

cat $LOG3 | while read line
  do
    ip=`echo $line | awk -F" " '{print $2}'`
    nume=`echo $line | awk -F" " '{print $1}'`        #结束访问次数
    nums=`grep $ip $LOG1 | awk -F" " '{print $1}'`    #开始访问次数
    num60=`expr $nume - $nums`
    echo $ip $nume $nums $num60 >> $SHLOG
  if [ "$num60" -gt 15 ]; then
    /sbin/iptables -nvL IN_NGBLACK
    if [ "$?" -eq 1 ]; then
      /sbin/iptables -N IN_NGBLACK
      /sbin/iptables -I INPUT -j IN_NGBLACK
    else
      chain_sum=`/sbin/iptables -nvL IN_NGBLACK | tail -n +3 | wc -l`
      if [ "$chain_sum" -gt 100 ]; then
        /sbin/iptables -D IN_NGBLACK $chain_sum
        /sbin/iptables -D IN_NGBLACK `expr $chain_sum - 1`
      fi
    fi

    /sbin/iptables -nvL IN_NGBLACK | grep $(echo $ip) | grep DROP
    if [ "$?" -eq 1 ]; then
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m time --timestart `date +%H:%M` --timestop `date -d '+10 min' +%H:%M` -j DROP
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m limit --limit 10/min --limit-burst 10 -j ACCEPT
      #/sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -j DROP
      #sleep 600 && /sbin/iptables -D IN_NGBLACK -s $ip -p tcp -m multiport --dports 80,443 -j DROP && /sbin/iptables -D IN_NGBLACK -s $ip -p tcp -m multiport --dports 80,443 -m limit --limit 10/min --limit-burst 10 -j ACCEPT & #主进程会在后台等待子进程执行完成后退出
    else
      chain_num=`/sbin/iptables -nvL IN_NGBLACK --line-numbers | grep $(echo $ip) | grep DROP | cut -d' ' -f1`
      /sbin/iptables -D IN_NGBLACK $chain_num
      /sbin/iptables -D IN_NGBLACK `expr $chain_num - 1`
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m time --timestart `date +%H:%M` --timestop `date -d '+15 min' +%H:%M` -j DROP
      /sbin/iptables -I IN_NGBLACK 1 -s $ip -p tcp -m multiport --dports 80,443 -m limit --limit 10/min --limit-burst 10 -j ACCEPT
    fi
    /sbin/iptables-save > $IPTAB
  fi
done