-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Broken pipe on API call with Minikube #1003
Comments
The same problem exists with |
If it helps, my problem is a minikube env on hyperv , win 10/amd64, docker 19.0.3.8 using ubuntu 18.0.4 containers |
I'm not sure how minikube sets up it's networking. I suspect that the |
I've recreated this on Kind (v0.8.1 go1.14.2 darwin/amd64, running on Docker version 19.03.8, build afacb8b), doing nothing more than making a call to So, in the same pod, I tried to bypass the Kubernetes client by using Spring's But knowing that the Kubernetes client uses OkHttp and not A little deeper digging makes it seem that the exception is thrown while dealing with the SSL handshake, as per the following stack trace. It's deep in some low-level socket code where it happens, but if I were guessing, I'd say that OkHttp is fine and Kind/Minikube are both fine. But the combination isn't so great. I guess that at some point OkHttp sends or does something that the K8s API on Kind/Minikube handle by closing the connection...but OkHttp expecting to continue using that connection throws the Broken Pipe exception because the connection has been closed by the K8s API on those clusters. My guess continues to suppose that whatever OkHttp does to cause the K8s API to close, doesn't result in a closed connection on GKE (or other K8s platforms)...and whatever it is that OkHttp does isn't done by |
I've found a way to make this work! In short, I was reading that there are some TLS 1.3 changes that might impact this and that aren't available until more recent versions of Java. So...long story short...I realized that I was still targeting Java 1.8 in my project's build. I bumped it up to target Java 11 in the build (which also involved me switching to Java 11 in SDKMan...for "reasons" I still have 1.8 as the default in SDKMan), and suddenly it works! What's more, it works on both Kind and Minikube! @zenbones Any chance you are building to target Java 1.8? If so, maybe try targeting Java 11? Would like to hear someone else try this and confirm that it works. (Note, that I'm building using Spring Boot 2.3.1 and using its support for creating a container image. Java 11 works fine, but Java 12 and 13 not so much because at build time it can't find compatible dependencies for the Paketo BellSoft Liberica Buildpack 2.8.0 while building the image. It does seem to build fine with Java 14, though it fails at runtime with a new exception: |
Wow, that's good detective work. Thanks. Our build does target Java 8, and we do pan to move to Java 11, but Oracle has given control of J2EE to the Eclipse Foundation, but not the Sounds like this is not anyone's fault and there's probably little to be done and it's on us to make the Java11 move... but I'm wondering if forking the project and rebuilding it under Java 8 might also be a temporary solution... maybe going so far as to swap out the OKHttp client for something else (maybe the Apache client). I may be able to try that. |
Swapping out OKHttp for Apache (or anything else) seems like quite a chore. The But yeah, I don't think this is a bug as much as a compatibility issue. As @alek-sys noted above, I also know it to work on GKE, regardless of the Java version in play (even Java 14 plays nice there). Just Kind and Minikube sorta require that your app that's using |
fwiw, all of this code is generated, so swapping out the client library isn't a workable solution since we need the ability to re-generate the library. For now, I would just use kind to create a Kubernetes 1.17 cluster instead of 1.18 (unless you really need 1.18 APIs) and I believe it should work w/ Java 8, kubernetes 1.18 made some TLS changes. |
Not sure what I can or can't do for now, but I can live with transient issues and find workarounds. I'm more concerned with ongoing problems. Are there any plans to make this compatible with Java 8, Minikube and kubernetes 1.18, or is the plan to let people upgrade out of Java 8 in order to find a solution? |
This library is compatible w/ Java8 and Kubernetes 1.18. This library is tested and working with both JDK8 and JDK11 and both cloud (Azure, GKE) and on-premise (my home cluster) with Kubernetes 1.16, 1.17 and 1.18. So I'm confident that it works correctly. There was a bug in JDK 11 (https://bugs.openjdk.java.net/browse/JDK-8236039) that has been fixed in recent versions that may have caused the problem cited w/ JDK 14 above (#1003 (comment)) as well as other certificate problems depending on JDK version. I have not done recent testing w/ minikube so it's possible that there is some problem in there certificate generation. I will try to repro when I have time. If you have problems w/ Java8 + this library and a complete install of Kubernetes (e.g. not minikube) let me know, in the meantime I think it's a problem specifically w/ minikube and we'll try to reproduce when we have cycles. |
And in the meantime I've sorted out a minimal Java 11 version of our code so I'll try this again and let you know. |
Whatever's happening is not just Java 11. I get the same broken pipe under Minikube with... openjdk version "11.0.7" 2020-04-14 I guess the next step is to try this in a non-Minikube environment. Back to the drawing board... |
And running in EKS on kubernetes 1.16 I get... exception in thread "main" java.lang.reflect.InvocationTargetException This is copied from your example code and was about the simplest example I could find. Is this tested against anything more than GKE? I don't have an account but maybe I'll try to set one up there. Oh, do you have that example you used to test on your home cluster? Maybe I could just drop that into a container and see if it works in Minikube or EKS? |
I tried to repro this on my machine (MacOS) without any success. Here are the steps I followed:
|
Odd, as the second report was for... The same problem exists with kind cluster (kind v0.8.1 go1.14.2 darwin/amd64), however it works on GKE. ...but I'm game. I'll update minikube to the latest win10 version, and put the code into a Jersey resource, run the 1.8 JVM starting a Grizzly instance on Ubuntu, none of which should be a significant difference from your setup. Fingers crossed. |
Replicated with... Windows 10 minikube version: v1.11.0 In container... Ubuntu 18.04 openjdk version "1.8.0_252" Running a Jersey resource under Grizzly, same broken pipe. Maybe an interaction between OS, Minikube and the Java client. Would love to be able to debug into Minikube. Or get an error log at least. |
@zenbones -Are you sure it's a broken pipe error or something else? I got SocketTimeout initially but that was due to wrong configs. |
Yes, I'm sure. See the error above, it has not changed. And I have debug statements in the java code so I can watch it approach the call to createNamespacePod(), so it's getting to that line, and that's the line in the stack trace. I did check the minikube logs. The only output is... Trace[267839508]: [2m19.517418668s] [2m19.515862333s] Transformed response object ...which occurs before the java client code ever reaches createNamespacePod(). I'll check and see if GoLang has a remote debugger I can attach to. |
As @brendandburns mentioned above, looks like some problem with your setup. I wish I could help you more on this but I am not able to reproduce this. |
I have the exact same problem on this environment, with Java 8 operators that have been working fine until a recent minikube upgrade. The problem affect several containers, and multiple operations (list, watch ...):
Here is a sample exception;
|
I just reproduced the issue with Kubernetes 1.17.8:
This is critical for us, any pointer would be really appreciated! |
@franck102 - Can you give me more information on your setup. I will try to repro it. |
io.fabric8.kubernetes.client looks like a different client. |
Good point, to be honest I had focused on the okhttp3 stack trace which is exactly the same and I didn’t realize the client was different. I will reproduce with SSL debugging enabled and post the stack trace, I did that before and it didn’t seem to be a certificate problem. |
I finally have client code working. It's against Minikube but running from outside kubernetes. I was able to reproduce the problems this way, and to get a solution, I'm setting up to try from with a container now. My experience is that the client using Java 8 does not work. Using Java 11 does not work, unless you add... System.setProperty("jdk.tls.client.protocols", "TLSv1.2") ...and then it works. I got this notion from golang/go#35722, so I suspect it's related and a TLS issue. I'll let you know if the solution works from within the container. |
You can check with maintainers of this repo. |
Thanks, since this affect both this client and the io.fabric8 client (@zenbones above) I will post in the minikube issue I mentioned above. |
BTW, using System.setProperty("jdk.tls.client.protocols", "TLSv1.2") in a container running in the cluster leads to... SEVERE: service exception: This NO_ERROR is treated by java as an error, and I don't see any result from the call, so this is different but still not good. |
But from outside this cluster, this works perfectly...
So it's not Minikube itself, but the configuration being loaded inside the cluster? |
Java 11 (amazoncorretto:11) with Kubernetes 1.17.8 (no tls switch needed for me) |
I agree, in that I think it's something basic in the way Java versions and Kubernetes or Go versions have implemented the TLS specification. The problem is that sometimes working, on very particular versions and implementations is very close to not working. I need to find a way through I can depend on. Not sure what that is. At least this works from outside kubernetes, so I could implement a controller process that sat outside the kubernetes framework... which seems ridiculous. |
I created a little client using the apache http client...
...and it works, in that calls complete, with TLS 1.3 (or at least no restriction).
So, this may be an OKHTTP3 / Kubernetes interaction. I do think it's TLS related, but apache has no problems. |
FYI Java 8 works with no special changes against Kubernetes 1.15.11. |
So, getting proper error messages from own little client, I could see I was getting a 403 on calls trying to do anything real with the API. That gave me the clue I needed to fix my RBAC. Once I did that everything worked with my client, so I flipped back to the standard client and everything worked. And, for whatever reason, it worked with TLS 1.3. So all of this may have been RBAC. Why this translates into broken pipes as opposed to some helpful error message I don't know. But as I have a working client, I'm going to close this issue. If anything help can come from this, if you're having problems, I'd say create your own working client so you can see what's going on. If I get problems again I'll expand the one I have with the swagger apis and open source it. Thanks for all the great input. |
Hello. |
I can confirm that this method mentioned here works client.setHttpClient(client.getHttpClient().newBuilder().protocols(Arrays.asList(Protocol.HTTP_1_1)).build()); The easiest way to reproduce this is to use docker 8u252-jre image, and use the okhttp client to send any request to a kubernetes 1.18 server. (it doesn't even have to be authenticated) |
|
I have a pretty basic minikube setup running in hyperv. Just trying to make sure the basics work, so this is copied from the examples. This code running inside the image of a deployment...
...at the point of api.createNamespacedPod(), leads to...
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.smallmind.spark.singularity.boot.SingularityEntryPoint.main(SingularityEntryPoint.java:65)
Caused by: io.kubernetes.client.openapi.ApiException: java.net.SocketException: Broken pipe (Write failed)
at io.kubernetes.client.openapi.ApiClient.execute(ApiClient.java:898)
at io.kubernetes.client.openapi.apis.CoreV1Api.createNamespacedPodWithHttpInfo(CoreV1Api.java:7902)
at io.kubernetes.client.openapi.apis.CoreV1Api.createNamespacedPod(CoreV1Api.java:7876)
at com.forio.epicenter.k8s.operator.worker.WorkerController.main(WorkerController.java:58)
... 5 more
Caused by: java.net.SocketException: Broken pipe (Write failed)
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431)
at sun.security.ssl.OutputRecord.write(OutputRecord.java:417)
at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:894)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:865)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
at okio.Okio$1.write(Okio.java:79)
at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
at okio.RealBufferedSink.flush(RealBufferedSink.java:224)
at okhttp3.internal.http2.Http2Writer.settings(Http2Writer.java:185)
at okhttp3.internal.http2.Http2Connection.start(Http2Connection.java:499)
at okhttp3.internal.http2.Http2Connection.start(Http2Connection.java:489)
at okhttp3.internal.connection.RealConnection.startHttp2(RealConnection.java:315)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:304)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88)
at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:221)
at okhttp3.RealCall.execute(RealCall.java:81)
at io.kubernetes.client.openapi.ApiClient.execute(ApiClient.java:894)
... 8 more
What's the best way to determine why I'm getting that error? Anything obvious I'm missing?
The text was updated successfully, but these errors were encountered: