Nginx_day4——uWSGI,灰度发布,网站限流限速,Nginx跨域

Nginx-day4

一、部署Python网站项目

什么是uWSGl ?

  • uWSGI是一个 Web 服务器 (WSGI 服务器)PHP-FOM相识,主要用途是将应用程序部署到生产环境中
    负责接收 Nginx 转发的请求并调用 Python 代码执行,再将结果返回给 Nginx。

  • 实现WSGI协议:作为桥梁连接Web服务器(如Nginx)与Python应用(如Django、Flask)

rust 复制代码
	[浏览器] → 	[Nginx/Apache]	 →    [uWSGI]	→ 	[Python Web应用(Django)]
                              		 
  
	
#[层			 组件					职责																	 ]
入口层			浏览器				发起 HTTP 请求,接收并渲染响应内容
接入层		Nginx / Apache			1.处理静态文件			 2.反向代理动态请求(转发给 uWSGI) 3.负载均衡、限流、SSL 卸载
中间层			uWSGI				1.接收 Nginx 转发的请求	 2.按 WSGI 协议调用 Django	      3.管理进程池、线程池、连接超时
应用层			Django				1.路由匹配(URL → View)	 2.业务逻辑执行(查询数据库、计算)  3.返回 HTML / JSON 响应

安装Python

  • python网站的依赖包 与 依赖关系
    ┌─────────────────────────────────────┐
    │ Django Web 应用 │
    ├─────────────────────────────────────┤
    │ django-bootstrap3(前端界面美化) │ ← 依赖 Django, ,是"皮肤"(让页面好看)
    ├─────────────────────────────────────┤
    │ Django 1.11.8(Web 框架核心) │ ← 依赖 pytz ,Python 最流行的 Web 框架,是骨架
    ├─────────────────────────────────────┤
    │ pytz(时区处理) │ 是 Django 的"心脏"(时间处理)
    └─────────────────────────────────────┘

测试 :先使用 Python应用 Django 自带的 Web 服务器,解析 Python 代码,Nginx并未参与

rust 复制代码
1)拷贝软件到proxy主机
[root@server1 ~]# scp -r /linux-soft/s2/wk/python/ 192.168.99.5:/root

2)安装python依赖软件
[root@proxy ~]# yum  -y install  gcc  make  python3  python3-devel

3)安装python网站的依赖包,python的软件包使用pip3安装
[root@proxy ~]# cd /root/python/
[root@proxy python]# pip3 install  pytz-2022.6-py2.py3-none-any.whl
[root@proxy python]# pip3 install  Django-1.11.8-py2.py3-none-any.whl
[root@proxy python]# pip3 install  django-bootstrap3-11.0.0.tar.gz

4)测试python网站
[root@proxy python]# tar -xf python-project-demo.tar.gz 	#网站代码
[root@proxy python]# cd python-project-demo/
[root@proxy python-project-demo]# python3 manage.py runserver 0.0.0.0:8000      #manage.py相当于网站运行的引导文件

在浏览器访问192.168.99.5:8000,启动网站的页面信息显示就是正常,web页面标题显示首页两字,页面暂时没有内容,耐心等待

此时可以测试完毕后按ctrl + c

安装uWSGI

uWSGI 运行动态网站配置文件(默认没有配置文件,需要自己写)

主要配置:

[uwsgi]

socket=127.0.0.1:8000 #与web服务(nginx)通信的接口

chdir=/root/python/python-project-demo #网站的工作目录

wsgi-file=learning_log/wsgi.py #定义网站运行时,uwsgi调用的脚本文件

daemonize=/var/log/uwsgi.log #指定日志文件位置


核心要点

  • 配置uwsgi配置文件设置
  • uwsgi_pass 动态页面交给uWSGI
  • include uwsgi_params 加载调用uWSGI配置文件
    实验要求 : 配置 Nginx 使其可以将 python的动态访问转交给uWSGI解析
rust 复制代码
1)安装uWSGI
[root@proxy python-project-demo]# cd ..
[root@proxy python]# pip3 install uWSGI-2.0.21.tar.gz

准备配置文件(默认没有配置文件,需要自己写),运行动态网站,
[root@proxy python]# vim myproject.ini  #要以ini结尾,文件名随意
[uwsgi]
socket=127.0.0.1:8000                    #与web服务(nginx)通信的接口
chdir=/root/python/python-project-demo   #网站的工作目录
wsgi-file=learning_log/wsgi.py           #定义网站运行时,uwsgi调用的脚本文件
daemonize=/var/log/uwsgi.log             #指定日志文件位置

