Skip to content

ZigzagAK/ngx_api_gateway

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Nginx Api Gateway module

ngx_api_gateway is a dynamically configurable solution for routing requests.

Key features

  • Dynamically add and remove upstreams.
  • Dynamically modify routes between URLs and backends.
  • Synchronization with external registry.
  • Templating.
  • Environment may be used in configuration inventory.
  • Internal configuration persistent storage.

Build status

Build Status

Dependencies

Modules

Other

SQLite for persistance.

Status

Development.

Overview

Upstreams

You may dynamically add and remove upstreams to nginx in runtime without reloads.

This feature is very important because reloads of nginx needs to close all active connections and create another ones. Websockets and tcp streams may prevent fast reloads.

Routes

As you know, locations in nginx is a configuration time feature and routing can't be changed in runtime dynamically.

With dynamic routes you may add and remove routes based on prefix tree and regular expression patterns.

You may associate URLs to upstream in runtime without chaning nginx cnfiguration with REST without reloads.

Configurations is stored to internal sqlite database and on reload is loaded to nginx configuration.

Synchronization with external registry

Routes and upstreams configuration may be fetched from external http server and applied. Some of changes may needs to reload nginx.

Templating

For detailed templating possibilities you may look ngx_template_module.

Synopsis

env.template:

env {{name}};

env.yml:

---
env:
  - name: LISTEN_PORT

dynamic.template:

server {
    listen {{listen}} reuseport;

    default_type text/plain;

    location / {
        auth_request {{auth.request}};

        api_gateway_router_dynamic {{dynamic_var}}:5m;

        proxy_connect_timeout {{proxy.connect_timeout}};
        proxy_read_timeout {{proxy.read_timeout}};

        if ({{dynamic_var}} = '') {
            return 404 'No route';
        }

        proxy_pass {{proxy.protocol}}://{{dynamic_var}};
    }

    location = /auth_stub {
        internal;
        return 200;
    }
}

dynamic.yml:

---
dynamic:
  - name: dynamic_entrypoint1
    listen: "{{env(LISTEN_PORT1)|default(9000)}}"
    dynamic_var: $dynamic1
    auth:
      request: /auth_stub
    proxy:
      connect_timeout: 10s
      read_timeout: 60s
      protocol: http

  - name: dynamic_entrypoint2
    listen: "{{env(LISTEN_PORT2)|default(9001)}}"
    dynamic_var: $dynamic2
    auth:
      request: /auth_stub
    proxy:
      connect_timeout: 10s
      read_timeout: 60s
      protocol: http

check.temlate:

healthcheck passive type=http rise={{rise}} fall={{fall}} timeout={{timeout}} interval={{interval}};
healthcheck_request_uri {{request.method}} {{request.uri}};
healthcheck_response_codes {{response.codes}};
healthcheck_response_body {{response.match}};

check.yml:

---
check:
  - name: http
    rise: 1
    fall: 2
    timeout: 10000
    interval: 10
    request:
      method: GET
      uri: /healthz
    response:
      codes: 200 204
      match: .*

nginx.conf:

template keyfile=env.yml template=env.template;

http {
    upstream_conf_zone 8m;

    template keyfile=check.yml template=check.template;

    api_gateway_template keyfile=dynamic.yml template=dynamic.template;

    server {
        listen 8888;

        location = /healthcheck/get {
            healthcheck_get;
        }

        location = /healthcheck/status {
            healthcheck_status;
        }

        location = /route {
            api_gateway_route;
        }

        location = /dynamic {
            dynamic_upstream;
        }

        location = /upstream {
            upstream_conf;
        }
    }
}

For more examples look into example folder.

Dynamic upstreams

upstream_conf_zone

Syntax upstream_conf_zone
Default 8m
Context http

upstream_conf

Syntax upstream_conf
Default -
Context location

Add upstream

Method: POST

Arguments:

  • method - roundrobin, leastconn, ip_hash.
  • stream - add stream upstream.
  • keepalive - number of keepalived connections.
  • keepalive_requests - number of keepalived requests.
  • keepalive_timeout - timeout for keepalived connection.
  • dns_update - background synchronization hosts addresses by DNS in seconds. Looking for details in ngx_dynamic_upstream.

Example: curl -X POST 'localhost:6000/upstream?name=test&keepalive=600&keepalive_requests=10'.

Delete upstream

Method: DELETE

Example: curl -X DELETE 'localhost:6000/upstream?name=test'.

Get information about upstreams

Method: GET

Example: curl localhost:6000/upstream.

Output:

[
    {
        "keepalive": 600,
        "keepalive_requests": 10,
        "method": "roundrobin",
        "name": "test1",
        "type": "http"
    },
    {
        "keepalive": 600,
        "keepalive_requests": 10,
        "method": "roundrobin",
        "name": "test2",
        "type": "http"
    }
]

Dynamic routes

Dynamic routes is implemented via api_gateway_router_dynamic directive.

Declare dynamic router

Syntax api_gateway_router_dynamic <variable>:<mem>
Default -
Context http,location

