是否可以使用 Java SDK 通过反向代理连接到 Azure Cosmos DB?

Is it possible to connect to Azure Cosmos DB via a reverse proxy using Java SDK?

我正在尝试使用 java sdk 连接到 cosmos。我在 AKS 中有一个 Nginx 代理 运行 指向我的 cosmos 实例(下面 nginx.conf 的子集):

  server {
    listen {{ .Values.cosmosDB.port }} so_keepalive=on;
    proxy_connect_timeout 5s;
    proxy_timeout 60m;
    proxy_buffer_size 30M;
    proxy_socket_keepalive on;
    proxy_ssl_session_reuse on;
    proxy_pass my-instance-cosmos-dev.documents.azure.com:443;
  }

我的想法是,通过端口转发,我可以通过此代理将我的本地用作 cosmos 主机 url:

kubectl port-forward svc/data-proxy 3308:443

运行 java 的快速入门(通过 Azure 门户生成)我无法配置连接的 cosmos 客户端。我尝试了几种配置:

默认网关模式:

        client = new CosmosClientBuilder()
            .endpoint(AccountSettings.HOST)
            .key(AccountSettings.MASTER_KEY)
            .endpointDiscoveryEnabled(true)
            .gatewayMode()
            .userAgentSuffix("CosmosDBJavaQuickstart")
            .consistencyLevel(ConsistencyLevel.EVENTUAL)
            .buildClient();

但是 returns 启动时出错 Database Account localhost does not exist:

CosmosException{userAgent=azsdk-java-cosmos/4.4.0 MacOSX/10.15.7 JRE/15.0.2, 
error={"code":"Forbidden","message":"Database Account localhost does not exist\r\nActivityId: 742a632d-cd00-42b7-8599-8fc6ff1eccad, Microsoft.Azure.Documents.Common/2.14.0, StatusCode: Forbidden","additionalErrorInfo":null}, resourceAddress='null', requestUri='null', statusCode=403, message=Database Account localhost does not exist

然后我尝试按如下方式传递代理配置,但收到 SSL 验证错误:

    ProxyOptions opts = new ProxyOptions(ProxyOptions.Type.HTTP,  InetSocketAddress.createUnresolved("127.0.0.1", 3308));
    gatewayConnectionConfig.setProxy(opts);


    gatewayConnectionConfig.setMaxConnectionPoolSize(5);
    
    //  Create sync client
    client = new CosmosClientBuilder()
        .endpoint(AccountSettings.HOST)
        .key(AccountSettings.MASTER_KEY)
        .endpointDiscoveryEnabled(true)
        .gatewayMode(gatewayConnectionConfig)
        .userAgentSuffix("CosmosDBJavaQuickstart")
        .consistencyLevel(ConsistencyLevel.EVENTUAL)
        .buildClient();

输出:

INFO: Getting database account endpoint from http://localhost:3308
Oct 07, 2021 10:01:31 AM com.azure.cosmos.implementation.RxGatewayStoreModel 
lambda$toDocumentServiceResponse
SEVERE: Network failure
javax.net.ssl.SSLException: failure when writing TLS control frames
    at io.netty.handler.ssl.SslHandler.setHandshakeFailureTransportFailure(SslHandler.java:1863)
    at io.netty.handler.ssl.SslHandler.access0(SslHandler.java:167)
    at io.netty.handler.ssl.SslHandler.operationComplete(SslHandler.java:978)
    at io.netty.handler.ssl.SslHandler.operationComplete(SslHandler.java:973)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:577)
    at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:551)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:490)
    at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:615)
    at io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:608)
    at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:117)
    at io.netty.channel.PendingWriteQueue.safeFail(PendingWriteQueue.java:279)
    at io.netty.channel.PendingWriteQueue.removeAndFailAll(PendingWriteQueue.java:177)
    at io.netty.handler.proxy.ProxyHandler.failPendingWrites(ProxyHandler.java:435)
    at io.netty.handler.proxy.ProxyHandler.failPendingWritesAndClose(ProxyHandler.java:352)
    at io.netty.handler.proxy.ProxyHandler.setConnectFailure(ProxyHandler.java:347)
    at io.netty.handler.proxy.ProxyHandler.access0(ProxyHandler.java:39)
    at io.netty.handler.proxy.ProxyHandler.run(ProxyHandler.java:199)
    at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
    at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:170)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
    at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: io.netty.handler.proxy.ProxyConnectException: http, none, /127.0.0.1:3308 => localhost/<unresolved>:3308, timeout
    ... 10 more

我不确定如何进行。这是受支持的连接模式吗?也许我在这里通过 SDK 误解了客户端设置...

我认为代理方法应该可行,但您必须在 connection-String 中写入您在 AccountSettings.HOST 中使用的原始 Cosmos-DB-URL。

我猜那里仍然引用了“localhost”,因为您是第一次尝试直接访问。但是由于您现在正在通过代理,所以应该有真正的 URL。 (my-instance-cosmos-dev.documents.azure.com)

此外,您没有收到 SSL 验证错误,它看起来像是超时。 (因为代理试图连接到本地主机)


如果您确实想使用第一种(直接)方法,那么您可以在 /etc/hosts 中添加一个条目,这应该让 cosmos-db SDK 发送正确的 Host-header 在请求中。

127.0.0.1 my-instance-cosmos-dev.documents.azure.com

然后你还需要在connection-string中引用真正的URL,然后指向localhost。