serving
serving copied to clipboard
Support GRPC and HTTP2 without explicit port labeling
In what area(s)?
/area networking
Describe the feature
Today to use GRPC or HTTP/2 for ingress into your service, you have to explicitly label the ports (see the GRPC sample: https://github.com/knative/docs/blob/master/docs/serving/samples/grpc-ping-go/sample.yaml)
However, the Runtime Contract states that the platform will perform automatic detection between HTTP/1.1, QUIC, and HTTP/2.
Unless overridden by setting the name field on the inbound port, the platform will perform automatic detection as described above. Developers SHOULD prefer to use automatic content negotiation where available
I have a proposal out to update this in the runtime contract to reflect our current behavior. Discussion on it can be seen here: https://github.com/knative/serving/pull/4035/files#r283535192
I suggest the update to the contract as we do not have line of sight to implementing this as it has strong dependencies on features in Envoy and Istio which AFAIK are not being worked on. Some background on how we landed this without automatic upgrade can be seen in this comment: https://github.com/knative/serving/pull/2539#issuecomment-444585549.
Please do not close this issue by changing the runtime contract, this should be considered as a bug for Knative, even if fixing it will be hard due to Knative's use of Istio.
As a developer, I should not have to opt-into using HTTP2 to use HTTP2.
Having the explicit choice for what protocol your app supports feels like a feature. This can help to catch errors in expectations that have performance implications in the differences between HTTP/1 and HTTP/2.
While the automatic detection could be a useful default, given the underlying dependencies in our stack cannot support those requirements. It's unclear Knative can even support this without significant work in Envoy and Istio.
Changing the runtime contract and aligning the expectations in the contract with what we can deliver feels like the right decision. We can re-evaluate that decision in the future if/when Envoy improves this experience.
Please at least keep this open as a feature request.
I commented this somewhere else, but pasting here and elaborating.
Our support today looks like:
(empty): HTTP/1.1 only "h2c": HTTP/2 only "http1": HTTP/1.1 only
This makes (empty) == "http1" in todays world.
I have concerns with making (empty) automatically upgrade to HTTP/2.0 in the future and leave the "http1" as the option with no upgrade. This breaks the equality between (empty) and "http1" which has the potential to 1) be breaking 2) be surprising to developers. I don't want to rule it out as our considerations and our understanding of developer expectations could change by the time we are able to implement this, but we should discuss at that time how automatic HTTP upgrading works and if it should be the default behavior.
I am fine keeping this issue open to track automatic HTTP/2.0 upgrades as a feature request.
Concur with Dan. When we can, we should rather support auto and keep
defaulting to http/1.1.
/assign tanzeeb
Issues go stale after 90 days of inactivity.
Mark the issue as fresh by adding the comment /remove-lifecycle stale.
Stale issues rot after an additional 30 days of inactivity and eventually close.
If this issue is safe to close now please do so by adding the comment /close.
Send feedback to Knative Productivity Slack channel or file an issue in knative/test-infra.
/lifecycle stale
Issues go stale after 90 days of inactivity.
Mark the issue as fresh by adding the comment /remove-lifecycle stale.
Stale issues rot after an additional 30 days of inactivity and eventually close.
If this issue is safe to close now please do so by adding the comment /close.
Send feedback to Knative Productivity Slack channel or file an issue in knative/test-infra.
/lifecycle stale
@tanzeeb You still look at this? With 1.5 or 1.6 can we do it? /remove-lifecycle stale
@rafaeltello is looking at it now
/assign @rafaeltello
I think we need to reopen question adding 'auto' vs changing "" default meaning.
The current spec :
https://knative.dev/docs/reference/serving-api/#serving.knative.dev/v1.RevisionTemplateSpec (see podSpec inside spec)
"delegates" name declaration to k8S
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#containerport-v1-core
which in turn declares port name as
" If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services."
looking at the IANA service names https://tools.ietf.org/html/rfc6335 it seem that RC comes with syntactic rules as well as a registration process/database https://www.iana.org/protocols . (see "Hypertext Transfer Protocol (HTTP) Upgrade Token Registry" link for the reference to "h2c" registration )
Having said that I think kNative / k8s customers are still free to name their ports what they like (within syntactical rules), but kNative as a platform wold probably need to to pursue IANA registration if we want to come up with a a special value like "auto" (per proposal above, or change k8s spec).
Given that I would propose to to revert back to the original plan of "" string meaning auto detection and breaking "http1" == "" equivalency.
I and Rafael are working on a spec ( will share within in a week or so). Just wanted to give participants an early heads up on this plan adjustment.
Design : https://docs.google.com/document/d/1cGmJsBht6vTwqvWvfRnAEmQ1NPQOpZHjR082t2L8Wl4/edit?usp=sharing
My $0.02 from writing the initial runtime spec.
The intent was that an empty name would mean that Knative would send the initial request as HTTP/1 with an h2c upgrade option where possible, i.e. section 3.2 of RFC7540. This would look like (copy-pasting):
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
Where the HTTP2-Settings would be supplied by either the client or by the intermediate Knative routing stack. In the case of a request which was issued with HTTP2 settings which couldn't be downgraded to HTTP/1, the request would be dropped (e.g. in the queue-proxy) if the user container refused the h2c upgrade.
In the case of an h2c upgrade, the client responds with a 101 and then continues using HTTP/2 framing, so the response body could use all the HTTP/2 features. The spec also mentions that an OPTIONS request may be made to probe for h2c; I'd be highly surprised if OPTIONS was implemented to perform mutations.
Note that the h2c upgrade is incompatible with the websocket upgrade, so if the connection from the client already had an upgrade header, the h2c header shouldn't be injected.
I think there is subtle difference of what protocol and what backend can support, when there is an ingress proxy in between. client -> H2 -> ingress proxy -> (some protocol) -> backend
Without prior knowledge, I don't know how ingress proxy could determine what it should use or what it could use.
For example, for a non-streaming H2 request, ingress proxy could downgrade it to H1 to a H1 only backend. For a gRPC request (also H2), ingress proxy should not downgrade. For a H1 request, ingress proxy could upgrade to H2 only backend.
Does it mean we need to layer ALPN? client -> ALPN0 -> ingress proxy -> ALPN1 -> backend
And ALPN0 depends on ALPN1 based on different combinations?
I don't think the backend is ever serving TLS, so I don't think ALPN figures into it.
What's the rationale for blocking gRPC 2->1? I'd think it would show up as POSTs of protobuf body, which the user-container might not know what to do with. Is the implementation simplified if gRPC is explicitly blocked? Right now, I don't think we do anything special with gRPC compared with other methods.
For HTTP/2 with Prior Knowledge, I think the user needs to specify h2c as a string.
Note that today Knative is not implementing the SHOULD offer an HTTP/2.0 upgrade option part of the spec, which is okay since it is a SHOULD.
I don't think the backend is ever serving TLS, so I don't think ALPN figures into it.
What's the rationale for blocking gRPC 2->1? I'd think it would show up as POSTs of protobuf body, which the user-container might not know what to do with. Is the implementation simplified if gRPC is explicitly blocked? Right now, I don't think we do anything special with gRPC compared with other methods.
I think the main reason is gRPC 2 -> 1 doesn't quite work smoothly coz H1 is not a full duplex protocol but gRPC assume bidirectional streaming underneath.
This issue is stale because it has been open for 90 days with no
activity. It will automatically close after 30 more days of
inactivity. Reopen the issue with /reopen. Mark the issue as
fresh by adding the comment /remove-lifecycle stale.
/lifecycle freeze
We still want this, I believe?
Per discussion with @ZhiminXiang , we will be creating multiple issues to better track progress in this area. #10856 -> Health prober work (almost done in #10628) #10857 -> Queue proxy #10858 -> Activator
Once these three are complete, we can enable E2E tests, and discuss a timeline to enable the feature.
/triage accepted
@rafaeltello Are you continuing work on the queue proxy/activator issues?
I don't think @rafaeltello will continue working on it.
Is anyone going to work on this? This is an important issue that needs to be resolved.
@AyushChothe just to confirm you're aware that you can set the containerPort.name to h2c and it will use http2 cleartext?
@AyushChothe just to confirm you're aware that you can set the
containerPort.nametoh2cand it will use http2 cleartext?
@dprotaso Yes, I know that. We need the feature to upgrade the port from http1 to h2c without explicit labeling, i.e if the sidecar probe detects the support for HTTP/2.