通過 VS Code 優雅地編輯 Pod 內的程式碼(非 NodePort)

2023-12-13 15:00:50

1. 概述

今天聊點啥呢,話說,你有沒有想過怎樣用 VS Code 連上 K8s 叢集內的某個 Pod,然後直接更新 Pod 內的程式碼?

當我聽到這個需求的時候,第一反應是在 Pod 內搞一個 sshd,然後 NodePort 方式暴露 Pod,接著用 VS Code 的某個遠端偵錯外掛。當然我沒有具體用過 VS Code 遠端開發的能力,不過我用過 Goland 裡類似的功能,總之這些 IDE 一定有辦法存取遠端的檔案系統,通過一些 FTP/SFTP 之類的協定完成檔案傳輸/同步的過程。

再進一步,如果將這個功能做到產品裡,那用 NodePort 就有點 low 了,畢竟暴露一堆的埠,很多場景下是不允許的,所以下一步自然就想到了 Ingress。

不過 Ingress 只能轉發 http/https 或者 TCP/UDP 流量,你發現沒有,這裡其實不支援 ssh/ftp 這類協定……

行,今天就聊聊怎樣在不暴露一堆 NodePort 的前提下,通過 VS Code 更新 Pod 內的程式碼。

2. NodePort 方式

NodePort 方式暴露 Pod 的 sshd 服務是最容易被想到的方案,這種方式在邏輯上沒有啥問題,NodePort 將 Pod 的 ip:pod 對映到 Nodes 的特定埠,從而實現 TCP 流量轉發(SFTP 協定下面是 SSH,SSH 協定在傳輸層用的是 TCP)。

在這個方案下,每個使用者最後會佔用一個 Nodes 層面的埠。換言之,單使用者,本地測試開發,沒問題。但是作為一個產品,部署上線,那你要麼做好和公司的運維、安全團隊辯論的準備,要麼另尋出路。

3. Ingress 方式

為了解決 NodePort 方式佔用多埠的問題,其實很容易往 Ingress 方向考慮,儘管 Ingress 一般用在 http 負載的代理上。不過大家可能會進一步想到 Ingress 設定的時候,不是可以根據 host 路由嘛。那是不是在使用者端 hosts 裡設定一堆的 域名/IP 對映關係,然後在 Ingress 里根據 host 區分使用者,從而實現不同使用者的流量轉發到不同 Pod 的目的?

再往前想一步,其實 host 是 http 流量轉發的時候用到的規則,也就是在 http 請求頭裡的屬性,這個不能用在非 http 流量上。

那麼往 TCP 流量代理的方向去考慮呢?比如 Traefik 實現的 Ingress Control 中支援類似如下設定:

apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
  name: ssh-ingress-route
spec:
  entryPoints:
    - ssh
  routes:
    - match: HostSNI(`user1.example.com`)
      services:
        - name: ssh-service
          port: 22
  tls:
    passthrough: true

是不是看起來挺和諧的?TCP 流量,根據 host 資訊區分流量。

然而這個 SNI 資訊是 SSL 協定裡用到的,也就是用到 TLS 才能用這個特性,SSH 協定其實並不使用 TLS,換言之,這個欄位設定不設定,對 SSH 流量來說,沒啥用。

對於 TCP 包來說,包頭有 IP 和 Port 資訊,並沒有 host,所以代理層是無法區分網路流量來自哪個使用者的,自然也就不能相應轉發到不同的 Pod 中去。

那麼有沒有支援 SSH 協定的 Ingress Control 實現呢?我瞟了下,沒找到。如果你找到了,可以在評論區告訴我。

4. 救命稻草

Ingress 這條路走不通了,其實就是 TCP 沒有 host 欄位,回過頭來我們還是要依賴 http 協定的 host 屬性。不過檔案傳輸協定裡可不包含 http,用 http 協定轉發「遠端偵錯」這類流量,想想,應該沒有人去這樣實現。

除了 Ingress 這個口子外,和 K8s 互動的另外一個入口就是 apiserver 了,就像 kubectl 可以用 exec/logs 之類的子命令和 Pod 建立長連線一樣,或許有人會做一些外掛,通過和 apiserver 互動實現 Pod 內檔案的操作呢?

OK,直接說答案:在 VS Code 裡裝上 KubernetesDev Containers 兩個外掛:

然後就能直接 Attach 進 Pod 了:

如上圖,找到你放程式碼的 Pod,然後右鍵 - 「Attach Visual Studio Code」,接著會彈出一個新的 VS Code:

然後你就可以像操作本地檔案系統一樣,在這個新的 VS Code 裡點選 Open Folder 來開啟你在 Pod 內的某個目錄了。如下圖,我這裡在容器內放了一個 gopool 專案的程式碼,效果是這樣的:

還不錯吧,你可以開始愉快地開發了。

5. 其他

不好,中午吃多了,犯困了。就這樣吧,留點東西下次再發。

我知道你還好奇這2個外掛的工作原理;我也知道這套方案要落地還差了許可權控制(RBAC 控制一個使用者只能存取自己名下的 Pods);我也知道你要睡午覺了……

Anyway,關注公眾號「胡說雲原生」,咱「明天」見。