Use nginx upstreams and reload only if configuration changes

This commit is contained in:
Manuel de Brito Fontes 2016-03-14 23:29:13 -03:00
parent d0a15b1267
commit cad814cbb3
50 changed files with 370 additions and 10432 deletions

View file

@ -52,17 +52,20 @@ func (ngx *NginxManager) Start() {
// shut down, stop accepting new connections and continue to service current requests
// until all such requests are serviced. After that, the old worker processes exit.
// http://nginx.org/en/docs/beginners_guide.html#control
func (ngx *NginxManager) Reload(cfg *nginxConfiguration, servicesL4 []Service) {
func (ngx *NginxManager) CheckAndReload(cfg *nginxConfiguration, upstreams []Upstream, servers []Server, servicesL4 []Service) {
ngx.reloadLock.Lock()
defer ngx.reloadLock.Unlock()
if err := ngx.writeCfg(cfg, servicesL4); err != nil {
newCfg, err := ngx.writeCfg(cfg, upstreams, servers, servicesL4)
if err != nil {
glog.Errorf("Failed to write new nginx configuration. Avoiding reload: %v", err)
return
}
if err := ngx.shellOut("nginx -s reload"); err == nil {
glog.Info("Change in configuration detected. Reloading...")
if newCfg {
if err := ngx.shellOut("nginx -s reload"); err == nil {
glog.Info("Change in configuration detected. Reloading...")
}
}
}

View file

@ -0,0 +1,92 @@
package nginx
// NGINXController Updates NGINX configuration, starts and reloads NGINX
type NGINXController struct {
resolver string
nginxConfdPath string
nginxCertsPath string
local bool
}
// IngressNGINXConfig describes an NGINX configuration
type IngressNGINXConfig struct {
Upstreams []Upstream
Servers []Server
}
// Upstream describes an NGINX upstream
type Upstream struct {
Name string
Backends []UpstreamServer
}
type UpstreamByNameServers []Upstream
func (c UpstreamByNameServers) Len() int { return len(c) }
func (c UpstreamByNameServers) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c UpstreamByNameServers) Less(i, j int) bool {
return c[i].Name < c[j].Name
}
// UpstreamServer describes a server in an NGINX upstream
type UpstreamServer struct {
Address string
Port string
}
type UpstreamServerByAddrPort []UpstreamServer
func (c UpstreamServerByAddrPort) Len() int { return len(c) }
func (c UpstreamServerByAddrPort) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c UpstreamServerByAddrPort) Less(i, j int) bool {
iName := c[i].Address
jName := c[j].Address
if iName != jName {
return iName < jName
}
iU := c[i].Port
jU := c[j].Port
return iU < jU
}
// Server describes an NGINX server
type Server struct {
Name string
Locations []Location
SSL bool
SSLCertificate string
SSLCertificateKey string
}
type ServerByNamePort []Server
func (c ServerByNamePort) Len() int { return len(c) }
func (c ServerByNamePort) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ServerByNamePort) Less(i, j int) bool {
return c[i].Name < c[j].Name
}
// Location describes an NGINX location
type Location struct {
Path string
Upstream Upstream
}
type locByPathUpstream []Location
func (c locByPathUpstream) Len() int { return len(c) }
func (c locByPathUpstream) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c locByPathUpstream) Less(i, j int) bool {
return c[i].Path < c[j].Path
}
// NewUpstreamWithDefaultServer creates an upstream with the default server.
// proxy_pass to an upstream with the default server returns 502.
// We use it for services that have no endpoints
func NewUpstreamWithDefaultServer(name string) Upstream {
return Upstream{
Name: name,
Backends: []UpstreamServer{UpstreamServer{Address: "127.0.0.1", Port: "8181"}},
}
}

View file

@ -60,10 +60,10 @@ func (ngx *NginxManager) loadTemplate() {
ngx.template = tmpl
}
func (ngx *NginxManager) writeCfg(cfg *nginxConfiguration, servicesL4 []Service) error {
func (ngx *NginxManager) writeCfg(cfg *nginxConfiguration, upstreams []Upstream, servers []Server, servicesL4 []Service) (bool, error) {
file, err := os.Create(ngx.ConfigFile)
if err != nil {
return err
return false, err
}
fromMap := structs.Map(cfg)
@ -72,6 +72,8 @@ func (ngx *NginxManager) writeCfg(cfg *nginxConfiguration, servicesL4 []Service)
conf := make(map[string]interface{})
conf["sslCertificates"] = ngx.sslCertificates
conf["upstreams"] = upstreams
conf["servers"] = servers
conf["tcpServices"] = servicesL4
conf["defBackend"] = ngx.defBackend
conf["defResolver"] = ngx.defResolver
@ -94,8 +96,8 @@ func (ngx *NginxManager) writeCfg(cfg *nginxConfiguration, servicesL4 []Service)
err = ngx.template.Execute(file, conf)
if err != nil {
return err
return false, err
}
return nil
return true, nil
}

View file

@ -17,7 +17,6 @@ limitations under the License.
package nginx
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
@ -28,27 +27,6 @@ import (
"github.com/golang/glog"
)
// SyncIngress creates a GET request to nginx to indicate that is required to refresh the Ingress rules.
func (ngx *NginxManager) SyncIngress(ingList []interface{}) error {
encData, _ := json.Marshal(ingList)
req, err := http.NewRequest("POST", "http://127.0.0.1:8080/update-ingress", bytes.NewBuffer(encData))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != 200 {
body, _ := ioutil.ReadAll(res.Body)
glog.Errorf("Error: %v", string(body))
return fmt.Errorf("nginx status is unhealthy")
}
return nil
}
// IsHealthy checks if nginx is running
func (ngx *NginxManager) IsHealthy() error {
res, err := http.Get("http://127.0.0.1:8080/healthz")