2) 运行uWSGI
[root@proxy python]# uwsgi --ini myproject.ini  #读取myproject.ini运行uWSGI
[uWSGI] getting INI configuration from myproject.ini
[root@proxy python]# ss -antlp | grep 8000  #8000已经监听,成功启动

3)修改nginx配置文件,添加uWSGI转发
[root@proxy python]# vim /usr/local/nginx/conf/nginx.conf
...
        location / {
            uwsgi_pass 127.0.0.1:8000;     # 动态页面交给uWSGI
            include uwsgi_params;          # 加载调用uWSGI配置文件
            root   html;
            index  index.html index.htm;
        }
        location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
            expires 30d;
         }
...
[root@proxy python]# /usr/local/nginx/sbin/nginx

4)测试
使用浏览器访问192.168.99.5

二、配置Nginx实现用IP测试灰度发布

主机名 IP地址 角色
proxy (已存在) eth1:192.168.99.5/24 代理服务器
web1 (已存在) eth1:192.168.99.100/24 web服务器
web2 (已存在) eth1:192.168.99.200/24 web服务器

灰度发布(Gray Release / CanaryRelease):

是一种平滑过渡的发布方式,让部分用户先使用新版本,观察稳定后再全量推送。

餐厅推出新菜单:

  1. 先让 5% 的客人尝试 → 观察反馈
  2. 没问题 → 扩大到 30%
  3. 反馈良好 → 100% 全量发布

核心要点Nginx 作为反向代理,根据预设规则(IP、Cookie、Header等),设置Upstream 定义(后端服务器池)将请求通过 $remote_addr 变量识别不同客户机,动态分发到不同版本的后端服务器
测试:要求不同IP的客户访问相同代理时,可以看到不同集群主机的内容

通过 $remote_addr 变量识别不同客户机


常用分流 变量

$remote_addr 客户端IP

$http_user_agent 浏览器类型

$cookie_name Cookie值

$http_x_forwarded_for 代理IP

$arg_userid URL参数 ?userid=123

网关层灰度发布

创建不同集群

rust 复制代码
1)为web1搭建nginx虚拟主机 
[root@proxy python]# scp /root/lnmp_soft/nginx-1.22.1.tar.gz 192.168.99.100:/root
[root@proxy python]# scp /root/lnmp_soft/nginx-1.22.1.tar.gz 192.168.99.200:/root
[root@web1 ~]# systemctl disable --now httpd    #取消开机自启,停止httpd服务
[root@web1 ~]# yum -y install make gcc openssl-devel pcre-devel #安装基础依赖包
[root@web1 ~]# tar -xf nginx-1.22.1.tar.gz
[root@web1 ~]# cd nginx-1.22.1/
[root@web1 nginx-1.22.1]# ./configure 
[root@web1 nginx-1.22.1]# make && make install
[root@web1 nginx-1.22.1]# vim /usr/local/nginx/conf/nginx.conf  #默认server listen 80的不要动,直接另外写一个server
http {    
...
    server {                      #此为新添加的server
        listen       8001;
        server_name  localhost;
        root html8001;
        index index.html;
}
    server {
        listen       80;
        server_name  localhost;
...
[root@web1 nginx-1.22.1]# /usr/local/nginx/sbin/nginx 
[root@web1 nginx-1.22.1]# mkdir /usr/local/nginx/html8001
[root@web1 nginx-1.22.1]# echo web1-nginx-80 > /usr/local/nginx/html/index.html
[root@web1 nginx-1.22.1]# echo web1-nginx-8001 > /usr/local/nginx/html8001/index.html

使用web1测试
[root@web1 nginx-1.22.1]# curl 192.168.99.100
web1-nginx-80
[root@web1 nginx-1.22.1]# curl 192.168.99.100:8001
web1-nginx-8001

2)为web2搭建nginx
[root@web2 ~]# systemctl disable --now httpd
[root@web2 ~]# yum -y install make gcc openssl-devel pcre-devel #安装基础依赖包
[root@web2 ~]# tar -xf nginx-1.22.1.tar.gz
[root@web2 ~]# cd nginx-1.22.1/
[root@web2 nginx-1.22.1]# ./configure 
[root@web2 nginx-1.22.1]# make && make install
[root@web2 nginx-1.22.1]# /usr/local/nginx/sbin/nginx 
[root@web2 nginx-1.22.1]# echo web2-nginx-80 > /usr/local/nginx/html/index.html

3)使用proxy主机在nginx配置中创建集群
[root@proxy python]# killall uwsgi      #停止uwsgi
[root@proxy python]# cd /usr/local/nginx
[root@proxy nginx]# cp conf/nginx.conf.default conf/nginx.conf  #恢复配置文件
[root@proxy nginx]# vim conf/nginx.conf
http {    
...
    upstream default {              #正常业务集群
        server 192.168.99.100:80;
        server 192.168.99.200:80;
    }
    upstream s8001 {
        server 192.168.99.100:8001;   #新版本业务集群1
    }
    server {
        listen       80;
        server_name  localhost;
        set $group "default";       #自己定义变量$group,默认值为default,访问正常业务集群
        if ($remote_addr ~ "192.168.99.1"){  #如果客户机ip是包含192.168.99.1就访问新版本业务集群1,$remote_addr为nginx的内置变量,代表访问者的ip,
        										根据ip分配业务集群,符合条件走新业务,不符合的走正常业务
             set $group s8001;  	#满足条件,变量重新赋值,那么$group 就会等于s8001,下面根据此值匹配走代理的新业务集群
        }
        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            proxy_pass http://$group;       #根据ip分配业务集群,符合条件走新业务,不符合的走默认
            root   html;
            index  index.html index.htm;
        }
...
[root@proxy nginx]# /usr/local/nginx/sbin/nginx -s reload


使用proxy测试
[root@proxy ~]# curl 192.168.99.5   #显示正常业务集群
web1-nginx-80
[root@proxy ~]# curl 192.168.99.5   #显示正常业务集群
web2-nginx-80

web1访问proxy
[root@web1 ~]# curl 192.168.99.5    #显示新版本业务集群1
web1-nginx-8001

三、通过不同用户ID测试灰度发布

测试:不同ID的客户访问相同代理时,可以看到不同集群主机的内容,用户身份决定流量去向

启动LNMP环境

rust 复制代码
1)proxy主机修改Nginx配置文件(修改默认首页与动静分离)
[root@proxy ~]# cd /usr/local/nginx
[root@proxy nginx]# cp conf/nginx.conf.default conf/nginx.conf  #恢复配置文件
[root@proxy nginx]# vim /usr/local/nginx/conf/nginx.conf
...
 location  ~  \.php$  {
            root           html;
            fastcgi_pass  unix:/run/php-fpm/www.sock;
            fastcgi_index  index.php;
            include        fastcgi.conf;
        }
