Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to cobra cli #17

Merged
merged 4 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 54 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,89 @@ make compile
> List of command available
```bash
-backends string
Load balanced backends, use commas to separate
-configFile string
Only config filename.yaml default ngonx.yaml (default "ngonx.yaml")
-configPath string
Config path only not filename.yaml (default "pwd")
-genkey
Action for generate hash for protected routes
-lbPort int
Port to serve to run load balancing (default 3030)
-prevkey string
Action for save a previous hash for protected routes to validate JWT
-proxyPort int
Port to serve to run proxy
-setup
Create yaml file configuration
-type string
Main Service default is proxy (default "proxy")
-version
Display version and exit
ngonxctl -h
```

```bash
This is Ngonx ctl a proxy reverse inspired on nginx & traefik

Usage:
ngonxctl [command]

Available Commands:
completion generate the autocompletion script for the specified shell
help Help about any command
lb Run ngonx as a load balancer (round robin)
proxy Run ngonx as a reverse proxy
setup Create configuration file it`s doesn`t exist
static Run ngonx as a static web server
version Print the version number of ngonxctl

Flags:
-f, --cfgfile string File setting.yml (default "ngonx.yaml")
-p, --cfgpath string Config path only (default "path/binary")
-h, --help help for ngonxctl

Use "ngonxctl [command] --help" for more information about a command.

```

> Start Proxy server first time
`genkey` command in true generate random secretkey and save on badgerdb on `badger.data`

```bash
./ngxctl -proxyPort 5000 -genkey true
./ngonxctl proxy -port 5000 -genkey true
```

`prevkey` command receive a custom secretkey and save this on badgerdb on `badger.data`

```bash
./ngxctl -proxyPort 5000 -prevkey <secretKey>
./ngonxctl proxy -port 5000 -prevkey <secretKey>
```

> Start Proxy server
```bash
./ngxctl -proxyPort 5001
./ngonxctl proxy -port 5000
```

> Start load balancer
```bash
./ngxctl -type lb --backends "http://localhost:5000,http://localhost:5001,http://localhost:5002"
./ngonxctl lb --backends "http://localhost:5000,http://localhost:5001,http://localhost:5002"
```
> Start static files server
> Start API PoC service
```bash
./ngonxctl static
```

Metrics
-----------

Currently ngonx use prometheus as a metric collector. The main service `proxy` expose for port 10000 on route `/metrics`

```bash
go run services/micro-a/api.go --port <port>
curl http://localhost:10000/metrics
```

> Start static files server

Management API & Web(coming...)
-----------

Currently ngonx use port 10001 for export a simple api to check all services

```bash
curl http://localhost:10001/api/v1/mngt/
```



> Start API PoC service
```bash
go run cmd/main.go -type static
go run services/micro-a/api.go --port <port>
```

Install badger db on window if you don`t use CGO
Expand All @@ -84,7 +109,7 @@ CGO_ENABLED=0 go get github.com/dgraph-io/badger/v3

```bash

cd ssl
cd scripts

chmod +x ./generate.sh

Expand Down Expand Up @@ -133,10 +158,6 @@ certbot renew

---

Metrics
-----------

Currently ngonx used prometheus for metric collector. The main service `proxy` expose for port 10000 on route `/metrics`

BenchMarking
------------
Expand Down
23 changes: 23 additions & 0 deletions cmd/cli/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cli

import (
"os"

"github.com/kenriortega/ngonx/pkg/config"
)

var (
// variables to store data for global usage
configFromYaml config.Config
cfgFile = "ngonx.yaml"
cfgPath, _ = os.Getwd()
errConfig error

// flags
flagPort = "port"
flagServerList = "backends"
flagGenApiKey = "genkey"
flagPrevKey = "prevkey"
flagCfgFile = "cfgfile"
flagCfgPath = "cfgpath"
)
119 changes: 69 additions & 50 deletions cmd/cli/lb.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
"strings"
"time"

"github.com/kenriortega/ngonx/pkg/backoff"
"github.com/kenriortega/ngonx/pkg/logger"

domain "github.com/kenriortega/ngonx/internal/proxy/domain"

handlers "github.com/kenriortega/ngonx/internal/proxy/handlers"
"github.com/kenriortega/ngonx/pkg/backoff"
"github.com/kenriortega/ngonx/pkg/logger"
"github.com/spf13/cobra"
)

// MaxJitter will randomize over the full exponential backoff time
Expand All @@ -24,62 +24,81 @@ const MaxJitter = 1.0
// NoJitter disables the use of jitter for randomizing the exponential backoff time
const NoJitter = 0.0

