Das Problem: Netzwerk-geschlossen-Fehler in Java gRPC

Bei einem gRPC-Aufruf von Java zu einem Dienst hinter Istio auf Kubernetes kann der Fehler auftreten:

UNAVAILABLE: Network closed for unknown reason

Während Tools wie grpcurl erfolgreich über TLS mit dem Dienst kommunizieren, schlägt der Java-Client fehl. Dies passiert häufig, weil der Java-Client versucht, eine Klartextverbindung zu einem Server herzustellen, der TLS-gesicherte Kommunikation erwartet.


Ursache verstehen

  • Der nachgelagerte Dienst (Istio Gateway) erwartet TLS-verschlüsselte Verbindungen.
  • Der Java-Client verwendete ManagedChannelBuilder.usePlaintext(), wodurch TLS deaktiviert wurde.
  • Diese Unstimmigkeit führt dazu, dass der Server die Verbindung schließt, was den Fehler verursacht.

Lösung: Aktivieren Sie TLS in Ihrem Java gRPC-Client

Sie müssen Ihren Java gRPC-Client so konfigurieren, dass TLS verwendet wird, und gegebenenfalls das Root-Zertifikat des Servers bereitstellen.

Schritte zur Behebung

  1. usePlaintext() entfernen

    • Deaktivieren Sie TLS nicht durch den Aufruf von usePlaintext().
  2. Root-Zertifikat laden

    • Beschaffen Sie das vertrauenswürdige Root-Zertifikat des Servers.
    • Laden Sie es in Ihren Client, um die Identität des Servers zu validieren.
  3. Einen TLS-aktivierten Kanal erstellen

    • Verwenden Sie NettyChannelBuilder mit einem SSL-Kontext, der mit dem Root-Zertifikat konfiguriert ist.

Beispiel-Java-Code

// Ihr PEM-formatiertes vertrauenswürdiges Root-Zertifikat
private static final String ROOT_CERTIFICATE = """
-----BEGIN CERTIFICATE-----
...Ihr Zertifikat hier...
-----END CERTIFICATE-----
""";

// Zertifikat laden
Collection<X509Certificate> certificates;
try (InputStream certStream = new ByteArrayInputStream(ROOT_CERTIFICATE.getBytes(StandardCharsets.UTF_8))) {
    certificates = (Collection<X509Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(certStream);
}

// TLS-aktivierten Kanal aufbauen
ManagedChannel channel = NettyChannelBuilder.forAddress("aiplatform-grpc.dev51.cbf.dev.paypalinc.com", 443)
    .sslContext(GrpcSslContexts.forClient().trustManager(certificates).build())
    .build();

// Stub erstellen und Aufruf ausführen
PredictionServiceGrpc.PredictionServiceBlockingStub preStub = PredictionServiceGrpc.newBlockingStub(channel);
response = preStub.predict(predictReq);

Wichtige Erkenntnisse

  • Stimmen Sie den Sicherheitsmodus des Clients immer auf die Anforderungen des Servers ab.
  • Für gRPC über HTTPS (Port 443) ist TLS erforderlich.
  • Die Verwendung von NettyChannelBuilder mit einem eigenen SSLContext ermöglicht vollständige Kontrolle über Zertifikate.

Indem Sie von Klartext- auf TLS-Modus mit den richtigen Zertifikaten wechseln, sollte Ihr Java gRPC-Client erfolgreich kommunizieren, ohne dass der Netzwerk-geschlossen-Fehler auftritt.


Wenden Sie diese Änderungen an, und Ihr gRPC-Client sollte genauso funktionieren wie grpcurl.