前段时间在 K8S 中部署服务,在不通过 Ingress、ALB 暴露服务的前提下,想在本机临时访问到服务的网站还挺不容易的。无意间了解到 nps 这个内网穿透工具,正是我需要的,测试使用示例记录如下
如果你之前使用过 frp 类的工具,那么 nps 也不容错过,值得体验。
部署 NPS 服务端
服务端部署在内部、外部都能访问到的中间节点
部署 nps 服务端,这里选择的是 yisier/nps,它是基于 ehang-io/nps 的 Fork 版本,后者已经三年没有更新。
下载二进制服务
$ wget https://github.com/yisier/nps/releases/download/v0.26.17/linux_amd64_server.tar.gz
$ tar xvf linux_amd64_server.tar.gz
修改配置:conf/nps.conf
我的服务器上的 80、443 已被占用,于是修改为 8000 和 8443 端口,另外 allow_ports 是映射时自动使用的端口范围,这个范围对应的是我在防火墙放行的端口区间,auth_key 需要设定为一个随机字符串。
http_proxy_port=8000
https_proxy_port=8443
auth_key=r4g8zyFVsHxTuwXM
#auth_crypt_key =1234567812345678
allow_ports=8100-8300
tls_enable=false
部署服务
# 安装
$ ./nps install
# 启动,停止和重启可用 stop 和 restart
$ nps start
打开自带的 Web Conosle 页面,地址为 http://[服务器IP]:8081,默认用户名密码为 admin / 123
部署 nps 客户端
客户端部署在目标服务或能访问目标服务的节点上
客户端可以直接使用密钥连接到 NPS 服务端(无配置文件模式),也可以配置客户端 conf(取决于服务器是否支持),本例认证模式使用前者
首先在 Web 页面新增一个客户端,可以看到「唯一验证密钥」,客户端连接服务器的时候使用(通过 -vkey 参数指定)
从 https://github.com/yisier/nps/releases 下载二进制客户端
$ wget https://github.com/yisier/nps/releases/download/v0.26.17/linux_amd64_client.tar.gz
$ tar xvf linux_amd64_client.tar.gz
因为作者没有构建 macOS arm64 架构,所以我自己编译下电脑上使用的客户端,命令如下:
# 指定跟 server 相同的版本避免兼容性问题
$ git clone https://github.com/yisier/nps.git
$ cd nps
$ git checkout v0.26.17
$ go mod tidy
$ go build cmd/npc/npc.go
运行客户端
$ ./npc install -server=11.22.33.44:8024 -vkey=<唯一验证密钥>
$ ./npc start
输出
2024/02/06 14:49:57.341 [I] [npc.go:234] the version of client is 0.26.17, the core version of client is 0.26.0,tls enable is false
2024/02/06 14:49:58.370 [I] [client.go:73] Successful connection with server 11.22.33.44:8024
成功连接到服务器,部署完成,接下来通过 Web Console 配置规则,进行转发测试。
场景一:访问内网 Redis 服务
在上一小节,我的电脑已启动 NPS Client,来到 Web Console 控制台,左侧选择「TCP 隧道」,点击「新增」
重要的参数是「客户端ID」及「目标IP」,对于 nps 客户端来讲,我的电脑上的服务都是 127.0.0.1,所以目标 IP 填写 127.0.0.1:6379
创建后,展示信息如上,接下来通过外部服务器连接到 server 的端口,此处是随机到的 8229
进行测试(此处的端口随机范围即配置中的 allow_ports=8100-8300)
在能够访问 nps 服务端的机器上使用 Redis 客户端连接内网的 Redis
$ redis-cli -h 11.22.33.44 -p 8229
11.22.33.44:8229> set message "hello world!"
OK
(1.51s)
而后我们来到内网的电脑,可以看到 key 已被设置
这个就是最基本的内网穿透使用示例,通过服务器建立隧道,转发流量
同理,家庭内部的 NAS 等服务,也可以通过内网穿透暴露出来,从互联网上访问。
场景二:通过跳板机将 K8S 服务映射出来
环境描述,K8S 集群需要通过特定的跳板机访问,跳板机器上有 kubectl 命令
首先,创建 Memos 示例服务
apiVersion: v1
kind: Pod
metadata:
name: memos-pod
labels:
app: memos
spec:
containers:
- name: memos-container
image: neosmemo/memos:stable
ports:
- containerPort: 5230
---
apiVersion: v1
kind: Service
metadata:
name: memos-service
spec:
selector:
app: memos
ports:
- protocol: TCP
port: 5230
targetPort: 5230
创建后,服务只能在集群内部访问,执行 kubectl 命令将端口映射到跳板机器,即在跳板机器上访问 127.0.0.1:5230 可以请求到 memos 服务。
$ kubectl port-forward --namespace default svc/memos-service 5230:5230
Forwarding from 127.0.0.1:5230 -> 5230
Forwarding from [::1]:5230 -> 5230
但是跳板机是 Linux 服务器,没有界面,我们期望通过本地电脑的浏览器访问网页时,就可以借助 nps 工具。
此处省略了跳板机部署 NPS Client 的步骤,注册后客户端ID 为 4,接下来在 Web Console 新增配置一条规则
这样,通过 http://11.22.33.44:8221 即可访问到 Kubernetes 集群中的 memos-service 服务
场景三:在 K8S 集群内部署 nps-clinet 作为代理
场景二通过跳板机 + port-forward 的方式,将 K8S 内的服务临时暴露,步骤较多,稍作优化,将 NPS Client 部署到 K8S 集群中,使用上就能更加便捷灵活
在集群内创建一个测试 Pod,用于安装 NPS Client
apiVersion: v1
kind: Pod
metadata:
name: exec-pod
spec:
containers:
- args:
- '-c'
- while true; do sleep 100000; done
command:
- /bin/sh
image: alpine:3.8
imagePullPolicy: IfNotPresent
name: alpine-container
安装 NPS Client 步骤略,注册后客户端ID 为 5
创建一个 TCP 隧道,在集群内服务间访问使用的是 Service,所以目标地址应填写 memos-service.default.svc.cluster.local:5230
(这是集群内部 Memos 服务的地址,Memos 服务在场景二中创建)
这样,无需借助 port-forward,配置规则就能直接访问到集群内部服务,场景三中 NPS Client Pod 相当于一个 K8S 内服服务的跳板机。
对场景三进一步封装优化
场景三使用临时的 Pod,手动部署 NPS Client,当 Pod 重启则客户端就会丢失,不是一个稳定的部署方案,接下来构建 NPS Client 镜像,以云原生的方式在集群中部署 NPS Client。
FROM alpine:3.19
WORKDIR /app
# 设置npc客户端的环境变量
ENV NPC_VERSION=v0.26.17
ENV NPS_SERVER=
ENV NPS_VKEY=
# 安装必要的依赖
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \
apk update && apk add --no-cache ca-certificates
# https://github.com/yisier/nps/releases/download/v0.26.17/linux_amd64_client.tar.gz
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
wget -O npc.tar.gz https://mirror.ghproxy.com/https://github.com/yisier/nps/releases/download/${NPC_VERSION}/linux_arm64_client.tar.gz; \
else \
wget -O npc.tar.gz https://mirror.ghproxy.com/https://github.com/yisier/nps/releases/download/${NPC_VERSION}/linux_amd64_client.tar.gz; \
fi && tar -xzf npc.tar.gz && rm -rf npc.tar.gz conf;
# 运行npc客户端
CMD ["sh", "-c", "./npc -server=$NPS_SERVER -vkey=$NPS_VKEY && tail -f /dev/null"]
多架构构建
docker buildx build -t kissbug8720/nps-client:0.0.1 --platform=linux/arm64,linux/amd64 --push .
使用 Docker 启动
$ docker run -d --rm --name nps-client -e NPS_SERVER=11.22.33.44:8024 -e NPS_VKEY=<your-client-vkey> kissbug8720/npc-client:0.0.1
使用 Kubernetes 启动
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: npc
spec:
selector:
matchLabels:
app: npc
template:
metadata:
labels:
app: npc
spec:
containers:
- name: npc
image: kissbug8720/nps-client:0.0.1
env:
- name: NPS_SERVER
value: "11.22.33.44:8024"
- name: NPS_VKEY
value: "<your-client-vkey>"
最后放两张 NPS Console 的统计图表
前些天第一次听说 NPS 这个服务,测试后感觉功能强大、体验良好,值得后续进一步学习使用。