...        
php-fpm的配置文件之前已经修改好,此时不用修改


1)重新加载Nginx服务
[root@proxy nginx]# /usr/local/nginx/sbin/nginx -s reload
[root@proxy nginx]# ss -antlp | grep :80   

2)启动MySQL服务(已经启动则不需要执行)
[root@proxy nginx]# systemctl start mariadb
[root@proxy nginx]# systemctl status mariadb

3)启动PHP-FPM服务(已经启动则不需要执行)
[root@proxy nginx]# systemctl start  php-fpm
[root@proxy nginx]# systemctl status php-fpm
[root@proxy nginx]# cp /root/lnmp_soft/php_scripts/test.php /usr/local/nginx/html/
[root@proxy nginx]# curl 192.168.99.5/test.php      #测试动态页面
<html>
<body>
This is HTML message
</br>
c is bigger</body>
</html>

4) 配置好lnmp之后,拷贝带登录效果的测试页面
[root@proxy nginx]# cd /root/lnmp_soft/php_scripts/
[root@proxy nginx]# tar -xf php-session-demo.tar.gz    #释放带登录功能的网页
[root@proxy nginx]# cp -r php-session-demo/* /usr/local/nginx/html/   #拷贝页面到nginx中

使用浏览器访问192.168.99.5/index.php  可以看到有登录界面的网页

如果想要访问此网站时直接输入http://192.168.99.5就能访问到这个登录页面,可以更改以下配置实现
[root@proxy nginx]# vim /usr/local/nginx/conf/nginx.conf
server {
   listen 80;
   
   location / {
      root html;
      index index.php index.html index.htm;     #新添加index.php
   }

...
 location  ~  \.php$  {
            root           html;
            fastcgi_pass  unix:/run/php-fpm/www.sock;
            fastcgi_index  index.php;
            include        fastcgi.conf;
        }
...  
[root@proxy nginx]# /usr/local/nginx/sbin/nginx -s reload
直接输入http://192.168.99.5就能访问到登录页面,输入任意用户名和密码登录测试即可

注:这里index.php是登录前页面 ,home.php是登录后才能看的页面

灰度逻辑写在 PHP 代码里

修改页面

rust 复制代码
1)修改home.php页面
[root@proxy php_scripts]# vim /usr/local/nginx/html/home.php        #修改php页面,将原有Welcome那行修改成以下状态
Welcome :  <?php
if(preg_match("/^abc/",$_SESSION['login_user'])) {      #preg_match匹配正则,如果登录账号是以abc开头,就连接99.100,否则连接99.200
echo "<a href='http://192.168.99.100'>开始</a>";
}
else
{
echo "<a href='http://192.168.99.200'>开始</a>";
}
?>

