# 通过 VS Code 优雅地编辑 Pod 内的代码（非 NodePort）


## 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 中支持类似如下配置：

```yaml
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 里装上 `Kubernetes` 和 `Dev Containers` 两个插件：

![](1.png)

然后就能直接 Attach 进 Pod 了：

![](2.png)

如上图，找到你放代码的 Pod，然后右键 - “Attach Visual Studio Code”，接着会弹出一个新的 VS Code：

![](3.png)

然后你就可以像操作本地文件系统一样，在这个新的 VS Code 里点击 Open Folder 来打开你在 Pod 内的某个目录了。如下图，我这里在容器内放了一个 gopool 项目的代码，效果是这样的：

![](4.png)

还不错吧，你可以开始愉快地开发了。

## 5. 其他

不好，中午吃多了，犯困了。就这样吧，留点东西下次再发。

我知道你还好奇这2个插件的工作原理；我也知道这套方案要落地还差了权限控制（RBAC 控制一个用户只能访问自己名下的 Pods）；我也知道你要睡午觉了……

Anyway，关注公众号“胡说云原生”，咱“明天”见。

