@@ -94,8 +94,8 @@ tags, and then generate with `hack/update-toc.sh`.
94
94
- [ Proposal: New <code >RemoteCommand</code > Sub-Protocol Version - <code >v5.channel.k8s.io</code >] ( #proposal-new-remotecommand-sub-protocol-version---v5channelk8sio )
95
95
- [ Proposal: API Server RemoteCommand <code >StreamTranslatorProxy</code >] ( #proposal-api-server-remotecommand-streamtranslatorproxy )
96
96
- [ Background: <code >PortForward</code > Subprotocol] ( #background-portforward-subprotocol )
97
- - [ Proposal: New <code >PortForward</code > Subprotocol Version - <code >v2.portforward.k8s.io</code >] ( #proposal-new-portforward-subprotocol-version---v2portforwardk8sio )
98
- - [ Proposal: API Server PortForward < code >StreamTranslatorProxy</ code > ] ( #proposal-api-server-portforward-streamtranslatorproxy )
97
+ - [ Proposal: New <code >PortForward</code > Tunneling Subprotocol Version - <code >v2.portforward.k8s.io</code >] ( #proposal-new-portforward-tunneling -subprotocol-version---v2portforwardk8sio )
98
+ - [ Proposal: API Server PortForward -- Stream Tunnel Proxy ] ( #proposal-api-server-portforward----stream-tunnel-proxy )
99
99
- [ Pre-GA: Kubelet <code >StreamTranslatorProxy</code >] ( #pre-ga-kubelet-streamtranslatorproxy )
100
100
- [ Test Plan] ( #test-plan )
101
101
- [ Prerequisite testing updates] ( #prerequisite-testing-updates )
@@ -505,83 +505,26 @@ $ curl http://localhost:8080/index.html
505
505
The nginx HTTP response is returned over the same data stream. Once the subrequest is
506
506
complete, both streams are closed and removed.
507
507
508
- ### Proposal: New ` PortForward ` Subprotocol Version - ` v2.portforward.k8s.io `
509
-
510
- In order to implement ` PortForward ` over WebSockets, we propose the client attempt to
511
- upgrade the connection to WebSockets with a new ` v2.portforward.k8s.io ` subprotocol
512
- version. This new version will implement stream functionality over WebSockets
513
- which currently exists in SPDY but not WebSockets. Specifically, the WebSockets streams
514
- will implement:
515
-
516
- 1 . StreamCreate signal: A signal to the other WebSockets endpoint that a
517
- stream has been created. This communication will also contain the headers used to
518
- create the stream.
519
- 2 . StreamClose signal: A signal to the other WebSockets endpoint that the stream
520
- has been half-closed, and will not allow any further writing on the stream from
521
- the closed end.
522
- 3 . Larger stream identifier space: In order to accommodate numerous concurrent
523
- streams from many posssible portforward subrequests, we will need a large stream
524
- identifier space. It appears that SPDY implements 2^31 possible stream identifiers
525
- and we will provide four bytes for the WebSockets stream identifier to match SPDY.
526
- The size of these four bytes should not be material, since the size of the
527
- WebSockets buffer is much larger (32KB). But if we need to reduce the size of
528
- the stream identifier, we can use a ` varint ` instead of a ` uint32 ` .
529
-
530
- The WebSockets stream functionality will be implemented by encoding and decoding
531
- stream headers within the WebSockets data message. The stream header struct will
532
- look like:
533
- ```
534
- // wsStreamHeader contains the data at the beginning of a websocket binary message.
535
- type wsStreamHeader struct {
536
- MessageType byte // Create, Close, or Data
537
- StreamID uint32 // or varint if we need to optimize
538
- // Headers are only included in a Create message type. Well-known keys are:
539
- // 1. StreamType: DataStream or ErrorStream.
540
- // 2. RequestID: A unique identifier for the subrequest.
541
- // 3. Port: The remote port the stream is forwarding data to.
542
- Headers http.Header
543
- }
544
- ```
545
-
546
- ### Proposal: API Server PortForward ` StreamTranslatorProxy `
547
-
548
- ![ PortForward Stream Translator Proxy] ( ./portforward-stream-translator-proxy.png )
549
-
550
- Updated steps detailing ** requests** and ** subrequests** for the proposed ` StreamTranslatorProxy ` .
551
-
552
- 1 . ` kubectl port-forward ` makes a ** request** to the API Server to upgrade to a WebSockets
553
- streaming connection. At the API Server, the WebSockets connection is upgraded and terminated,
554
- while a legacy SPDY connection is created upstream to the container runtime.
555
- 2 . An arbitrary number of subsequent (and possibly concurrent) client ** subrequests** can be made over
556
- this previously established WebSockets connection. Example: ` curl http://localhost:8080/index.html ` .
557
- 3 . Each of these ** subrequests** creates two streams over the connection (a uni-directional
558
- error stream and a bi-directional data stream) between the client and the API Server.
559
- 4 . The API Server in turn creates a one-to-one correspondence between the WebSockets streams
560
- and upstream SPDY streams. The WebSocket streams are connected to SPDY streams by goroutines
561
- copying data between them. So each ** subrequest** spawns four goroutines to service the two
562
- streams (one for the ** subrequest** itself, as well as three to copy stream data in each
563
- direction).
564
- 5 . All the resources associated with the ** subrequest** are reclaimed once the ** subrequest**
565
- is completed.
566
-
567
- Similar to ` RemoteCommand ` , ` PortForward ` will also have a ` StreamTranslatorProxy `
568
- within the API server to route data from WebSocket streams onto upstream, legacy
569
- SPDY streams. The new portforward ` StreamTranslatorProxy ` will handle requests
570
- for WebSockets connection upgrades with a ` v2.portforward.k8s.io ` header. The
571
- portforward ` StreamTranslatorProxy ` will initially attempt to create an upstream
572
- SPDY connection to the Kubelet using the legacy ` v1.portforward.k8s.io ` header.
573
- If successful, the ` StreamTranslatorProxy ` will create a server-side WebSockets
574
- connection, returning ` 101 Switching Protocols ` to the WebSockets client. The
575
- server-side WebSockets connection will handle the ` StreamCreate ` and ` StreamClose `
576
- signals, as well as de-multiplexing WebSocket streams using the passed stream
577
- identifier. Upon receiving a ` StreamCreate ` signal on the server-side of the
578
- WebSockets connection, a WebSocket stream will be created and queued onto a
579
- stream create channel. On the other end of the channel, the ` StreamTranslatorProxy `
580
- will create a SPDY stream to associate with the WebSockets stream, using headers
581
- from the WebSockets stream. And if both portforward request streams have been
582
- created (data and error), then streaming will commence between the WebSockets
583
- and SPDY streams. Upon completion, the streams will be closed and removed. The
584
- ` StreamClose ` signal will be used to determine if the streaming has completed.
508
+ ### Proposal: New ` PortForward ` Tunneling Subprotocol Version - ` v2.portforward.k8s.io `
509
+
510
+ We propose a new PortForward version ` v2.portforward.k8s.io ` , which identifies upgrade
511
+ requests which require tunneling. PortForward tunneling transparently encodes and
512
+ decodes SPDY framed messages into (and out of) the payload of a WebSocket message.
513
+ This tunneling is implemented on the client by substituting a WebSocket connection
514
+ (which implements the ` net.Conn ` interface) into the constructor of a SPDY client.
515
+ The SPDY client reads and writes its messages into and out of this connection. These
516
+ SPDY messages are then encoded or decoded into and out of the WebSocket message payload.
517
+
518
+ ### Proposal: API Server PortForward -- Stream Tunnel Proxy
519
+
520
+ At the API Server, tunneling is implemented by sending different parameters into the
521
+ ` UpgradeAwareProxy ` . If the new subprotocol version ` v2.portforward.k8s.io ` is requested,
522
+ the ` UpgradeAwareProxy ` is called with a new ` tunnelingResponseWriter ` . This ` ResponseWriter `
523
+ contains a tunneling WebSocket connection, which is returned when the connection is
524
+ hijacked. And this tunneling WebSocket connection encodes and decodes SPDY messages
525
+ as the downstream connection within the dual concurrent ` io.Copy ` proxying goroutines.
526
+ The upstream connection is the same SPDY connection to the container (through the
527
+ Kubelet and CRI).
585
528
586
529
### Pre-GA: Kubelet ` StreamTranslatorProxy `
587
530
0 commit comments