Nginx+lua+redis 实现微服务动态路由(openresty+redis)及redis带密码配置

一.下载软件包

1..echo-nginx-module 下载,是一个 Nginx 模块,提供直接在 Nginx 配置使用包括 "echo", "sleep", "time" 等指令。

wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz


 2.lua-nginx-module 下载。可在 Nginx 中嵌入 Lua 语言,让 Nginx 可以支持 Lua 强大的语法。

wget https://github.com/openresty/lua-nginx-module/archive/v0.10.12rc2.tar.gz


3.redis2-nginx-module 下载。是一个支持 Redis 2.0 协议的 Nginx upstream 模块,它可以让 Nginx 以非阻塞方式直接防问远方的 Redis 服务,同时支持 TCP 协议和 Unix Domain Socket 模式,并且可以启用强大的 Redis 连接池功能。

wget https://github.com/openresty/redis2-nginx-module/archive/v0.15rc1.tar.gz


4.set-misc-nginx-module 下载。是标准的HttpRewriteModule指令的扩展,提供更多的功能,如URI转义与非转义、JSON引述,Hexadecimal、MD5、SHA1、Base32、Base64编码与解码、随机数等等

wget https://github.com/openresty/set-misc-nginx-module/archive/v0.32rc1.tar.gz

 5.nginx 下载

wget http://nginx.org/download/nginx-1.14.0.tar.gz

二、编译安装

1.确认下目录位置   

[root@test01 ~]# ls

echo-nginx-module-0.61       nginx-1.14.0            redis2-nginx-module-0.15rc1

lua-nginx-module-0.10.12rc2    set-misc-nginx-module-0.32rc1

2.进入nginx-1.12.2 ,编译安装

安装依赖

yum install pcre-devel openssl-devel gcc curl lua lua-devel

yum 安装luajit-devel.x86_64

    ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_gzip_static_module --with-http_stub_status_module --with-http_ssl_module --with-file-aio --with-http_realip_module --add-module=../echo-nginx-module-0.61 --add-module=../redis2-nginx-module-0.15rc1 --add-module=../lua-nginx-module-0.10.12rc2 --add-module=../set-misc-nginx-module-0.32rc1

    make

注意:

若只是升级操作,则不需要make install ,若第一次安装,则需要make install

    a.升级操作


    cd /usr/local/nginx/sbin/

    mv nginx nginx.bak

    cd ~/objs/

    cp -rp  nginx /usr/local/nginx/sbin/

    kill -USR2 $(cat /var/run/nginx.pid)

    b.安装操作

     make install

调整nginx配置文件,编写启动脚本

3.redis插件安装

1)lua-resty-redis是openresty(1.9.15.1)的一个组件,简单来说,它提供一个lua语言版的redis API,使用socket(lua sock)和redis通信。(不需要)

mdkir /usr/local/nginx/lua  

cd /usr/local/nginx/lua

wget https://github.com/openresty/lua-resty-redis/archive/v0.26.tar.gz

tar -xf  v0.26.tar.gz

2)安装lua-redis-parser

wget  https://github.com/openresty/lua-redis-parser/archive/v0.13.tar.gz

tar -xvf v0.13.tar.gz

gmake CC=gcc

gmake install CC=gcc

cd /usr/local/lib/lua/5.1/redis/

cd ../..

cp -rp lua/ /usr/lib64/

4. redis 安装 (略过)

三.lua 脚本测试


首先,要解析并拆分URL字符串,各种百度和Google,需要写一段Lua代码,实现字符串按"/"拆分

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

其实就是定义了一个split_path函数。

然后我们将上面的Split.lua文件,配置到Nginx的配置文件中

/usr/local/nginx/conf/nginx.conf

 init_worker_by_lua_file "/usr/local/nginx/lua/split.lua"

编辑 vhost.conf 配置文件

