nginxnginx-configconsulservice-discoveryconsul-template

How can i set automaticly registered services on nginx config using consul template


I'm using consul, consul-template and nginx on docker. When adding each new service, i have to change consul-template source file again. By the way all we're using soap services and proxy. All of them have service uri. How can i write nginx.ctmpl ? example web service end point :

 1.1.1.1:123/Service1.asmx

in consul-config, added like this:

"services": [
  {
    "id": "Svc0",
    "name": "Service",
    "port": 3307,
    "address": "1.1.1.1",
    "checks": [
      {
      "http": "http://1.1.1.1:123/service1.asmx",
      "method": "GET",
      "interval": "10s",
      "timeout": "1s"
      }]
  }
  ]

In nginx.ctmpl. I want to change this part for dynamic but i could'nt find any solution because of server part.

upstream backend {

{{ range service "Service" }}
  server {{ .Address }}:{{ .Port }};{{ end }}
}
server {
        listen                443 ssl;
        server_name           domainname.com.tr;
        proxy_set_header      X-Forwarded-Port 443;
        ssl_certificate       /etc/nginx/tls/..crt;
        ssl_certificate_key   /etc/nginx/tls/..key;
        
   location / {
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_pass https://domainanother;
        }
        
   location  ^~ /Service1.asmx {
 
            proxy_pass http://backend;
            proxy_redirect off;
        }
        access_log /etc/nginx/log/gw/https/access.log;
        error_log /etc/nginx/log/gw/https/error.log;
}

Solution

  • This should do what you want.

    Given the following service config:

    # services.hcl
    services {
      id = "svc1"
      name = "service1"
      address = "1.1.1.1"
      port = 8080
    }
    
    services {
      id = "svc2"
      name = "service2"
      address = "1.1.1.1"
      port = 8081
      check = {
        http = "http://1.1.1.1/Service1.asmx"
        method = "GET"
        interval = "10s"
        timeout = "1s"
      }
    }
    

    and the following template:

    {{- /*
    
      Upstream template
    
      This template is used to the upstream configuration for the service.
      It takes an array of service health objects as input and returns the template
      as a string.
    
    */ -}}
    {{- define "upstream-template" -}}
    ### Upstream configuration for {{ . }}
    upstream {{ . }} {
      zone upstream_{{ . }} 128k;
      {{ range service . "any" }}
      # Instance: {{ printf "%s-%s" .ID .Name }}
    
      {{- /* Mark the backend as down if the health status is critical */ -}}
      {{- $is_down := sprig_ternary " down" "" (eq .Status "critical") }}
      server {{ printf "%s:%d%s" .Address .Port $is_down -}};
      {{ end }}
    }
    {{ end -}}
    
    {{- /* Obtain list of services from the catalog */ -}}
    {{- $servicesList := services -}}
    
    {{- /* Generate upstream configurations for each logical service */ -}}
    {{- range $servicesList -}}
      {{- if and (ne .Name "consul") (.Name | contains "sidecar" | not) -}}
        {{- executeTemplate "upstream-template" .Name -}}
      {{- end -}}
    {{- end -}}
    
    server {
      listen                443 ssl;
      server_name           domainname.com.tr;
      proxy_set_header      X-Forwarded-Port 443;
      ssl_certificate       /etc/nginx/tls/..crt;
      ssl_certificate_key   /etc/nginx/tls/..key;
    
      access_log /etc/nginx/log/gw/https/access.log;
      error_log /etc/nginx/log/gw/https/error.log;
    
      location / {
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_pass https://domainanother;
      }
    
      {{- /*
        Generate the location blocks for each logical service.
        Ignore the 'consul' service itself, and any sidecar services.
      */ -}}
      {{ range $servicesList -}}
      {{- if and (ne .Name "consul") (.Name | contains "sidecar" | not) }}
      location ^~ /{{ .Name | sprig_title }}.asmx {
        proxy_pass http://{{ .Name }};
        proxy_redirect off;
      }
      {{ end -}}
      {{- end }}
    }
    

    Consul template will produce the following nginx configuration.

    ### Upstream configuration for service1
    upstream service1 {
      zone upstream_service1 128k;
      
      # Instance: svc1-service1
      server 1.1.1.1:8080;
      
    }
    ### Upstream configuration for service2
    upstream service2 {
      zone upstream_service2 128k;
      
      # Instance: svc2-service2
      server 1.1.1.1:8081;
      
    }
    server {
      listen                443 ssl;
      server_name           domainname.com.tr;
      proxy_set_header      X-Forwarded-Port 443;
      ssl_certificate       /etc/nginx/tls/..crt;
      ssl_certificate_key   /etc/nginx/tls/..key;
    
      access_log /etc/nginx/log/gw/https/access.log;
      error_log /etc/nginx/log/gw/https/error.log;
    
      location / {
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_pass https://domainanother;
      }
      location ^~ /Service1.asmx {
        proxy_pass http://service1;
        proxy_redirect off;
      }
      
      location ^~ /Service2.asmx {
        proxy_pass http://service2;
        proxy_redirect off;
      }
      
    }