Example:

location / {
    api_gateway_router_dynamic $backend:5m;
    proxy_pass http://$backend;

Routes associated with nginx variable, declared with api_gateway_router_dynamic directive.

route_conf

Syntax route_conf
Default -
Context location

Register location handler for setup new route, delete existing.

Add new route

Method: POST

Arguments:

  • backend - upstream name.
  • api - route. May be uri mask (/a/b/*/c/d) or regular expression.
  • var - variable name.

Example: curl -X POST localhost:8888/route?backend=app1&api=/a/b/*/c&var=$backend.

Delete route

Method: DELETE

Arguments:

  • api - route. May be uri mask (/a/b/*/c/d) or regular expression.
  • var - variable name.

Example: curl -X DELETE localhost:8888/route?api=/a/b/*/c&var=$backend.

Static routes

Static routes is implemented via api_gateway_router directive.

It injects backend's configuration into server or location.

Declare static router

Syntax api_gateway_router <variable>:<mem> <backends>
Default -
Context server,location

Example:

check.yml:

---
check:
  - name: http
    rise: 1
    fall: 2
    timeout: 10000
    interval: 10
    request:
      method: GET
      uri: /healthz
    response:
      codes: 200 204
      match: .*

backend.template:

upstream {{__group}}@{{name}} {
    zone shm_{{name}} 256k;

    dns_update {{dns.update}};
    dns_add_down on;

    {{servers}}

    check passive type=http rise={{check@http.rise}} fall={{check@http.fall}} timeout={{check@http.timeout}} interval={{check@http.interval}};
    check_request_uri {{check@http.request.method}} {{check@http.request.uri}};
    check_response_codes {{check@http.response.codes}};
    check_response_body {{check.response.match}};
}

backends.yml:

---
backends:

  - name: backend1
    api:
      - /app1/fun1
      - ~ ^/app3/fun2
      - /app1/fun3
      - /app1/*/hello/*
      - /app1/0000000
    dns:
      update: 60s
    server:
      max_conns: 10
      max_fails: 2
      fail_timeout: 30s
    upsync:
      interval: 60s
      timeout: 10s
    check:
      response:
        match: pong
    servers:
      - server 127.0.0.1:3333 max_conns={{server.max_conns}} max_fails={{server.max_fails}} fail_timeout={{server.fail_timeout}};
      - server 127.0.0.1:4444 max_conns={{server.max_conns}} max_fails={{server.max_fails}} fail_timeout={{server.fail_timeout}};

  - name: backend2
    api:
      - /app2/fun1
      - ~ ^/app2/fun2
      - /app2/fun3
      - /app2/*/hello/*
      - /app2/0000000
    dns:
      update: 60s
    server:
      max_conns: 10
      max_fails: 2
      fail_timeout: 30s
    upsync:
      interval: 60s
      timeout: 10s
    check:
      response:
        match: pong
    servers:
      - server 127.0.0.1:5555 max_conns={{server.max_conns}} max_fails={{server.max_fails}} fail_timeout={{server.fail_timeout}};
      - server 127.0.0.1:6666 max_conns={{server.max_conns}} max_fails={{server.max_fails}} fail_timeout={{server.fail_timeout}};

entrypoint.template:

server {
    listen {{listen}} reuseport;

    default_type text/plain;

    {{server.directives|default()}}

    {{server.locations|default()}}

    location / {
        auth_request {{auth.request}};

        {{location.directives|default()}}

        api_gateway_router $backend:1m {{backends}};

        proxy_connect_timeout {{proxy.connect_timeout}};
        proxy_read_timeout {{proxy.read_timeout}};

        proxy_pass {{proxy.protocol}}://$backend;
    }

    location = /auth_stub {
        internal;
        return 200;
    }
}

entrypoints.yml:

---
entrypoints:

  - name: app
    listen: 11111
    server:
      directives:
        - set $variable1 1;
        - set $variable2 2;
      locations:
        - location ~* ^/app1/.+\.(jpg|gif|png)$ { proxy_pass http://backends@backend1; }
        - location ~* ^/app2/.+\.(jpg|gif|png)$ { proxy_pass http://backends@backend2; }
    location:
      directives:
        - set $variable3 3;
        - set $variable4 4;
    auth:
      request: /auth_stub
    proxy:
      connect_timeout: 100s
      read_timeout: 600s
      protocol: http
    backends:
      - backends@backend1
      - backends@backend2

nginx:

http {
    template keyfile=check.yml;
    api_gateway_template keyfile=backends.yml template=backend.template;
    api_gateway_template keyfile=entrypoints.yml template=entrypoint.template;
}

Synchronization with external registry

api_gateway_template

Syntax api_gateway_template keyfile=keys.yml template=template_file url=host:port/url
Context http

Synchronization inventory with external registry.

Example: api_gateway_template keyfile=backends.yml template=backend.template url=127.0.0.1:7777/registry/backends;

See example for details.

Update timeout

Syntax api_gateway_timeout <timeout>
Context http

Update interval

Syntax api_gateway_interval <interval>
Context http