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
-
usePlaintext()
entfernen- Deaktivieren Sie TLS nicht durch den Aufruf von
usePlaintext()
.
- Deaktivieren Sie TLS nicht durch den Aufruf von
-
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.
-
Einen TLS-aktivierten Kanal erstellen
- Verwenden Sie
NettyChannelBuilder
mit einem SSL-Kontext, der mit dem Root-Zertifikat konfiguriert ist.
- Verwenden Sie
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
.