2)测试
浏览器访问192.168.99.5/index.php分别输入不同名称的账户,可以看到"开始"连接的是不同的地址
术语 说明
灰度 介于黑(全旧)与白(全新)之间的中间状态,平滑过渡的发布方式
金丝雀发布 先让少量用户测试新版本,如无问题再扩大范围
A/B测试 同时运行新旧版本,对比效果

四、配置网站限流限速

定义limit_rate限速

使用到的参数:

  • limit_rate 限速(全局限速:http内server外使用) (虚拟主机限速:server内使用)
  • vlimit_conn_zone 连接限制,控制连接数
  • $binary_remote_addr是nginx的内置变量,获取客户的地址,可存储到文件中
rust 复制代码
1)定义limit_rate限速
[root@proxy nginx]# vim /usr/local/nginx/conf/nginx.conf
http {
...    
limit_rate 100k;        #全局限速,速度限制100k,最大100k的速度传输数据
server {
    listen 80;
...
[root@proxy php_scripts]# /usr/local/nginx/sbin/nginx -s reload

测试,使用dd制作一个大文件测试,填充0到html/test.img文件,大小100M,填充一次
[root@proxy php_scripts]# cd /usr/local/nginx/
[root@proxy nginx]# dd if=/dev/zero of=html/test.img bs=100M count=1
[root@proxy nginx]# yum -y install wget 
[root@proxy nginx]# wget 192.168.99.5/test.img  #每秒速度大约100k,看到结果之后ctrl C 即可
...
test.img             0%[               ] 400.00K   101KB/s    eta 16m 49s

2)定义虚拟主机限速
[root@proxy nginx]# vim conf/nginx.conf
http {
...    
server {
    listen 80;
    server_name localhost;
    limit_rate 200k;            #虚拟主机限速
...
[root@proxy nginx]# /usr/local/nginx/sbin/nginx -s reload
[root@proxy nginx]# wget 192.168.99.5/test.img  #每秒速度大约200k,看到结果之后ctrl C 即可

3)定义用户访问不同内容时速度不一样
[root@proxy nginx]# vim conf/nginx.conf
http {
...    
server {
...
    listen 80;
...
    location /file_a {      #用户file_a目录下的内容限速300k
        limit_rate 300k;        
    }
    location /file_b {      #用户访问file_b目录下的内容不限速
        limit_rate 0k;          
    }
...
[root@proxy nginx]# /usr/local/nginx/sbin/nginx -s reload

2)创建测试目录
[root@proxy nginx]# mkdir html/file_a
[root@proxy nginx]# mkdir html/file_b

3)拷贝测试文件
[root@proxy nginx]# cp html/test.img html/file_a/
[root@proxy nginx]# cp html/test.img html/file_b/

4)下载测试
[root@proxy nginx]# wget 192.168.99.5/file_a/test.img   #每秒速度大约300k,看到结果之后ctrl C 即可
[root@proxy nginx]# wget 192.168.99.5/file_b/test.img   #不限速,以电脑最快的速度下载

此时会有一个问题,用户在浏览器开两个页面分别下载file_a(300k限速) 的内容,两个下载页面约600k的限速,但是配置文件中是没有600k的限速的,如果要解决这个问题,修改用户访问连接限制

连接限制(非必须配置)
修改用户访问连接限制,使一个客户同时打开多个连接也无法突破限制
[root@proxy nginx]# vim conf/nginx.conf
...
http {
...    
limit_rate 100k;       		 #全局限速,速度限制100k,最大100k的速度传输数据
limit_conn_zone $binary_remote_addr zone=addr:10m;  #limit_conn_zone连接限制,控制连接数,
													#$binary_remote_addr是nginx的内置变量,获取客户的地址,
													#ip存储到addr文件中,空间为10m
server {
    listen 80;
...
    location /file_a {      #用户file_a目录下的内容限速300k
        limit_rate 300k;
        limit_conn addr 1;  #file_a目录下的文件只能下载一个,开多个页面不能下载
    }
...
[root@proxy nginx]# /usr/local/nginx/sbin/nginx -s reload

五、Nginx实现跨域

  • 跨域浏览器基于同源策略:当网页请求不同协议、域名或端口的资源时,会拦截服务器返回的数据,禁止当前页面读取。通过配置Nginx的 CORS策略 解除游览器的跨域拦截(面题)
  • 同源策略:限制一个源的网页只能访问同源的资源,禁止访问不同源的数据。

核心参数: add_header 'Access-Control-Allow-Origin'(CORS策略):服务器响应数据中添加允许跨域访问

两个 URL 必须同时满足以下三个条件才算同源:

条件 说明 示例
协议相同 http / https http:// vs https:// ❌
域名相同 主域名一致 example.com vs api.com
端口相同 80 / 443 / 其他 :80 vs :8080 ❌
rust 复制代码
创建2个虚拟主机,一个80端口(这个用默认配置即可),一个8080端口
1)为proxy主机的添加8080虚拟主机
[root@proxy ~]# cd /usr/local/nginx
[root@proxy nginx]# cp conf/nginx.conf.default conf/nginx.conf  #恢复配置文件
[root@proxy nginx]# vim conf/nginx.conf
...
server {
listen 8080;
root html;
index index.html;
}
server {
listen 80;
...
[root@proxy nginx]# /usr/local/nginx/sbin/nginx  -s reload

2)创建2个测试页面
[root@proxy nginx]# echo 8080 ok > html/api.html
自己测试自己
[root@proxy nginx]# curl 192.168.99.5/api.html
8080 ok
[root@proxy nginx]# curl 192.168.99.5:8080/api.html
8080 ok

使用浏览器测试:192.168.99.5/api.html,显示8080 ok
另外开一个浏览器的标签页测试:192.168.99.5:8080/api.html,显示8080 ok
此时都能正常访问,因为还没有进行跨域访问

3)使用跨域访问,此代码写好是有一个按钮
[root@proxy nginx]# vim html/press.html     #8080虚拟主机测试页面
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>API-test</title>
    <script>
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://192.168.99.5:8080/api.html',true);
        xhr.send();
        function change(){
            if(xhr.readyState==4 && xhr.status==200){
                alert(xhr.responseText);
            }
        }
    </script>
</head>
<body>
<input  id="button" type="button" value="测试" onclick="change();">
</body>

4)打开浏览器
访问http://192.168.99.5:8080/press.html,可以看到测试按钮,点击有显示8080 ok
访问http://192.168.99.5/press.html,点击按钮无反应,返回的数据被浏览器拦截,此时在8080虚拟主机中添加即可允许从任意地址请求8080的数据
[root@proxy nginx]# vim conf/nginx.conf
server {
listen 8080;
add_header 'Access-Control-Allow-Origin' '*';  #服务器响应数据中添加允许跨域访问,*代表任意
root html;
index index.html;
}
[root@proxy nginx]# /usr/local/nginx/sbin/nginx  -s reload

