背景
由于国内的vps要搭建网站都需要备案,所以目前自己的一些服务是在香港的一台vps上;同时自己家里部署了一些服务比如nas需要在外部访问,当前是用另一台vps做的内网穿透,本着能省一点是一点的原则,遂想着将这两个能力放到一台vps上。
核心问题
由于不想每次访问时还需要输入端口号,最理想的方案肯定是都是用80/443端口来访问,但这样内网穿透的端口就会和ingress的端口冲突;
理想的方案是内网穿透的服务不直接占用主机端口,而是通过域名区分,需要穿透的域名转发到内网穿透服务。
解决方案
搭建步骤
vps端部署
搭建k8s集群
由于vps上资源并不富裕,所以这里我使用的是k3s,执行curl -sfL https://get.k3s.io | sh - --disable traefik
,注意我后面使用了ingress nginx所以增加了--disable traefik
参数禁止默认使用traefik,理论上traefik也行,但是后面ingress的配置可能会有点不同。
部署ingress nginx
# 添加官方 Nginx Ingress helm repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# 使用 Helm 安装 Nginx Ingress
helm install nginx-ingress ingress-nginx/ingress-nginx --namespace kube-system
部署frps
其他没啥特别的,只有service中注意frps的连接端口需要使用NodePort
apiVersion: v1
kind: Service
metadata:
labels:
app: frps-svc
name: frps-svc
namespace: frps
spec:
ports:
- name: server
port: 10000
protocol: TCP
targetPort: 10000
nodePort: 34567
selector:
app: frps-server
type: NodePort
部署cert manager
由于需要在k8s侧就要做域名的区分,所以需要将tls证书放到k8s侧,同时使用cert manager能够自动进行证书的renew,简化后续维护
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.14.2 \
--set installCRDs=true
创建letsencrypt issuer
issuer有ClusterIssuer和Issuer两种,ClusterIssuer是全集群生效,一种只在对应的namespace生效,相应的ingress需要创建在这个namespace。这里我们使用Issuer,因为我们后续需要生成泛域名证书,如果使用ClusterIssuer其中有一步报错一直没查到原因(可能是不支持)。泛域名证书的solver只能使用dns01,关于这里的配置可以参考这里,这里我是用的是Cloudflare
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-dns
namespace: frps
spec:
acme:
email: example@youmail.com
privateKeySecretRef:
name: letsencrypt-dns
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
key: api-token
name: cloudflare-api-token-secret
创建内网穿透的service
后续请求经过ingress后通过这个service转发到内网穿透服务
apiVersion: v1
kind: Service
metadata:
labels:
app: frps-http
name: frps-http
namespace: frps
spec:
ports:
- name: server-http
port: 38080
protocol: TCP
targetPort: 38080
selector:
app: frps-server
type: ClusterIP
创建ingress
注意这里创建的是泛域名的ingress,这样后续要增加服务,在vps侧是不需要增加任何配置的
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wildcard-ingress
namespace: frps
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- "*.yourdomain.com"
secretName: my-tls
rules:
- host: "*.yourdomain.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frps-http
port:
number: 38080
到这里,在vps上的配置就ok了
内网服务搭建
由于家里的服务不止一个,如果经过内网穿透直接映射到服务的endpoint,则frpc的配置就会变得比较复杂,vps侧的service也需要配置多个端口,所以我在内网再部署了一层nginx,再通过nginx转发到各个服务上,这样内网穿透就只需要配置一个80端口即可。nginx的具体配置这里就不列出来了,需要注意的是只需要配置listen 80端口即可,server name需要和vps侧配置相同。