server {

        listen 80;

        server_name test.xxxx.com;

        index index.html index.htm index.php;

        location = /redis {

            internal;

            set_unescape_uri $key $arg_key;

            redis2_query get $key;

            #redis2_query auth "mypaas";

            redis2_pass 172.16.197.72:6379;

        }

        location / {

            set $target '';

            access_by_lua '

        local parameters = split_path(ngx.var.uri)

        local action = parameters[1]

        if(#parameters == 0) then

                   ngx.exit(ngx.HTTP_FORBIDDEN)

        end

        local key = action

        local res = ngx.location.capture(

                    "/redis", { args = { key = key } }

        )

        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

        local parser = require "redis.parser"

        local server, typ = parser.parse_reply(res.body)

        if typ ~= parser.BULK_REPLY or not server then

                    ngx.log(ngx.ERR, "bad redis response: ", res.body)

                    ngx.exit(500)

        end

        if server == "" then

                    server = "test.paas.qjclouds.com"

        end

        ngx.var.target = server

       ';

       resolver 8.8.8.8;

       proxy_pass http://$target;

      proxy_set_header Host test.xxx.com;

     }

access_log /tmp/access.log;

    }

需求变更:

1. 访问域名的  重定向到某个页面

2.访问/xxx   重定向到 某个固定页面

3.访问/xxx/xxx/xxxx的重定向到 某个server并 把请求转发过去

4.访问到后端主机的请求,需要负载(负载地址 在redis value里面,并且以','分割)

更改 /usr/local/nginx/lua/split.lua文件为如下:

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

function split_arr(inputstr, sep)

        if sep == nil then

                sep = "%s"

        end

        local t={} ; i=1

        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do

                t[i] = str

                i = i + 1

        end

        return t

end

更改Nginx文件为:

    server {

        listen 80;

        server_name uatx.paas.xxx.com;

        index index.html index.htm index.php;

        location = /redis {

            internal;

            set_unescape_uri $key $arg_key;

            redis2_query get $key;

            redis2_pass 172.19.151.176:6379;

        }

        location / {

            set $target '';

            access_by_lua '

        local parameters = split_path(ngx.var.uri)

        local action = parameters[1]

        local action1 = parameters[2]

        local action2 = ngx.var.host

        if ngx.var.uri == "/" then

               res = ngx.location.capture(

                "/redis", { args = { key = "0_"..action2 } }

                )

              local parser = require "redis.parser"

              local dapeng, typ = parser.parse_reply(res.body)

           return ngx.redirect(dapeng)

        end

        if(#parameters == 0) then

                 ngx_log(ngx.ERR, "----------------------->")

                 ngx.exit(ngx.ERROR)

                   ngx.exit(ngx.HTTP_FORBIDDEN)

        end

        if action1 == nil then

 res = ngx.location.capture(

                    "/redis", { args = { key = "0_/paas/res" } }

                )

else

         res = ngx.location.capture(

                    "/redis", { args = { key = "0_/"..action.."/"..action1 } }

        )

        end

        if res.status ~= 200 then

                    ngx.exit(res.status)

        end

        if not res.body then

               res = ngx.location.capture(

                "/redis", { args = { key = "0_paas/res" } }

                )

        end

        local parser = require "redis.parser"

        local server, typ = parser.parse_reply(res.body)

        if typ ~= parser.BULK_REPLY or not server then

                    return ngx.redirect("/paas/res")

        end

        if server == "" then

                    server = "uat.paas.qjclouds.com"

        end

        if server == "" then

                    server = "uat.paas.qjclouds.com"

        end

        local more = server

        local have = split_arr(more, ",")

        ngx.var.target = have[math.random(1,#have)]

       ';

       resolver 8.8.8.8;

       proxy_pass http://$target;

      proxy_set_header Host $host;

      proxy_set_header  X-Real-IP        $remote_addr;

     proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;

     }

access_log /tmp/access.log;

error_log /tmp/access.log;

    }

https配置

a.配置重定向

server {

  listen 0.0.0.0:80;

  #listen [::]:80 ipv6only=on default_server;

  server_name mp.xytest.qjclouds.com;

  server_tokens off; ## Don't show the nginx version number, a security best practice

#location ~ ^/.well-known {

#root /tmp;

#}

  return 301 https://$http_host$request_uri;

}

2.配置https  

server {

        listen 443;

server_tokens off;

        server_name mp.xytest.qjclouds.com;

        index index.html index.htm index.php;

add_header Access-Control-Allow-Origin "*";

        ssl                  on;    

        ssl_certificate      vhosts/ssl/mp.xytest.qjclouds.com.pem;

        ssl_certificate_key  vhosts/ssl/mp.xytest.qjclouds.com.key;    

        #ssl_ciphers  HIGH:!aNULL:!MD5;    

        ssl_prefer_server_ciphers   on;    

        ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 SSLv2 SSLv3;   

        ssl_session_cache shared:SSL:10m;   

        ssl_session_timeout 5m;

        location = /redis {

            internal;

            set_unescape_uri $key $arg_key;

            redis2_query get $key;

            redis2_pass 10.68.0.16:6379;

        }

        location / {

            set $target '';            


            access_by_lua '

        local parameters = split_path(ngx.var.uri)

        local action = parameters[1]

        local action1 = parameters[2]

        local action2 = ngx.var.host

        if ngx.var.uri == "/" then

               res = ngx.location.capture(

                "/redis", { args = { key = "0_"..action2 } }

                )

              local parser = require "redis.parser"

              local dapeng, typ = parser.parse_reply(res.body)

           return ngx.redirect(dapeng)

        end

        if(#parameters == 0) then

                 ngx_log(ngx.ERR, "----------------------->")

                 ngx.exit(ngx.ERROR)

                   ngx.exit(ngx.HTTP_FORBIDDEN)

        end

        if action1 == nil then 

 res = ngx.location.capture(

                    "/redis", { args = { key = "0_/paas/res" } }

                )


else 

         res = ngx.location.capture(

                    "/redis", { args = { key = "0_/"..action.."/"..action1 } }

        )

        end

        if res.status ~= 200 then

                    ngx.exit(res.status)

        end

        if not res.body then

               res = ngx.location.capture(

                "/redis", { args = { key = "0_paas/res" } }

                )

        end

        local parser = require "redis.parser"

        local server, typ = parser.parse_reply(res.body)

        if typ ~= parser.BULK_REPLY or not server then

                    return ngx.redirect("/paas/res")

        end

        if server == "" then

                    server = "uatb.ress.qjclouds.com"

        end

        ngx.var.target = server

       ';

       resolver 8.8.8.8;               

       proxy_pass http://$target;

      proxy_set_header Host $host;

      proxy_set_header  X-Real-IP        $remote_addr;  

     proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for; 

     }

access_log /usr/local/nginx/logs/access.log access;

error_log /usr/local/nginx/logs/error.log;

    }

redis 带密码的配置:

实现思路,

因为每次auth之后,会有返回ok,但是不需要返回OK ,还是返回之前的值的样子,故重新编辑返回值,只返回之前的key的形式,具体实现方式如下:

    server {

        listen 80;

        server_name *.xingyun.xxx.com;

        index index.html index.htm index.php;

        location = /redis {

            internal;

    redis2_raw_queries $args $echo_request_body;

            redis2_pass 127.0.0.1:6382;

        }

        location / {

            set $target '';            


            access_by_lua '

        local parameters = split_path(ngx.var.uri)

        local action = parameters[1]

        local action1 = parameters[2]

        local action2 = ngx.var.host

        function LsReadis(key)

          local parser = require "redis.parser"

          local reqs = {

             {"auth", "mima"},

             {"get", key}

                }  

  local raw_reqs = {}

 for i, req in ipairs(reqs) do

table.insert(raw_reqs, parser.build_query(req))

  end

   local res = ngx.location.capture("/redis?" .. #reqs,

     { body = table.concat(raw_reqs, "") })

  if res.status ~= 200 or not res.body then

     ngx.log(ngx.ERR, "failed to query redis")

     ngx.exit(500)

   end

   replies = parser.parse_replies(res.body, #reqs)

     return replies[2][1]

        end

        if ngx.var.uri == "/" then

    if LsReadis("0_"..action2) == nil then

    ngx.exit(501)

    else

            return ngx.redirect(LsReadis("0_"..action2))

    end

        end

        ----判断paas后是否为空

        if action1 == nil then

        key = "0_paas/res"

        else

        key = "0_/"..action.."/"..action1

        end

       ----空值重定向

server = LsReadis(key)

        if not server or server == nil then

local key = "0_paas/res"

server = LsReadis(key)

        end

       ----redis 连接或取值失败

       if server == "" then

          server = "uatb.xingyun.qjclouds.com"

        end

       ngx.var.target = server

       ';

       resolver 8.8.8.8;

       proxy_pass http://$target;

       proxy_set_header Host $host;

       proxy_set_header  X-Real-IP        $remote_addr;

       proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;

}

access_log /usr/local/nginx/logs/test.log access;

error_log /usr/local/nginx/logs/test.log;

    }

你可能感兴趣的:(Nginx+lua+redis 实现微服务动态路由(openresty+redis)及redis带密码配置)