再次访问http://192.168.99.5/press.html,点击按钮即可看到8080 ok 的页面

5)修改具体允许请求的地址,增加安全
[root@proxy nginx]# vim conf/nginx.conf
server {
listen 8080;
add_header 'Access-Control-Allow-Origin' 'http://192.168.99.5';
root html;
index index.html;
}
[root@proxy nginx]# /usr/local/nginx/sbin/nginx  -s reload
重新访问http://192.168.99.5/press.html,点击按钮即可看到8080 ok 的页面
相关推荐
小小测试开发5 小时前
RAG检索评测实战:9种架构对比与自动化评估框架搭建
运维·人工智能·python·自动化
zzz_23686 小时前
智慧社区项目全维度测试报告:功能、接口、自动化与性能验证
运维·自动化
Brilliantwxx6 小时前
【Linux】基础指令
linux·运维·服务器
ZhemgLee6 小时前
在Linux上使用Claude Code 并使用本地VS Code SSH远程访问的完整指南
linux·运维·服务器·ssh
Yiiz.8 小时前
虚拟机网络设置
运维
乐维_lwops15 小时前
2026年如何实现多分支机构全网设备统一运维监控一
运维·cmdb·运维监控·网管·agent ops
视觉AI16 小时前
VS Code Remote-SSH 连接Jetson踩坑完整解决记录(网段不通+主机密钥变更双重故障)
运维·网络·人工智能·windows·ssh·边缘计算
银河麒麟操作系统16 小时前
闸机高效稳跑,通勤提速升级!银河麒麟赋能北京轨交新基建
运维·服务器·安全·交通物流
六点_dn17 小时前
Linux学习笔记-printf命令
linux·运维·算法