nginx map $ upstream_addr无效,总是使用默认值

时间:2017-04-13 01:15:09

标签: nginx

为简单起见,我有一个上游只有1个服务器的例子:

Elixir.

和位置代理

upstream EarthML_IdentityService {
    server localhost:25303 ;
}
map $upstream_addr $EarthML_IdentityServiceuniquepath {
    default "7ab713ad-9ca5-4b08-8d32-84ec2e69370a/131365180085121149";
    127.0.0.1:25303 "7ab713ad-9ca5-4b08-8d32-84ec2e69370a/131365180085121149";
}

但如果我删除了地图的location ~* ^/(subscriptions/.*/)?(resourcegroups/.*/)?providers/(EarthML.Identity) { rewrite ^ /$EarthML_IdentityServiceuniquepath$uri break; proxy_pass http://earthml_identityservice; server_name_in_redirect on; port_in_redirect off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Path $request_uri; proxy_connect_timeout 3s; proxy_set_header X-Forwarded-PathBase /; proxy_cache_bypass $http_upgrade; add_header X-Upstream $upstream_addr; } 条目,那么它就会停止工作。我在标头中添加了default,以确保add_header X-Upstream $upstream_addr;确实设置为X-Upstream

1 个答案:

答案 0 :(得分:0)

提供上下文的提升。我在Microsoft ServiceFabric中设置了微服务框架。

我正在使用所有服务的nginx infront进行路由的公共映射以纠正服务。

在最新版本中添加了一项新功能UseServiceFabricIntegration,在设置服务监听和服务时允许服务结构为所有服务网址添加前缀suffix

在3节点设置中,这意味着服务A将以3个不同的后缀为前缀,每个节点一个。此集成还sets up检查与此服务通信时后缀应匹配,否则返回410 GONE。

我试图在nginx中创建一个上游配置,如果主节点无法响应,它可能会将请求重新路由到其他两个节点之一。 (这里的节点是我在每个节点上运行nginx loadbalancer,直到现在我使用了没有上游的配置,节点1上的所有nginx请求也会映射到节点1上的服务。)

我想改变这种行为,为下一个版本做好准备,我希望能够在单独的节点上运行nginx并映射到不同节点上的服务,并且如上所述也可以在服务错误的情况下重新路由节点

主要的问题是,在nginx中使用上游服务器无法解决这个问题,因为原始问题被问到了这些不同的后缀。

解决方案

我改为放弃了为aspnet核心构建的服务结构集成实现,并推出了自己的。

在nginx配置中我添加了:

sb.AppendLine($"{tabs}proxy_set_header X-ServiceFabric-Key    {uniquekey};");

其中uniquekey是根据服务名称和服务清单版本$"\"{ServiceName.AbsoluteUri.Substring("fabric:/".Length)}/{ServiceVersion}\""

创建的

我添加了自己的startupfilter来检查是否添加了此密钥:

if(context.Request.Headers.TryGetValue("X-ServiceFabric-Key", out StringValues serviceFabricKey))
{
    if (!serviceFabricKey.FirstOrDefault().Equals(this.serviceFabricKey))
    {
        context.Response.StatusCode = StatusCodes.Status410Gone;
        return;
    }
}

因为我还使用http通信进行服务之间的一些内部通信,所以我添加了一个快速示例来执行get请求:

public class HttpCommunicationServicePartitionClient : ServicePartitionClient<HttpCommunicationClient>
{
    private readonly FabricClient fabricClient;
    private readonly Uri application;
    public HttpCommunicationServicePartitionClient(
        FabricClient fabricClient, Uri application, Uri serviceUri, ServicePartitionKey partitionKey = null, TargetReplicaSelector targetReplicaSelector = TargetReplicaSelector.Default, string listenerName = null, OperationRetrySettings retrySettings = null)
        : base(new HttpCommunicationClientFactory(new ServicePartitionResolver(() => fabricClient)), serviceUri, partitionKey, targetReplicaSelector, listenerName, retrySettings)
    {

        this.fabricClient = fabricClient;
        this.application = application;

    }

    public string BearerToken { get; set; }


    public Task<HttpResponseMessage> GetAsync(string pathAndQuery)
    {
        return InvokeWithRetryAsync(async (client) =>
        {
            if (!string.IsNullOrEmpty(BearerToken))
            {
                client.DefaultRequestHeaders.Authorization = 
                    new AuthenticationHeaderValue("Bearer", BearerToken);
            }

            var services = await fabricClient.QueryManager.GetServiceListAsync(application, ServiceUri).ConfigureAwait(false);
            var service = services.FirstOrDefault();
            var key = $"{ServiceUri.AbsoluteUri.Substring("fabric:/".Length)}/{service.ServiceManifestVersion}";

            client.DefaultRequestHeaders.Add("X-ServiceFabric-Key", key);


            HttpResponseMessage response = await client.GetAsync(new Uri(client.BaseAddress, pathAndQuery));
            return response;
        });
    }



}