Skip to content

Commit

Permalink
Merge pull request #45 from nginxinc/ws-support
Browse files Browse the repository at this point in the history
Added websocket support
  • Loading branch information
pleshakov authored Aug 24, 2016
2 parents cc5cf33 + cad5d7d commit 9929f05
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 8 deletions.
34 changes: 34 additions & 0 deletions examples/websocket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# WebSocket support

To load balance a WebSocket application with NGINX Ingress controllers, you need to add the **nginx.org/websocket-services** annotation to your Ingress resource definition. The annotation specifies which services are websocket services. The annotation syntax is as follows:
```
nginx.org/websocket-services: "service1[,service2,...]"
```

In the following example we load balance three applications, one of which is using WebSocket:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.org/websocket-services: "ws-svc"
spec:
rules:
- host: cafe.example.com
http:
paths:
- path: /tea
backend:
serviceName: tea-svc
servicePort: 80
- path: /coffee
backend:
serviceName: coffee-svc
servicePort: 80
- path: /ws
backend:
serviceName: ws-svc
servicePort: 8008
```
*ws-svc* is a service for the WebSocket application. The service becomes available at the `/ws` path. Note how we used the **nginx.org/websocket-services** annotation.
24 changes: 20 additions & 4 deletions nginx-controller/nginx/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nginx

import (
"fmt"
"strings"
"sync"

"github.com/golang/glog"
Expand Down Expand Up @@ -78,6 +79,8 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri

upstreams := make(map[string]Upstream)

wsServices := getWebsocketServices(ingEx)

if ingEx.Ingress.Spec.Backend != nil {
name := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)
upstream := cnf.createUpstream(ingEx, name, ingEx.Ingress.Spec.Backend, ingEx.Ingress.Namespace)
Expand Down Expand Up @@ -116,7 +119,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri
upstreams[upsName] = upstream
}

loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg)
loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName])
locations = append(locations, loc)

if loc.Path == "/" {
Expand All @@ -126,7 +129,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri

if rootLocation == false && ingEx.Ingress.Spec.Backend != nil {
upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)
loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg)
loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
locations = append(locations, loc)
}

Expand All @@ -147,7 +150,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri

upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)

loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg)
loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
locations = append(locations, loc)

server.Locations = locations
Expand All @@ -172,13 +175,26 @@ func (cnf *Configurator) createConfig(ingEx *IngressEx) Config {
return ingCfg
}

func createLocation(path string, upstream Upstream, cfg *Config) Location {
func getWebsocketServices(ingEx *IngressEx) map[string]bool {
wsServices := make(map[string]bool)

if services, exists := ingEx.Ingress.Annotations["nginx.org/websocket-services"]; exists {
for _, svc := range strings.Split(services, ",") {
wsServices[svc] = true
}
}

return wsServices
}

func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) Location {
loc := Location{
Path: path,
Upstream: upstream,
ProxyConnectTimeout: cfg.ProxyConnectTimeout,
ProxyReadTimeout: cfg.ProxyReadTimeout,
ClientMaxBodySize: cfg.ClientMaxBodySize,
Websocket: websocket,
}

return loc
Expand Down
5 changes: 5 additions & 0 deletions nginx-controller/nginx/ingress.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ server {

{{range $location := $server.Locations}}
location {{$location.Path}} {
proxy_http_version 1.1;
{{if $location.Websocket}}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
{{end}}
proxy_connect_timeout {{$location.ProxyConnectTimeout}};
proxy_read_timeout {{$location.ProxyReadTimeout}};
client_max_body_size {{$location.ClientMaxBodySize}};
Expand Down
5 changes: 5 additions & 0 deletions nginx-controller/nginx/nginx.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,10 @@ http {
server_names_hash_max_size {{.ServerNamesHashMaxSize}};
{{if .ServerNamesHashBucketSize}}server_names_hash_bucket_size {{.ServerNamesHashBucketSize}};{{end}}

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

include /etc/nginx/conf.d/*.conf;
}
1 change: 1 addition & 0 deletions nginx-controller/nginx/nginx.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type Location struct {
ProxyConnectTimeout string
ProxyReadTimeout string
ClientMaxBodySize string
Websocket bool
}

// NginxMainConfig describe the main NGINX configuration file
Expand Down
24 changes: 20 additions & 4 deletions nginx-plus-controller/nginx/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nginx

import (
"fmt"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -81,6 +82,8 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri

upstreams := make(map[string]Upstream)

wsServices := getWebsocketServices(ingEx)

if ingEx.Ingress.Spec.Backend != nil {
name := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)
upstream := cnf.createUpstream(name)
Expand Down Expand Up @@ -121,7 +124,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri
upstreams[upsName] = upstream
}

loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg)
loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName])
locations = append(locations, loc)

if loc.Path == "/" {
Expand All @@ -131,7 +134,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri

if rootLocation == false && ingEx.Ingress.Spec.Backend != nil {
upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)
loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg)
loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
locations = append(locations, loc)
}

Expand All @@ -156,7 +159,7 @@ func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]stri

upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)

loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg)
loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
locations = append(locations, loc)

server.Locations = locations
Expand All @@ -181,13 +184,26 @@ func (cnf *Configurator) createConfig(ingEx *IngressEx) Config {
return ingCfg
}

func createLocation(path string, upstream Upstream, cfg *Config) Location {
func getWebsocketServices(ingEx *IngressEx) map[string]bool {
wsServices := make(map[string]bool)

if services, exists := ingEx.Ingress.Annotations["nginx.org/websocket-services"]; exists {
for _, svc := range strings.Split(services, ",") {
wsServices[svc] = true
}
}

return wsServices
}

func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) Location {
loc := Location{
Path: path,
Upstream: upstream,
ProxyConnectTimeout: cfg.ProxyConnectTimeout,
ProxyReadTimeout: cfg.ProxyReadTimeout,
ClientMaxBodySize: cfg.ClientMaxBodySize,
Websocket: websocket,
}

return loc
Expand Down
5 changes: 5 additions & 0 deletions nginx-plus-controller/nginx/ingress.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ server {

{{range $location := $server.Locations}}
location {{$location.Path}} {
proxy_http_version 1.1;
{{if $location.Websocket}}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
{{end}}
proxy_connect_timeout {{$location.ProxyConnectTimeout}};
proxy_read_timeout {{$location.ProxyReadTimeout}};
client_max_body_size {{$location.ClientMaxBodySize}};
Expand Down
5 changes: 5 additions & 0 deletions nginx-plus-controller/nginx/nginx.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,10 @@ http {
server_names_hash_max_size {{.ServerNamesHashMaxSize}};
{{if .ServerNamesHashBucketSize}}server_names_hash_bucket_size {{.ServerNamesHashBucketSize}};{{end}}

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

include /etc/nginx/conf.d/*.conf;
}
1 change: 1 addition & 0 deletions nginx-plus-controller/nginx/nginx.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Location struct {
ProxyConnectTimeout string
ProxyReadTimeout string
ClientMaxBodySize string
Websocket bool
}

// NginxMainConfig describe the main NGINX configuration file
Expand Down

0 comments on commit 9929f05

Please sign in to comment.