Docker?安裝Nginx與配置Nginx的案例
前言
1.什么是nginx
Nginx (engine x) 是一個高性能的HTTP和反向代理web服務(wù)器,ginx是一款輕量級的Web 服務(wù)器/反向代理服務(wù)器及電子郵件(IMAP/POP3)代理服務(wù)器,在BSD-like 協(xié)議下發(fā)行。其特點(diǎn)是占有內(nèi)存少,并發(fā)能力強(qiáng),事實(shí)上nginx的并發(fā)能力確實(shí)在同類型的網(wǎng)頁服務(wù)器中表現(xiàn)較好
2.為什么使用nginx
在傳統(tǒng)的Web項目中,并發(fā)量小,用戶使用的少。所以在低并發(fā)的情況下,用戶可以直接訪問tomcat服務(wù)器,然后tomcat服務(wù)器返回消息給用戶。
用戶訪問<-->Tomcat服務(wù)器
而在互聯(lián)網(wǎng)項目下,因單個tomcat默認(rèn)并發(fā)量有限制。如果請求量過大,會產(chǎn)生如下問題:
Tomcat8 默認(rèn)配置的最大請求數(shù)是 150,也就是說同時支持 150 個并發(fā),當(dāng)然了,也可以將其改大。
當(dāng)某個應(yīng)用擁有 250 個以上并發(fā)的時候,應(yīng)考慮應(yīng)用服務(wù)器的集群。
具體能承載多少并發(fā),需要看硬件的配置,CPU 越多性能越高,分配給 JVM 的內(nèi)存越多性能也就越高,但也會加重 GC 的負(fù)擔(dān)。
操作系統(tǒng)對于進(jìn)程中的線程數(shù)有一定的限制:
Windows 每個進(jìn)程中的線程數(shù)不允許超過 2000
Linux 每個進(jìn)程中的線程數(shù)不允許超過 1000
Tomcat的最大并發(fā)數(shù)是可以配置的,實(shí)際運(yùn)用中,最大并發(fā)數(shù)與硬件性能和CPU數(shù)量都有很大關(guān)系的。更好的硬件,更多的處理器都會使Tomcat支持更多的并發(fā)。
maxThreads="150" 最大并發(fā)數(shù)
minSpareThreads="10"///初始化時創(chuàng)建的線程數(shù)
maxSpareThreads="500"///一旦創(chuàng)建的線程超過這個值,Tomcat就會關(guān)閉不再需要的socket線程。
3.高并發(fā)
是互聯(lián)網(wǎng)分布式系統(tǒng)架構(gòu)設(shè)計中必須考慮的因素之一,它通常是指,通過設(shè)計保證系統(tǒng)能夠同時并行處理很多請求。
高并發(fā)相關(guān)常用的一些指標(biāo)有響應(yīng)時間(Response Time),吞吐量(Throughput),每秒查詢率QPS(Query Per Second),并發(fā)用戶數(shù)等。
響應(yīng)時間: 系統(tǒng)對請求做出響應(yīng)的時間。例如系統(tǒng)處理一個HTTP請求需要200ms,這個200ms就是系統(tǒng)的響應(yīng)時間。
吞吐量: 單位時間內(nèi)處理的請求數(shù)量。
QPS: 每秒響應(yīng)請求數(shù)。在互聯(lián)網(wǎng)領(lǐng)域,這個指標(biāo)和吞吐量區(qū)分的沒有這么明顯。
并發(fā)用戶數(shù): 同時承載正常使用系統(tǒng)功能的用戶數(shù)量。
高可用(High Availability)
通常來描述一個系統(tǒng)經(jīng)過專門的設(shè)計,從而減少停工時間,而保持其服務(wù)的高度可用性。
(一直都能用 99.9999%)
高性能:
是指服務(wù)響應(yīng)時間快,(CPU/處理器/內(nèi)存)特別是在高并發(fā)下響應(yīng)時間不會急劇增加。
4.Nginx特點(diǎn):
高并發(fā)、高性能,
可擴(kuò)展性好,
高可靠性,
熱部署,
BSD許可證。
對于反向代理和正向代理這篇文章講的很仔細(xì)了
正向代理和反向代理
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
一、docker安裝nginx
docker run -d --name mynginx --restart=always -v /home/nginx/nginx.conf:/etc/nginx/nginx.conf -v /home/nginx/default.conf:/etc/nginx/conf.d/default.conf -p 8080:80 -t nginx
提示:我是安裝在/home/nginx目錄下的,所以先建這個目錄 mkdir nginx。
-v
表示文件掛載,用法: -v 本地掛載文件:容器目標(biāo)文件。
-d
容器將在后臺以守護(hù)進(jìn)程的形式運(yùn)行,而不會阻塞終端。
–restart=always
運(yùn)行容器時使用–restart參數(shù)可以指定一個restart策略,來指示在退出時容器應(yīng)該如何重啟或不應(yīng)該重啟。
no – 容器退出時不要自動重啟。這個是默認(rèn)值。
on-failure[:max-retries] – 只在容器以非0狀態(tài)碼退出時重啟??蛇x的,可以退出docker daemon嘗試重啟容器的次數(shù)。
always – 不管退出狀態(tài)碼是什么始終重啟容器。當(dāng)指定always時,docker daemon將無限次數(shù)地重啟容器。容器也會在daemon啟動時嘗試重啟,不管容器當(dāng)時的狀態(tài)如何。
unless-stopped – 不管退出狀態(tài)碼是什么始終重啟容器,不過當(dāng)daemon啟動時,如果容器之前已經(jīng)為停止?fàn)顟B(tài),不要嘗試啟動它。
查看nginx版本可以通過命令 docker inspect nginx 查看
二、Nginx配置簡介
1.文件講解
文件掛載到本地后會看到兩個文件
default.conf nginx.conf
default.conf:
默認(rèn)的 nginx 配置文件
nginx.conf:
nginx的主配置文件,它包含了全局配置和一些默認(rèn)的設(shè)置,影響整個nginx服務(wù)器的行為,這個文件通常用于配置一些全局性的參數(shù)。
2.nginx.conf
cat nginx.conf
user nginx; #Nginx 主配置文件中的一個重要選項,用于指定 Nginx 服務(wù)器的工作進(jìn)程數(shù)。 #每個工作進(jìn)程都是一個獨(dú)立的 Nginx 進(jìn)程,用于處理客戶端請求 #Nginx 將根據(jù)可用的 CPU 核數(shù)動態(tài)確定工作進(jìn)程的數(shù)量。這樣可以更好地利用多核系統(tǒng)的性能。 #例如:worker_processes 4,配置4個線程 worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; #配置與連接處理相關(guān)的參數(shù),如最大連接數(shù) events { worker_connections 1024; } #配置 HTTP 服務(wù)器的參數(shù),設(shè)定http服務(wù)器,利用它的反向代理功能提供負(fù)載均衡支持 http { #引入其他配置文件,通常用于模塊化配置。在conf/mime.types查看支持哪些類型 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"'; access_log /var/log/nginx/access.log main; #是否使用sendfile傳輸文件 sendfile on; #tcp_nopush on; #連接超時時間 keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
3.default.conf
server { ##配置監(jiān)聽端口 listen 80; listen [::]:80; #配置服務(wù)器名 server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } #配置404頁面 #error_page 404 /404.html; # redirect server error pages to the static page /50x.html #配置50x頁面 error_page 500 502 503 504 /50x.html; #精確匹配 location = /50x.html { #root是配置服務(wù)器的默認(rèn)網(wǎng)站根目錄位置,在nginx目錄下html root /usr/share/nginx/html; } #這是轉(zhuǎn)發(fā)php腳本代理到127.0.0.1:80的Apache偵聽 # 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 # #禁止訪問 .htxxx 文件 #location ~ /\.ht { # deny all; #} }
三、nginx負(fù)載均衡
1.配置服務(wù)器列表地址
修改配置文件 vim default.conf注意:我們nginx容器啟動時-p 8080:80, 下面8001,8002,8003端口為別對應(yīng)的三個web容器服務(wù),也需要在啟動時映射端口到80端口,例如 -p 8001:80
upstream servercluster { server 127.0.0.1:8001; server 127.0.0.1:8002; server 127.0.0.1:8003; }
然后需要在 location / {…}中進(jìn)行配置
location / { #root /usr/share/nginx/html; #index index.html index.htm; proxy_pass http://servercluster; }
2.多集群策略
輪詢 | 默認(rèn)方式 |
---|---|
weight | 權(quán)重方式 |
ip_hash | 依據(jù)ip分配方式 |
least_conn | 最少連接方式 |
fair(第三方) | 響應(yīng)時間方式 |
url_hash(第三方) | 依據(jù)url分配方式 |
注意:在沒有配置情況下默認(rèn)輪詢策略
2.1 權(quán)重配置
例如:
#權(quán)重越大,命中概率更高 weight,可按照服務(wù)器資源來分配 upstream servercluster { server 127.0.0.1:8001 weight=5; server 127.0.0.1:8002 weight=3; server 127.0.0.1:8003 weight=2; }
2.2 ip_hash
指定負(fù)載均衡按照基于客戶端IP的分配方式,這個方法確保了相同的客戶端的請求一直發(fā)送到對應(yīng)的服務(wù)器,以保證session會話。這樣每個方可都固定訪問一個后端服務(wù)器,可以解決session不能跨服務(wù)器的問題。
例如:
#權(quán)重越大,命中概率更高 weight,可按照服務(wù)器資源來分配 upstream servercluster { ip_hash; # server 127.0.0.1:8001 weight=5; server 127.0.0.1:8002 weight=3; server 127.0.0.1:8003 weight=2; }
2.3 least_conn
把請求轉(zhuǎn)發(fā)給鏈接數(shù)較少的后端服務(wù)器。輪詢算法是把請求平均的轉(zhuǎn)發(fā)給各個后端,使它們的負(fù)載大致相同;但是有些請求占用的時間很長會導(dǎo)致其所在的后端負(fù)載較高。這種情況下,least_conn這種方式就可以達(dá)到更好的負(fù)載均衡效果
upstream servercluster { least_conn; #把請求轉(zhuǎn)發(fā)給鏈接數(shù)量較少的后端服務(wù)器 server 127.0.0.1:8001 weight=5; server 127.0.0.1:8002 weight=3; server 127.0.0.1:8003 weight=2; }
2.4 fair
按照服務(wù)端的響應(yīng)時間來分配請求,響應(yīng)時間短的有限分配
upstream servercluster { server 127.0.0.1:8001; server 127.0.0.1:8002; server 127.0.0.1:8003; fair; #實(shí)現(xiàn)響應(yīng)時間短的優(yōu)先分配 }
2.5 url_hash
按照訪問url的hash結(jié)果來分配請求,使用每個url定向到同一個后端服務(wù)器,要配合緩存命中來使用。同一個資源多次請求,可能會達(dá)到不同的服務(wù)器上,導(dǎo)致不必要的多次下載,緩存命中率不高,以及一些資源時間的浪費(fèi)。而使用url_hash可以使用同一個url(也就是同一個資源請求)會到達(dá)同一臺服務(wù)器,一旦緩存了資源,再次收到請求,就可以從緩存中獲取
upstream servercluster { hash $request_url server 127.0.0.1:8001; server 127.0.0.1:8002; server 127.0.0.1:8003; }
3.nginx緩存配置
通過命令進(jìn)入到nginx容器中,docker exec -it mynginx bash。
在 /etc/nginx文件夾下建立一個data文件夾用于做nginx緩存。
然后再本地關(guān)在文件的主配置文件配置緩存目錄經(jīng)
proxy_cache_path /etc/nginx/data levels=1:2
keys_zone=web_cache:50m inactive=1m max_size=1g
levels:表示有兩層文件夾
keys_zone:之情緩存key和緩存50m
max_size:緩存最大1g
然后還需要配置default.conf 開啟反向代理數(shù)據(jù)
proxy_store off; #反向代理數(shù)據(jù)
proxy_redirect off;
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://servercluster;
proxy_cache web_cache;
proxy_cache_valid 200 304 2m; #響應(yīng)200 304 進(jìn)行緩存
proxy_cache_key s c h e m e scheme schemeproxy_host$request_uri; #使用當(dāng)前url地址作為當(dāng)前緩存key
注意:修改任何配置文件后都需要重啟nginx容器 docker restart mynginx
最終呈現(xiàn)文件
四 nginx路由規(guī)則
1.匹配格式
這個"/" 表示的是匹配路由規(guī)則進(jìn)行路由轉(zhuǎn)發(fā)的。
我們可以在里面寫過個location進(jìn)行路由匹配:
符號 | 規(guī)則 |
---|---|
= | 開頭表示精準(zhǔn)匹配 |
~ | 大小寫敏感 |
~* | 忽略大小寫 |
^~ | 只需匹配url開頭 |
@ | 定義一個命名的location,在內(nèi)部定向時使用 |
location [ = | ~* | ^~ ] /url/ {…}
location @name {…}
規(guī)則使用匹配方式如下:
deny,設(shè)置禁止訪問的IP
#禁止IP:192.168.1.1訪問 location / { deny 192.168.1.1; }
#禁止所有IP訪問 location / { deny all; }
allow,設(shè)置允許訪問的IP
#只允許IP:192.168.1.1訪問 location / { allow 192.168.1.1; }
#允許所有IP訪問 location / { allow all; }
deny和allow的優(yōu)先級
nginx的權(quán)限指令是從上往下執(zhí)行的,在同一個塊下deny和allow指令同時存在時,誰先匹配誰就會起作用,后面的權(quán)限指令就不會執(zhí)行了。如下圖,如果 “deny 111.111.111.111” 觸發(fā)了,那它后面的兩條都不會觸發(fā)。
location / { deny 192.168.1.1; allow 192.168.1.2; deny 192.168.1.3; }
其實(shí)他們的關(guān)系就像 “if…else if…else if”,誰先觸發(fā),誰起作用。
if (deny 192.168.1.1) {...} else if (allow 192.168.1.2) {...} else if (deny 192.168.1.3) {...}
2.location匹配優(yōu)先級
在配置中需要注意的一點(diǎn)就是location的匹配規(guī)則和優(yōu)先級
- = 開頭表示精確匹配
- ^~ 開頭表示url以某個常規(guī)字符串開頭,不是正則匹配;
- ~ 開頭表示區(qū)分大小寫的正則匹配
- ~* 開頭表示不區(qū)分大小的正則匹配
- / 通用匹配,如果沒有其他匹配,任何請求都會匹配到;
3.location的匹配流程
1.、判斷是否精準(zhǔn)匹配,如果匹配,直接返回結(jié)果并結(jié)束搜索匹配過程
2.、判斷是否普通匹配,如果匹配,看是否包含^~前綴,包含則返回,否則記錄匹配結(jié)果location時返回或記錄最長匹配的那個
3.、判斷是否正則匹配,按配置文件里的正則表達(dá)式的順序,由上到下開始匹配,一旦匹配結(jié)果成功,并結(jié)束搜索匹配過程.
4.、如果正則匹配沒有匹配到結(jié)果,則返回步驟2記錄的匹配結(jié)果
五、 nginx頁面攔截
在請求通過nginx的時候,在針對某些場景的使用做特殊處理,比如錯誤頁面,返回指定錯誤頁,例如:
當(dāng)前默認(rèn)是在無法響應(yīng)對應(yīng)請求的情況下,默認(rèn)在/usr/share/nginx/html文件下找到50x.html文件,返回頁面50x.html
既然是可以配置,我們也可以將自定義的文件復(fù)制到對應(yīng)的目錄下面在進(jìn)行配置。
使用docker cp /url/xxx.html 容器名:ngnix docker中的目標(biāo)文件下,在修改配置成對應(yīng)的文件名稱
六、 nginx動靜分離
對于前端的項目:可以是一個靜態(tài)服務(wù)器或資源池; --可以吧各種靜態(tài)文件都匹配到nginx中,可以直接請求nginx可以響應(yīng)不同頁面
對于后端項目:做反向代理;
動靜分離:需要動態(tài)的時候,就做轉(zhuǎn)發(fā)請求,需要靜態(tài)的時候,就直接返回靜態(tài)頁面(直接響應(yīng)我們的結(jié)果)
需求場景:在客戶端發(fā)起請求時,nginx會轉(zhuǎn)發(fā)到服務(wù)器服務(wù)器然后返回一個靜態(tài)文件,如果反復(fù)請求相同靜態(tài)文件都需要去轉(zhuǎn)發(fā)到服務(wù)器,就會增加開銷,性能降低,我們就可以將靜態(tài)文件報錯到nginx中,下次請求就直接返回。
基于.net6解決方式:
1.需要寫一個生成靜態(tài)文件的中間件,保存到指定目錄,在項目通過docker啟動時掛載到宿主機(jī)文件夾下
app.UseStaticPage("/app/data/staticfile", true, true);
/// <summary> /// Middleware /// </summary> public class StaticPageMiddleware { private readonly RequestDelegate _next; private string _directoryPath = null; private bool _supportDelete = false; private bool _supportWarmup = false; public StaticPageMiddleware(RequestDelegate next, string directoryPath, bool supportDelete, bool supportWarmup) { this._next = next; this._directoryPath = directoryPath; this._supportDelete = supportDelete; this._supportWarmup = supportWarmup; } /// <summary> /// 任意HTTP請求,都要經(jīng)過這個方法 /// /// 如何抓到響應(yīng),并保存成HTML靜態(tài)頁 /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task InvokeAsync(HttpContext context) { if (context.Request.Path.Value!.StartsWith("/item/"))//規(guī)則支持自定義 { Console.WriteLine($"This is StaticPageMiddleware InvokeAsync {context.Request.Path.Value}"); #region context.Response.Body var originalStream = context.Response.Body; using (var copyStream = new MemoryStream()) { context.Response.Body = copyStream; await _next(context);//后續(xù)的常規(guī)流程,正常請求響應(yīng) copyStream.Position = 0; var reader = new StreamReader(copyStream); var content = await reader.ReadToEndAsync(); string url = context.Request.Path.Value; this.SaveHtml(url, content); copyStream.Position = 0; await copyStream.CopyToAsync(originalStream); context.Response.Body = originalStream; } #endregion } else { await _next(context); } } private void SaveHtml(string url, string html) { try { if (string.IsNullOrWhiteSpace(html)) return; if (!url.EndsWith(".html")) return; if (Directory.Exists(_directoryPath) == false) Directory.CreateDirectory(_directoryPath); var totalPath = Path.Combine(_directoryPath, url.Split("/").Last()); File.WriteAllText(totalPath, html);//直接覆蓋 } catch (Exception ex) { Console.WriteLine(ex.Message); } } /// <summary> /// 刪除某個頁面 /// </summary> /// <param name="url"></param> /// <param name="index"></param> private void DeleteHmtl(string url) { try { if (!url.EndsWith(".html")) return; var totalPath = Path.Combine(_directoryPath, url.Split("/").Last()); File.Delete(totalPath);//直接刪除 } catch (Exception ex) { Console.WriteLine($"Delete {url} 異常,{ex.Message}"); } } /// <summary> /// 清理文件,支持重試 /// </summary> /// <param name="index">最多重試次數(shù)</param> private void ClearDirectory(int index) { if (index > 0) { try { var files = Directory.GetFiles(_directoryPath); foreach (var file in files) { File.Delete(file); } } catch (Exception ex) { Console.WriteLine($"ClearDirectory failed {ex.Message}"); ClearDirectory(index--); } } } } /// <summary> /// 擴(kuò)展中間件 /// </summary> public static class StaticPageMiddlewareExtensions { /// <summary> /// /// </summary> /// <param name="app"></param> /// <param name="directoryPath">文件寫入地址,文件夾目錄</param> /// <param name="supportDelete">是否支持刪除</param> /// <param name="supportClear">是否支持全量刪除</param> /// <returns></returns> public static IApplicationBuilder UseStaticPage(this IApplicationBuilder app, string directoryPath, bool supportDelete, bool supportClear) { return app.UseMiddleware<StaticPageMiddleware>(directoryPath, supportDelete, supportClear); } }
2.nginx也需要通過掛載將項目掛載在宿主機(jī)的靜態(tài)文件也掛載到nginx的docker容器中,然后通過修改配置來指定對應(yīng)的靜態(tài)文件
OK!?。。。。。。。。。。。?/p>
總結(jié)
nginx主要的就是一個配置,如有補(bǔ)充或者有差異的地方,麻煩再評論下面指出,共勉!?。。?!
到此這篇關(guān)于Docker 安裝Nginx與配置Nginx的文章就介紹到這了,更多相關(guān)Docker 安裝Nginx內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
docker快速安裝Es和kibana的實(shí)現(xiàn)步驟
在工作過程中,經(jīng)常需要測試環(huán)境搭建Es環(huán)境,本文主要介紹了docker快速安裝Es和kibana,具有一定的參考價值,感興趣的可以了解一下2024-03-03Docker容器host與none網(wǎng)絡(luò)的使用
本文主要介紹了Docker容器host與none網(wǎng)絡(luò)的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>2022-06-06Docker四種網(wǎng)絡(luò)模式演示及連通性測試
這篇文章主要為大家介紹了Docker四種網(wǎng)絡(luò)模式演示及連通性測試,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04