nixy - nginx auto configuration and service discovery for Mesos/Marathon
Nixy is a daemon that automatically configures Nginx for web services deployed on Apache Mesos and Marathon.
Features:
Install nixy from pre-compiled packages. Check releases
page.
Edit config (default on ubuntu is /etc/nixy.toml):
# Nixy listening port
port = "6000"
# X-Proxy header, defaults to hostname
xproxy = ""
# Marathon API
marathon = ["http://example01:8080", "http://example02:8080"] # add all HA cluster nodes in priority order.
user = "" # leave empty if no auth is required.
pass = ""
# Nixy realm, set this if you want to be able to filter your apps (e.g. when you have different loadbalancers which should expose different apps)
# You will also need to set "NIXY_REALM" label at your app to be included in generated conf
realm = ""
# Nginx
nginx_config = "/etc/nginx/nginx.conf"
nginx_template = "/etc/nginx/nginx.tmpl"
nginx_cmd = "nginx" # optionally "openresty" or "docker exec nginx nginx"
nginx_ignore_check = false # optionally disable nginx config test. Health check will always show OK.
#left_delimiter = "{{" # if you want to change the default template delimiters
#right_delimiter = "}}" # if you want to change the default template delimiters
# Statsd settings
[statsd]
addr = "localhost:8125" # optional for statistics
#namespace = "nixy.my_mesos_cluster"
#sample_rate = 100
Optionally edit the nginx template (default on ubuntu is /etc/nginx/nginx.tmpl)
Install nginx or openresty and start the service.
"docker run -d --name nginx -p 7000:7000 -v /etc/nginx:/etc/nginx nginx"
. You will also need to change config "nginx_cmd"
to "docker exec nginx nginx"
for reloads to work correctly in this case.Start nixy! (service nixy start)
Routing is based on the HTTP Host header matching app ID by default.
If apps are organized under a directory structure the directory will become the root subdomain.
This is easy to change and customize to your own choosing by editing the
nginx.tmpl
file. For example if you prefer routing based on uri instead of subdomains take a look at nginx-path.tmpl
.
Example to access your apps /bar1
, /bar2
, /foo/bar3
running inside Mesos and Marathon:
curl -i localhost/ -H 'Host: bar1.example.com'
curl -i localhost/ -H 'Host: bar2.example.com'
curl -i localhost/ -H 'Host: bar3.foo.example.com'
Assuming you have configured nginx on port 80.
Deploy your app to Marathon setting a custom label called subdomain
:
"labels": {
"subdomain": "foobar"
},
This will override the Host
for that app and replace it with foobar
as the new subdomain/host.
It's also possible to add multiple subdomains to a single app, dividing by a space character.
"labels": {
"subdomain": "foo bar"
},
This will now match both foo
and bar
as the new subdomain/host.
Nixy uses the standard Go (Golang) template package to generate its config. It's a powerful and easy to use language to fully customize the nginx config. The default template is meant to be a working base that adds some sane defaults for Nginx. If needed just extend it or modify to suite your environment the best.
If you are unsure of what variables you can use inside your template just do a GET /v1/config
and you will receive a JSON response of everything available. All labels and environment variables are available. Other options could be to enable websockets, HTTP/2, SSL/TLS, or to control ports, logging, load balancing method, or any other custom settings your applications need.
Examples:
Add some ACL rules to block traffic from outside the internal network? Add a Label called internal
to your app and the following snippet to your template:
{{- if $app.Labels.internal}}
# allow anyone from local network.
allow 10.0.0.0/8;
# block everyone else
deny all;
{{- end }}
Optionally, add dynamically which network that have access to the same label:
{{- if $app.Labels.internal}}
# allow anyone from local network.
allow {{ $app.Labels.internal }};
# block everyone else
deny all;
{{- end }}
Add a custom http header based on an Environment variable inside your app?
{{- if $app.Env.APP_ENV}}
# could be dev, stage, production...
add_header X-Environment {{ $app.Env.APP_ENV }} always;
{{- end}}
Wrapper for strings.Contains. Contains reports whether substr is within string.
{{if contains $host "www" }}
Wrapper for strings.HasPrefix. HasPrefix tests whether the string s begins with prefix.
{{if hasPrefix $host "www" }}
Wrapper for strings.HasSuffix. HasSuffix tests whether the string s ends with suffix.
{{if hasSuffix $host ".com" }}
Wrapper for strings.Split. Splits the input string on the separating string and returns a slice of substrings.
{{- $url := split "localhost:8080" ":" }}
host: {{index $url 0}}
port: {{index $url 1}}
Alias for the strings.Join function.
apps: {{join $applist ","}}
Alias for the strings.Trim function.
host: {{trim ".app.test.com." "."}}
Alias for the strings.Replace function.
{{$host := "app/test/com"}}
host = {{replace $host "/" "." -1}}
Wrapper for os.Getenv. Retrieves the value of the environment variable named by the key. It returns the value, which will be empty if the variable is not present.
hostname: {{getenv "HOSTNAME"}}
Alias for time.Now
# Generated by nixy {{datetime}}
Sometimes it is useful to implement the same service with apps within marathon.
In this case you can use .MergeAppsByLabel("some-label")
instead of .Apps
in your template
to merge multiple apps into a single service.
For example if the following apps running in marathon implement the same API:
my-service-a
my-service-b
And they both have the label servicename=my-service
you could use MergeAppsByLabel("servicename")
to access both implementations as nixy.marathon.mesos:12345
.
Labels
from each original app are added
to each Task from that original app. This is necessary if you want
to have implementation specific labels. For example, if one
implementation is faster, we could route more traffic there.It is possible to use Nixy to configure nginx as a proxy for TCP or UDP traffic.
Please check the nginx-stream.tmpl
example template. It assumes you have configured PortDefinitions
correctly for all your services in Marathon.
Latest versions of Nginx open-source comes with streaming by default. If you are running version 1.9 you will need to compile it with --with-stream
manually.
GET /
prints nixy version.GET /v1/config
JSON response with all variables available inside the template.GET /v1/reload
manually trigger a new config reload.GET /v1/health
JSON response with health status of template, nginx config and Marathon endpoints available.GET /v1/metrics
Prometheus metrics endpoint.In case you want to monitor nixy using Nagios (or compatible monitoring) you can use the included check_nixy
plugin.