From 8e8c7febc3679f588efd32568942d9fd3dd440cf Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 25 May 2026 10:45:35 +0800 Subject: [PATCH] feat: expose G14 preview via FRP --- deploy/frp/README.md | 22 +++++++++- deploy/frp/frpc.g14.toml | 17 ++++++++ deploy/frp/frps.dev.toml | 8 ++++ scripts/g14-gitops-render.mjs | 80 +++++++++++++++++++++++++++++++++-- 4 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 deploy/frp/frpc.g14.toml diff --git a/deploy/frp/README.md b/deploy/frp/README.md index 0930abdd..c036d799 100644 --- a/deploy/frp/README.md +++ b/deploy/frp/README.md @@ -7,8 +7,9 @@ The DEV reverse link is D601 to master edge through frp. - `hwlab-tunnel-client` owns the frp client health contract. - `hwlab-cloud-web` owns the public browser entry on port `16666`. - `hwlab-edge-proxy` owns public API/health ingress on port `16667`. -- `frps.dev.toml` reserves `16666` and `16667` only as TCP `remotePort` values; do not also bind - them as `vhostHTTPPort`, because that collides with the DEV TCP proxy. +- `frps.dev.toml` reserves D601 `16666` / `16667`, G14 `17666` / `17667`, and tunnel health `7402` + as TCP `remotePort` values; do not also bind them as `vhostHTTPPort`, because that collides with + the DEV TCP proxy. - `deploy/deploy.json` is the source for the public endpoints and FRP proxy mapping. Run `node scripts/deploy-contract-plan.mjs --check` to detect drift such as public `6666`/`6667` reuse before any future apply command. @@ -16,3 +17,20 @@ The DEV reverse link is D601 to master edge through frp. material out of band before a real deployment. - UniDesk backend, provider-gateway, and microservice proxy are not HWLAB runtime substitutes. + +## G14 public preview + +G14 uses a separate preview port range and must not reuse D601's `16666` / `16667`: + +- G14 browser endpoint: `http://74.48.78.17:17666` +- G14 API/edge endpoint: `http://74.48.78.17:17667` +- G14 frpc proxy names: `hwlab-g14-cloud-web` and `hwlab-g14-edge-proxy` +- G14 k3s Deployment: `hwlab-dev/hwlab-g14-frpc`, generated by `scripts/g14-gitops-render.mjs` +- Master frps allow-list template: `deploy/frp/frps.dev.toml` +- G14 frpc local template: `deploy/frp/frpc.g14.toml` + +Only `hwlab-cloud-web:8080` and `hwlab-edge-proxy:6667` are exposed through FRP. +Internal services, Tekton, Argo CD, registry, database, and simulator services stay ClusterIP-only. +The master-side `/opt/hwlab-frp/frps.dev.toml` may need a manual allow-list update matching `deploy/frp/frps.dev.toml` before +the G14 frpc Deployment can register `17666` and `17667`; this is an edge operation, not a D601 +client change. diff --git a/deploy/frp/frpc.g14.toml b/deploy/frp/frpc.g14.toml new file mode 100644 index 00000000..e8bb7534 --- /dev/null +++ b/deploy/frp/frpc.g14.toml @@ -0,0 +1,17 @@ +serverAddr = "74.48.78.17" +serverPort = 7000 +loginFailExit = true + +[[proxies]] +name = "hwlab-g14-cloud-web" +type = "tcp" +localIP = "hwlab-cloud-web.hwlab-dev.svc.cluster.local" +localPort = 8080 +remotePort = 17666 + +[[proxies]] +name = "hwlab-g14-edge-proxy" +type = "tcp" +localIP = "hwlab-edge-proxy.hwlab-dev.svc.cluster.local" +localPort = 6667 +remotePort = 17667 diff --git a/deploy/frp/frps.dev.toml b/deploy/frp/frps.dev.toml index 7607b065..53fab415 100644 --- a/deploy/frp/frps.dev.toml +++ b/deploy/frp/frps.dev.toml @@ -8,6 +8,14 @@ end = 16666 start = 16667 end = 16667 +[[allowPorts]] +start = 17666 +end = 17666 + +[[allowPorts]] +start = 17667 +end = 17667 + [[allowPorts]] start = 7402 end = 7402 diff --git a/scripts/g14-gitops-render.mjs b/scripts/g14-gitops-render.mjs index bb02837d..38c7805c 100644 --- a/scripts/g14-gitops-render.mjs +++ b/scripts/g14-gitops-render.mjs @@ -13,8 +13,8 @@ const defaultRegistryPrefix = process.env.HWLAB_G14_REGISTRY_PREFIX || "127.0.0. const defaultSourceRepo = process.env.HWLAB_G14_GIT_URL || "git@github.com:pikasTech/HWLAB.git"; const defaultBranch = process.env.HWLAB_G14_BRANCH || "G14"; const defaultGitopsBranch = process.env.HWLAB_G14_GITOPS_BRANCH || "G14-gitops"; -const defaultRuntimeEndpoint = "http://hwlab-edge-proxy.hwlab-dev.svc.cluster.local:6667"; -const defaultWebEndpoint = "http://hwlab-cloud-web.hwlab-dev.svc.cluster.local:8080"; +const defaultRuntimeEndpoint = process.env.HWLAB_G14_RUNTIME_ENDPOINT || "http://74.48.78.17:17667"; +const defaultWebEndpoint = process.env.HWLAB_G14_WEB_ENDPOINT || "http://74.48.78.17:17666"; const defaultProxyUrl = process.env.HWLAB_G14_PROXY_URL || "http://127.0.0.1:10808"; const defaultAllProxyUrl = process.env.HWLAB_G14_ALL_PROXY_URL || "socks5h://127.0.0.1:10808"; const defaultNoProxy = process.env.HWLAB_G14_NO_PROXY || "127.0.0.1,localhost,::1,10.0.0.0/8,10.42.0.0/16,10.43.0.0/16,192.168.0.0/16,.svc,.cluster.local,kubernetes.default.svc,registry.hwlab-ci.svc,hwlab-registry.hwlab-ci.svc"; @@ -871,12 +871,82 @@ function argoApplication(args) { }; } +function g14FrpcManifest() { + const labels = { + "app.kubernetes.io/name": "hwlab-g14-frpc", + "app.kubernetes.io/part-of": "hwlab", + "hwlab.pikastech.local/environment": "dev", + "hwlab.pikastech.local/gitops-target": "g14" + }; + return { + apiVersion: "v1", + kind: "List", + items: [ + { + apiVersion: "v1", + kind: "ConfigMap", + metadata: { + name: "hwlab-g14-frpc-config", + namespace: "hwlab-dev", + labels + }, + data: { + "frpc.toml": `serverAddr = "74.48.78.17" +serverPort = 7000 +loginFailExit = true + +[[proxies]] +name = "hwlab-g14-cloud-web" +type = "tcp" +localIP = "hwlab-cloud-web.hwlab-dev.svc.cluster.local" +localPort = 8080 +remotePort = 17666 + +[[proxies]] +name = "hwlab-g14-edge-proxy" +type = "tcp" +localIP = "hwlab-edge-proxy.hwlab-dev.svc.cluster.local" +localPort = 6667 +remotePort = 17667 +` + } + }, + { + apiVersion: "apps/v1", + kind: "Deployment", + metadata: { + name: "hwlab-g14-frpc", + namespace: "hwlab-dev", + labels + }, + spec: { + replicas: 1, + selector: { matchLabels: { "app.kubernetes.io/name": "hwlab-g14-frpc" } }, + template: { + metadata: { labels }, + spec: { + containers: [{ + name: "frpc", + image: "fatedier/frpc:v0.68.1", + imagePullPolicy: "IfNotPresent", + args: ["-c", "/etc/frp/frpc.toml"], + volumeMounts: [{ name: "config", mountPath: "/etc/frp", readOnly: true }] + }], + volumes: [{ name: "config", configMap: { name: "hwlab-g14-frpc-config" } }] + } + } + } + } + ] + }; +} + function runtimeKustomization({ source }) { return { apiVersion: "kustomize.config.k8s.io/v1beta1", kind: "Kustomization", namespace: "hwlab-dev", - resources: ["namespace.yaml", "code-agent-codex-config.yaml", "services.yaml", "health-contract.yaml", "workloads.yaml"] + resources: ["namespace.yaml", "code-agent-codex-config.yaml", "services.yaml", "health-contract.yaml", "workloads.yaml", "g14-frpc.yaml"] }; } @@ -890,6 +960,7 @@ This directory is generated from \`CI.json\`, \`deploy/deploy.json\`, and \`depl - Artifact contract: images are tagged by source git commit \`${source.short}\` and pushed to \`${args.registryPrefix}\`. - Branch split: source branch \`${args.sourceBranch}\` remains the watched code branch; generated desired state is promoted to \`${args.gitopsBranch}\`. - CD: Argo CD Application \`argocd/hwlab-g14-dev\` consumes \`${args.gitopsBranch}:deploy/gitops/g14/runtime\`. +- Public preview: FRP exposes only G14 web \`${args.webEndpoint}\` and edge/API \`${args.runtimeEndpoint}\` through \`hwlab-g14-frpc\`; D601 keeps \`:16666/:16667\`. - D601 boundary: this path does not target D601, does not use UniDesk Code Queue, and does not change D601 production traffic. - Concurrency: CI builds are per source commit and do not acquire the legacy DEV CD Lease; Argo CD reconciles the Git desired state. `; @@ -925,6 +996,8 @@ async function plannedFiles(args) { sourceRepo: args.sourceRepo, registryPrefix: args.registryPrefix, runtimePath: "deploy/gitops/g14/runtime", + publicEndpoints: { web: args.webEndpoint, runtime: args.runtimeEndpoint }, + frpDeployment: "hwlab-dev/hwlab-g14-frpc", tektonPipeline: "hwlab-ci/hwlab-g14-ci-image-publish", argoApplication: "argocd/hwlab-g14-dev" }); @@ -942,6 +1015,7 @@ async function plannedFiles(args) { putJson("runtime/services.yaml", transformListNamespace(services, deploy.namespace, labels, annotations)); putJson("runtime/health-contract.yaml", transformHealthContract(health, deploy.namespace, labels, annotations, args.runtimeEndpoint, args.webEndpoint)); putJson("runtime/workloads.yaml", transformWorkloads({ workloads, deploy, source, registryPrefix: args.registryPrefix, runtimeEndpoint: args.runtimeEndpoint, webEndpoint: args.webEndpoint })); + putJson("runtime/g14-frpc.yaml", g14FrpcManifest()); return { files, source }; }