func StartLB(serverList string, port int) {

if len(serverList) == 0 {
log.Fatal("Please provide one or more backends to load balance")
}

// parse servers
tokens := strings.Split(serverList, ",")
for _, tok := range tokens {
serverUrl, err := url.Parse(tok)
var lbCmd = &cobra.Command{
Use: "lb",
Short: "Run ngonx as a load balancer (round robin)",
Run: func(cmd *cobra.Command, args []string) {
port, err := cmd.Flags().GetInt(flagPort)
if err != nil {
logger.LogError(err.Error())
}
serverList, err := cmd.Flags().GetString(flagServerList)
if err != nil {
log.Fatalf(err.Error())
}
if len(serverList) == 0 {
log.Fatal("Please provide one or more backends to load balance")
}

// parse servers
tokens := strings.Split(serverList, ",")
for _, tok := range tokens {
serverUrl, err := url.Parse(tok)
if err != nil {
logger.LogError(err.Error())
}

proxy := httputil.NewSingleHostReverseProxy(serverUrl)
proxy.ErrorHandler = func(writer http.ResponseWriter, request *http.Request, e error) {
logger.LogInfo(fmt.Sprintf("[%s] %s\n", serverUrl.Host, e.Error()))
retry := handlers.GetRetryFromContext(request)

if retry < 3 {
time.Sleep(backoff.Default.Duration(retry))
ctx := context.WithValue(request.Context(), domain.RETRY, retry+1)
proxy.ServeHTTP(writer, request.WithContext(ctx))

proxy := httputil.NewSingleHostReverseProxy(serverUrl)
proxy.ErrorHandler = func(writer http.ResponseWriter, request *http.Request, e error) {
logger.LogInfo(fmt.Sprintf("[%s] %s\n", serverUrl.Host, e.Error()))
retry := handlers.GetRetryFromContext(request)
return
}

if retry < 3 {
time.Sleep(backoff.Default.Duration(retry))
ctx := context.WithValue(request.Context(), domain.RETRY, retry+1)
proxy.ServeHTTP(writer, request.WithContext(ctx))
// after 3 retries, mark this backend as down
handlers.ServerPool.MarkBackendStatus(serverUrl, false)

return
// if the same request routing for few attempts with different backends, increase the count
attempts := handlers.GetAttemptsFromContext(request)
logger.LogInfo(fmt.Sprintf("%s(%s) Attempting retry %d\n", request.RemoteAddr, request.URL.Path, attempts))
ctx := context.WithValue(request.Context(), domain.ATTEMPTS, attempts+1)
handlers.Lbalancer(writer, request.WithContext(ctx))
}

// after 3 retries, mark this backend as down
handlers.ServerPool.MarkBackendStatus(serverUrl, false)
handlers.ServerPool.AddBackend(&domain.Backend{
URL: serverUrl,
Alive: true,
ReverseProxy: proxy,
})
logger.LogInfo(fmt.Sprintf("Configured server: %s\n", serverUrl))
}

// if the same request routing for few attempts with different backends, increase the count
attempts := handlers.GetAttemptsFromContext(request)
logger.LogInfo(fmt.Sprintf("%s(%s) Attempting retry %d\n", request.RemoteAddr, request.URL.Path, attempts))
ctx := context.WithValue(request.Context(), domain.ATTEMPTS, attempts+1)
handlers.Lbalancer(writer, request.WithContext(ctx))
// create http server
server := http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: http.HandlerFunc(handlers.Lbalancer),
}

handlers.ServerPool.AddBackend(&domain.Backend{
URL: serverUrl,
Alive: true,
ReverseProxy: proxy,
})
logger.LogInfo(fmt.Sprintf("Configured server: %s\n", serverUrl))
}

// create http server
server := http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: http.HandlerFunc(handlers.Lbalancer),
}

// start health checking
go handlers.HealthCheck()

logger.LogInfo(fmt.Sprintf("Load Balancer started at :%d\n", port))
if err := server.ListenAndServe(); err != nil {
logger.LogError(err.Error())
}
// start health checking
go handlers.HealthCheck()

logger.LogInfo(fmt.Sprintf("Load Balancer started at :%d\n", port))
if err := server.ListenAndServe(); err != nil {
logger.LogError(err.Error())
}

},
}

func init() {
lbCmd.Flags().String(flagServerList, cfgFile, "Load balanced backends, use commas to separate")
lbCmd.Flags().Int(flagPort, 4000, "Port to serve to run load balancing ")

rootCmd.AddCommand(lbCmd)
}
Loading