OpenResty是什麼,官網是這樣介紹的:html
經過 Lua 擴展 NGINX 實現的可伸縮的 Web 平臺nginx
的確,OpenResty能夠簡單的理解爲Nginx + Lua,經過Lua庫引入數據庫訪問能力,真正的讓Nginx向搭建可以處理超高併發、擴展性極高的動態 Web 應用、Web 服務和動態網關這一目標邁出了重要的一步git
server {
listen 80;
# 以dvclab.com做爲主網站域名,徹底匹配
server_name ${hostname};
rewrite ^(.*)$ https://${hostname}$1 permanent;
}
server {
listen 443;
server_name ${hostname};
# ssl證書文件位置(常見證書文件格式爲:crt/pem)
ssl_certificate /etc/nginx/ssl/${hostname}.pem;
# ssl證書key位置
ssl_certificate_key /etc/nginx/ssl/${hostname}.key;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_prefer_server_ciphers on;
root /etc/nginx/dist;
index index.html index.htm;
}
複製代碼
/etc/nginx/dist
內便可,後續會使用Docker Compose的yaml配置文件作路徑映射server {
listen 80;
server_name ${hostname};
rewrite ^(.*)$ https://${hostname}$1 permanent;
}
server {
listen 443 ssl;
server_name ${hostname};
# ssl證書文件位置(常見證書文件格式爲:crt/pem)
ssl_certificate /etc/nginx/ssl/auth-cert.pem;
# ssl證書key位置
ssl_certificate_key /etc/nginx/ssl/auth-cert.key;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://${target}/;
}
}
複製代碼
/
hostname/users/1/info/2
轉發到hosname1:9200
,hostname/users/3/info/4
轉發到hostname2:8080
在/opt/openresty/lua/目錄下建立 split.luagithub
echo ' --[[ 拆分字符串 e.g. /a/b/c table[1] a table[2] b table[3] c --]] function split(str, pat) local t = {} local fpat = "(.-)" .. pat local last_end = 1 local s, e, cap = str:find(fpat, 1) while s do if s ~= 1 or cap ~= "" then table.insert(t, cap) end last_end = e + 1 s, e, cap = str:find(fpat, last_end) end if last_end <= #str then cap = str:sub(last_end) table.insert(t, cap) end return t end function split_path(str) return split(str, '[\\/]+') end ' > /opt/openresty/lua/split.lua
複製代碼
在/opt/openresty/lua/目錄下建立 query_redis.luaredis
echo ' -- redis結果解析,導入redis.parser腳本 local parser = require "redis.parser" -- ngx.var.uri只包含路徑參數,不包含主機與端口 -- 調用worker啓動時引入的lua腳本中提供的函數 local parameters = split_path(ngx.var.uri) -- 訪問的是根路徑 if(#parameters == 0) then ngx.exit(ngx.HTTP_FORBIDDEN) end -- 拆分出查詢參數 user_id = parameters[2] container_id = parameters[4] ngx.log(ngx.EMERG, "user_id--->", user_id) ngx.log(ngx.EMERG, "container_id--->", container_id) -- 組合參數 key = "DYNA" id = user_id .. "_" .. container_id -- 向redis查詢 res = ngx.location.capture( "/redis", { args = { key = key, id = id } } ) -- 查詢失敗 if res.status ~= 200 then ngx.log(ngx.ERR, "redis server returned bad status: ", res.status) ngx.exit(res.status) end -- 結果爲空 if not res.body then ngx.log(ngx.ERR, "redis returned empty body") ngx.exit(500) end -- raw tcp response from redis server -- 共2條返回因此應該使用parse_replies(res.body, 2) -- OK -- 172.17.144.4:8080 ngx.log(ngx.EMERG, "raw response ----->", res.body) local results = parser.parse_replies(res.body, 2) for i, result in ipairs(results) do if i == 2 then server = result[1] typ = result[2] end end -- 檢查結果類型 if typ ~= parser.BULK_REPLY or not server then ngx.exit(500) end -- 返回value爲空 if server == "" then server = "default.com" end ngx.var.target = server ngx.log(ngx.EMERG, "key--->", key) ngx.log(ngx.EMERG, "id--->", id) ngx.log(ngx.EMERG, "service--->", server) ' > /opt/openresty/lua/query_redis.lua
複製代碼
DYNA
爲key的hash表,hash表的key是由用戶請求中解析出的user_id和container_id使用_
組合而成,對應的value就是要轉發到的目標target在/opt/openresty/conf.d/目錄下建立dynamicRouter.confdocker
echo ' # 啓用主進程後,在每次Nginx工做進程啓動時運行指定的Lua代碼 init_worker_by_lua_file /usr/local/openresty/nginx/lua/split.lua; server { listen 443; server_name ${hostname}; # redis交互庫是openresty的內置的庫 location = /redis { # Specifies that a given location can only be used for internal requests internal; redis2_query auth ${redis_password}; # 解析請求參數 set_unescape_uri $id $arg_id; set_unescape_uri $key $arg_key; # 執行redis查詢請求 redis2_query hget $key $id; # 查詢請求轉發到指定的redis_server redis2_pass redis:6379; } location / { # 設置一個內嵌腳本的共享變量 set $target ''; # 引入內嵌腳本 access_by_lua_file /usr/local/openresty/nginx/lua/query_redis.lua; resolver 8.8.8.8; # 進行請求轉發(反向代理) proxy_set_header Host $host; proxy_set_header X-Forwarded-For $host; # 若是客戶端請求升級,將代理WebSocket proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'Upgrade'; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; # 最後的斜槓勿丟 proxy_pass http://$target/; } } > /opt/openresty/conf.d/dynamicRouter.conf 複製代碼
在部署OpenResty服務後,就能夠經過讀寫Redis的方式來實現動態路由轉發了shell
在shell命令行使用 docker exec命令結合redis-cli便可完成動態配置,舉例以下:數據庫
目的:將 /users/ {container_id} 映射到 {port}bash
docker exec -it or-redis /bin/bash
redis-cli --askpass
# 輸入redis密碼
hset DYNA ${user_id}_${container_id} ${host}:${port}
複製代碼
或者使用Redis-Java API 接口完成動態路由的設置服務器
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 增長可執行權限
sudo chmod +x /usr/local/bin/docker-compose
複製代碼
echo 'version: "3" services: redis: image: redis restart: always volumes: - /opt/redis/redis.conf:/etc/redis/redis.conf command: redis-server /etc/redis/redis.conf ports: - "61379:6379" container_name: or-redis openresty: image: openresty/openresty restart: always depends_on: - redis container_name: openresty volumes: - /opt/openresty/ssl/:/etc/nginx/ssl/ - /opt/openresty/conf.d/:/etc/nginx/conf.d/ - /opt/openresty/lua/:/usr/local/openresty/nginx/lua/ - /opt/static/:/etc/nginx/dist/ ports: - "443:443" - "80:80" ' > /etc/openresty/openresty.yaml
docker-compose -f /opt/openresty.yaml up -d
複製代碼
/opt/openresty/ssl/
目錄是用來放域名的HTTPS證書的,固然也可使用更方便的Let's Encrypt
服務,可參考使用lua-resty-auto-ssl