一、Nginx介紹
1.1引言
為什么要學(xué)習(xí)
Nginx
問(wèn)題1:客戶端到底要將請(qǐng)求發(fā)送給哪臺(tái)服務(wù)器
問(wèn)題2:如果所有客戶端的請(qǐng)求都發(fā)送給了服務(wù)器1
問(wèn)題3:客戶端發(fā)送的請(qǐng)求可能是申請(qǐng)動(dòng)態(tài)資源的,也有申請(qǐng)靜態(tài)資源的服務(wù)器搭建集群后
- 在搭建集群后,使用
Nginx
做反向代理
1.2 Nginx介紹
Nginx
是由俄羅斯人研發(fā)的,應(yīng)對(duì) Rambler
的網(wǎng)站并發(fā),并且2004年發(fā)布的第一個(gè)版本
Nginx
的特點(diǎn)
- 穩(wěn)定性極強(qiáng),7*24小時(shí)不間斷運(yùn)行 (一直運(yùn)行)
-
Nginx
提供了非常豐富的配置實(shí)例 - 占用內(nèi)存小,并發(fā)能力強(qiáng) (隨便配置一下就是5w+,而
tomcat
的默認(rèn)線程池是150)
二、Nginx的安裝
2.1安裝 Nginx
- 使用
docker-compose
安裝
在/home
目錄下創(chuàng)建docker_nginx
目錄
[root@VM-0-6-centos home]# mkdir docker_nginx
- 創(chuàng)建
docker-compose.yml
文件并編寫下面的內(nèi)容,保存退出vim docker-compose.yml
version: '3.9'
services:
nginx:
restart: always
image: nginx:latest // 拉取鏡像
container_name: nginx // 設(shè)置容器名稱
ports:
- 80:80
- 執(zhí)行
docker-compose up -d
[root@VM-0-6-centos docker_nginx]# docker-compose up -d
Starting nginx ... done
-
訪問(wèn)80端口,看到下圖說(shuō)明安裝成功(輸入自己服務(wù)器的Ip就可以訪問(wèn)80端口了)
2.2 Nginx的配置文件
- 查看當(dāng)前
nginx
的配置,需要進(jìn)入docker
容器中
[root@VM-0-6-centos docker_nginx]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24aa71edacb5 nginx:latest "/docker-entrypoint.…" 9 minutes ago Up 3 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp nginx
[root@VM-0-6-centos docker_nginx]# docker exec -it 24a bash
root@24aa71edacb5:/#
- 進(jìn)入容器后
root@24aa71edacb5:/# cd /etc/nginx/ // nginx 配置文件目錄
root@24aa71edacb5:/etc/nginx# cat nginx.conf
-
nginx.conf
文件內(nèi)容如下
user nginx;
worker_processes auto; // 數(shù)值越大,Nginx的并發(fā)能力就越強(qiáng)
error_log /var/log/nginx/error.log notice; // Nginx錯(cuò)誤日志存放的位置
pid /var/run/nginx.pid; // Nginx運(yùn)行的一個(gè)標(biāo)識(shí)
# 以上統(tǒng)稱為全局塊
events {
worker_connections 1024; // 數(shù)值越大,Nginx的并發(fā)能力就越強(qiáng)
}
# events塊
http {
include /etc/nginx/mime.types; // 引入一個(gè)外部文件,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"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf; // 引入了 conf.d 目錄下,以 .conf 為結(jié)尾的配置文件
}
# http塊
-
conf.d
目錄下只有一個(gè)default.conf
文件,內(nèi)容如下:
# server塊
server {
listen 80; // Nginx監(jiān)聽(tīng)的端口號(hào)
listen [::]:80;
server_name localhost; // Nginx接受請(qǐng)求的IP
#access_log /var/log/nginx/host.access.log main;
# location塊
location / {
root /usr/share/nginx/html; // 將接受到的請(qǐng)求根據(jù)/usr/share/nginx/html去查找靜態(tài)資源
index index.html index.htm; // 默認(rèn)去上述的路徑中找到index.html或index.htm
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
2.3 修改 docker-compose
文件
root@24aa71edacb5:/etc/nginx/conf.d# exit // 退出容器
exit
[root@VM-0-6-centos docker_nginx]# docker-compose down // 停止 docker-compose
Stopping nginx ... done
Removing nginx ... done
Removing network docker_nginx_default
- 修改
docker-compose.yml
文件,掛載卷:
version: '3.9'
services:
nginx:
restart: always
image: nginx:latest
container_name: nginx
ports:
- 80:80
volumes:
- /home/docker_nginx/conf.d/:/etc/nginx/conf.d // 掛載卷
- 重新構(gòu)建容器
docker-compose build
[root@VM-0-6-centos docker_nginx]# docker-compose build
nginx uses an image, skipping
- 重新啟動(dòng)容器
[root@VM-0-6-centos docker_nginx]# docker-compose up -d
Creating network "docker_nginx_default" with the default driver
Creating nginx ... done
- 這時(shí)我們?cè)俅卧L問(wèn)80端口是訪問(wèn)不到的,因?yàn)槲覀冇成淞藬?shù)據(jù)卷之后,還沒(méi)有編寫
server
塊中的內(nèi)容
[root@VM-0-6-centos docker_nginx]# ls
conf.d docker-compose.yml
- 我們?cè)?
/home/docker_nginx/conf.d
下,新建default.conf
,并插入如下內(nèi)容:
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
- 重啟
nginx
:docker-compose restart
[root@VM-0-6-centos conf.d]# docker-compose restart
Restarting nginx ... done
- 這時(shí)我們?cè)僭L問(wèn)80端口,可以看到是訪問(wèn)成功的。
三、Nginx的反向代理
3.1正向代理和反向代理介紹
- 正向代理:
- 正向代理服務(wù)是由客戶端設(shè)立的
- 客戶端了解代理服務(wù)器和目標(biāo)服務(wù)器都是誰(shuí)
- 幫助咱們實(shí)現(xiàn)突破訪問(wèn)權(quán)限,提高訪問(wèn)的速度,對(duì)目標(biāo)服務(wù)器隱藏客戶端的ip地址
- 反向代理:
- 反向代理服務(wù)器是配置在服務(wù)端的
- 客戶端不知道訪問(wèn)的到底是哪一臺(tái)服務(wù)器
- 達(dá)到負(fù)載均衡,并且可以隱藏服務(wù)器真正的ip地址
3.2 基于Nginx實(shí)現(xiàn)反向代理
準(zhǔn)備一個(gè)目標(biāo)服務(wù)器:?jiǎn)?dòng)
tomcat
服務(wù)器,編寫nginx
的配置文件(/home/docker_nginx/conf.d/default.conf)
,通過(guò)Nginx
訪問(wèn)到tomcat
服務(wù)器-
準(zhǔn)備
tomcat
服務(wù)器,-
docker-compose
方式 查看鏈接 - 手動(dòng)方式
-
docker run -d -p 8080:8080 --name tomcat tomcat
#或者已經(jīng)下載了tomcat鏡像
docker run -d -p 8080:8080 --name tomcat 鏡像的標(biāo)識(shí)
#添加數(shù)據(jù)卷
docker run -it -v /宿主機(jī)絕對(duì)目錄:/容器內(nèi)目錄 鏡像名
- 編寫
default.conf
文件,內(nèi)容如下:
server {
listen 80;
listen [::]:80;
server_name localhost;
# 基于反向代理訪問(wèn)到 tomcat 服務(wù)器
location / {
proxy_pass http://ip:8080/; // tomcat服務(wù)器的IP和端口
}
}
- 重啟
nginx
[root@VM-0-6-centos docker_nginx]# docker-compose restart
Restarting nginx ... done
- 這時(shí)我們?cè)L問(wèn)
80
端口,可以看到8080
端口tomcat
的默認(rèn)首頁(yè)
3.3 關(guān)于 Nginx 的 location 路徑映射
- 優(yōu)先級(jí)關(guān)系:
(location = )
>(location /xxx/yyy/zzz)
>(location ^~)
>(location ~,~*)
>(location /起始路徑)
>(location /)
- 精準(zhǔn)匹配
= /
location = / {
# 精準(zhǔn)匹配,主機(jī)名后面不能帶任何字符串
# 例如www.baidu.com不能是www.baidu.com/id=xxx
}
- 通用匹配
location /xxx {
# 匹配所有以/xxx開頭的路徑
# 例如127.0.0.1:8080/xxx xxx可以為空,為空則和=匹配一樣
}
- 正則匹配
location ~ /xxx {
# 匹配所有以 /xxx 開頭的路徑
}
- 匹配開頭路徑
location ^~ /xxx/xx {
# 匹配所有以/xxx/xx開頭的路徑
}
- 匹配結(jié)尾路徑
location ~* \.(gif/jpg/png)$ {
# 匹配以 .gif、.jpg 或者 .png 結(jié)尾的路徑
}
- 路徑映射測(cè)試:修改
/home/docker_nginx/conf.d/default.conf
如下
server {
listen 80;
listen [::]:80;
server_name localhost;
location /index {
proxy_pass http://ip:8081/; # tomcat 首頁(yè)
}
location ^~ /ceshi/ {
proxy_pass http://ip:8080/ceshi/; # 測(cè)試項(xiàng)目前臺(tái)首頁(yè)
}
location / {
proxy_pass http://ip:8080/Admin/; # 測(cè)試項(xiàng)目后臺(tái)首頁(yè)
}
}
- 重啟nginx
[root@VM-0-6-centos docker_nginx]# docker-compose restart
Restarting nginx ... done
- 訪問(wèn)
http://ip/index
可以進(jìn)入tomcat
首頁(yè) - 訪問(wèn)
http://ip/ceshi/XXX
可以進(jìn)入測(cè)試項(xiàng)目前臺(tái)首頁(yè) - 訪問(wèn)
http://ip 或者 http://ip:80
可以進(jìn)入測(cè)試項(xiàng)目后臺(tái)首頁(yè)
四、Nginx 負(fù)載均衡
-
Nginx
為我們默認(rèn)提供了三種負(fù)載均衡的策略:- 輪詢: 將客戶端發(fā)起的請(qǐng)求,平均分配給每一臺(tái)服務(wù)器
- 權(quán)重: 會(huì)將客戶端的請(qǐng)求,根據(jù)服務(wù)器的權(quán)重值不同,分配不同的數(shù)量
-
ip_hash
: 基于發(fā)起請(qǐng)求的客戶端的ip
地址不同,他始終會(huì)將請(qǐng)求發(fā)送到指定的服務(wù)器上,就是說(shuō)如果這個(gè)客戶端的請(qǐng)求的ip
地址不變,那么處理請(qǐng)求的服務(wù)器將一直是同一個(gè)
4.1 輪詢
- 想實(shí)現(xiàn)
Nginx
輪詢負(fù)載均衡機(jī)制只需要修改配置文件如下
upstream my-server{ # 輪詢方式:my-server 為自定義名稱(名稱不能用下劃線)
server ip:port; # 服務(wù)器地址1
server ip:port; # 服務(wù)器地址2
......
}
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
proxy_pass http://my-server/; # upstream的名稱
}
}
- 重啟
nginx
[root@VM-0-6-centos docker_nginx]# docker-compose restart
Restarting nginx ... done
- 多次刷新頁(yè)面,我們可以發(fā)現(xiàn)我們進(jìn)入的是不同的
tomcat
-
http://ip:8080
頁(yè)面
-
http://ip:8081
頁(yè)面
4.2 權(quán)重
- 實(shí)現(xiàn)權(quán)重的方式:在配置文件中
upstream
塊中加上weight
upstream my_server{
server ip:8080 weight=10; # weight 權(quán)重 10
server ip:8081 weight=2; # weight 權(quán)重 2
}
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
proxy_pass http://my_server/; # tomcat首頁(yè)
}
}
4.3 ip_hash
- 實(shí)現(xiàn)
ip_hash
方式:在配置文件upstream
塊中加上ip_hash;
upstream my_server{
ip_hash; # ip地址不變,始終訪問(wèn)同一臺(tái)服務(wù)器
server ip:8080;
server ip:8081;
}
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
proxy_pass http://my_server/; # tomcat首頁(yè)
}
}
五、Nginx 動(dòng)靜分離
-
Nginx
的并發(fā)能力公式:
worker_processes * worker_connections / 4 | 2 = Nginx 最終的并發(fā)能力
動(dòng)態(tài)資源需要/4
,靜態(tài)資源需要/2
Nginx
通過(guò)動(dòng)靜分離,來(lái)提升Nginx
的并發(fā)能力,更快的給用戶響應(yīng)
5.1 動(dòng)態(tài)資源代理
- 配置如下
location / {
proxy_pass 路徑;
}
5.2 靜態(tài)資源代理
- 配置如下
location / {
# root 靜態(tài)資源路徑;
root /usr/share/nginx/html;
# index 默認(rèn)訪問(wèn)路徑下是什么資源;
index index.html index.htm;
autoindex on; # 以列表的形式,展示靜態(tài)資源的全部?jī)?nèi)容
}
- 靜態(tài)資源測(cè)試
停止之前運(yùn)行的nginx
[root@VM-0-6-centos docker_nginx]# docker-compose down
Stopping nginx ... done
Removing nginx ... done
Removing network docker_nginx_default
- 修改
docker-compose.yml
添加靜態(tài)資源數(shù)據(jù)卷 不同版本的靜態(tài)資源位置可能不同,可以在 2.2 中查看默認(rèn)的位置(location
塊中root
后的路徑)
version: '3.9'
services:
nginx:
restart: always
image: nginx:latest
container_name: nginx
ports:
- 80:80
volumes:
- /home/docker_nginx/conf.d/:/etc/nginx/conf.d
- /home/docker_nginx/html/:/usr/share/nginx/html # 添加掛載靜態(tài)頁(yè)面數(shù)據(jù)卷
- 啟動(dòng)
nginx
[root@VM-0-6-centos docker_nginx]# docker-compose up -d
Creating network "docker_nginx_default" with the default driver
Creating nginx ... done
- 在
/home/docker_nginx/html
下新建一個(gè)index.html
,內(nèi)容隨意。
修改nginx
的配置文件
location /html { # 此處有 /html,后面可不用寫 /html,會(huì)直接訪問(wèn)到此目錄下
root /usr/share/nginx;
index index.html;
}
- 重啟
nginx
[root@VM-0-6-centos docker_nginx]# docker-compose restart
Restarting nginx ... done
- 訪問(wèn)如下:
六、Nginx 集群
6.1 引言
- 單點(diǎn)故障,為避免
nginx
的宕機(jī),導(dǎo)致整個(gè)程序的崩潰
準(zhǔn)備多臺(tái)nginx
準(zhǔn)備keepalived
,監(jiān)聽(tīng)nginx
的健康情況
準(zhǔn)備haproxy
,提供一個(gè)虛擬的路徑,統(tǒng)一的去接收用戶的請(qǐng)求
6.2 搭建
- 先準(zhǔn)備好以下文件放入
/home/docker_nginx_cluster
目錄中
-
Dockerfile
文件內(nèi)容如下:
FROM nginx:1.13.5-alpine
RUN apk update && apk upgrade
RUN apk add --no-cache bash curl ipvsadm iproute2 openrc keepalived # 用apk 安裝 keepalived
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"] # 運(yùn)行 entrypoint.sh 文件
-
entrypoint.sh
文件內(nèi)容如下:
#!/bin/sh
/usr/sbin/keepalived -D -f /etc/keepalived/keepalived.conf # 運(yùn)行 keepalived
nginx -g "daemon off;" # 運(yùn)行 nginx
-
docker-compose.yml
文件內(nèi)容如下:
version: "3.9"
services:
nginx_master: # 主機(jī)設(shè)置
build:
context: ./
dockerfile: ./Dockerfile
ports:
- 8081:80
volumes:
- ./index-master.html:/usr/share/nginx/html/index.html
- ./favicon.ico:/usr/share/nginx/html/favicon.ico
- ./keepalived-master.conf:/etc/keepalived/keepalived.conf
networks:
static-network: # 固定 IP 地址
ipv4_address: 172.20.128.2
cap_add:
- NET_ADMIN
nginx_slave: # 從機(jī)設(shè)置
build:
context: ./
dockerfile: ./Dockerfile
ports:
- 8082:80
volumes:
- ./index-slave.html:/usr/share/nginx/html/index.html
- ./favicon.ico:/usr/share/nginx/html/favicon.ico
- ./keepalived-slave.conf:/etc/keepalived/keepalived.conf
networks:
static-network:
ipv4_address: 172.20.128.3
cap_add:
- NET_ADMIN
proxy:
image: haproxy:1.7-alpine
ports:
- 80:6301
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
networks:
- static-network
networks:
static-network:
ipam:
config:
- subnet: 172.20.0.0/16
-
keepalived-master.conf
文件內(nèi)容如下:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
state MASTER # 主機(jī)
interface eth0 # 容器內(nèi)部的網(wǎng)卡名稱
virtual_router_id 33
priority 200 # 優(yōu)先級(jí)
advert_int 1
authentication {
auth_type PASS
auth_pass letmein
}
virtual_ipaddress {
172.20.128.50 # 虛擬地址,連接 haproxy
}
track_script {
chk_nginx
}
}
-
keepalived-slave.conf
文件內(nèi)容如下:
vrrp_script chk_nginx {
script "pidof nginx"
interval 2
}
vrrp_instance VI_1 {
state BACKUP # 從機(jī)
interface eth0 # 容器內(nèi)部的網(wǎng)卡名稱
virtual_router_id 33
priority 100 # 優(yōu)先級(jí),要低于主機(jī)
advert_int 1
authentication {
auth_type PASS
auth_pass letmein
}
virtual_ipaddress {
172.20.128.50 # 虛擬地址,連接 haproxy
}
track_script {
chk_nginx
}
}
-
haproxy.cfg
文件內(nèi)容如下:
global
log 127.0.0.1 local0
maxconn 4096
daemon
nbproc 4
defaults
log 127.0.0.1 local3
mode http
option dontlognull
option redispatch
retries 2
maxconn 2000
balance roundrobin
timeout connect 5000ms
timeout client 5000ms
timeout server 5000ms
frontend main
bind *:6301
default_backend webserver
backend webserver
server ngxin_master 172.20.128.50:80 check inter 2000 rise 2 fall 5
- 啟動(dòng)容器,注意確保
80
、8081
和8082
端口未被占用(或者修改docker-compose.yml
中的端口)
[root@VM-0-6-centos docker_nginx_cluster]# docker-compose up -d
- 訪問(wèn)
IP:8081
端口,可以看到master
頁(yè)面
- 訪問(wèn)
IP:8082
端口,可以看到slave
頁(yè)面
- 直接訪問(wèn)
80
端口,顯示的和8081
端口的頁(yè)面一致
因?yàn)槲覀冊(cè)O(shè)置了 8081
端口的 master
優(yōu)先級(jí)為 200
,比 8082
端口的 slave
優(yōu)先級(jí) 100
高,所以我們?cè)L問(wèn) 80
端口,看到的是 master
。
- 測(cè)試停止主機(jī):
docker stop docker_nginx_cluster_nginx_master_1
[root@VM-0-6-centos docker_nginx_cluster]# docker stop docker_nginx_cluster_nginx_master_1
docker_nginx_cluster_nginx_master_1
- 刷新頁(yè)面,顯示從機(jī)頁(yè)面
- 再次啟動(dòng)主機(jī)容器:
docker start docker_nginx_cluster_nginx_master_1
[root@VM-0-6-centos docker_nginx_cluster]# docker start docker_nginx_cluster_nginx_master_1
docker_nginx_cluster_nginx_master_1
- 刷新頁(yè)面,又返回主機(jī)頁(yè)面