快连VPN 官方站点 · 容器网络加速服务 镜像版本 v2.4.1 · 文档更新
实践 · 场景方案

五类场景的落地方案

同一套容器加速能力,在不同环境里要解决的问题并不相同。本文按宿主机已有出口、Kubernetes 集群、CI 构建、多出口审计、合规要求五类场景,分别给出冲突成因、配置写法与验证方式。文中所有示例配置基于 v2.4.1 的规则格式,属示例口径,可作为部署基线的起点。

01 · 场景总览

场景总览

下表是本页的核心结论:五类场景各自的典型现状、核心痛点、快连做法与预期结果。结果列描述的是配置生效后的稳定状态,不承诺具体性能数值。

表 1:五类场景的现状、痛点、做法与结果对照(示例口径,实际行为以部署环境的网络拓扑与规则配置为准)
场景 典型现状 核心痛点 快连做法 结果
宿主机已有出口 已跑着网关 / 软路由 / 其他加速进程 抢默认网关、路由回环、DNS 互相污染 容器内建独立 netns + 策略路由,main 表只读 并存
Kubernetes 集群 多租户 Pod 共用节点网络 一个节点一套出口,无法按工作负载授权 DaemonSet 注入,按 namespace / label 打标分流 按租户隔离
CI 构建 构建机拉取 npm / PyPI / Maven 依赖频繁超时 拉取慢导致流水线超时,重试推高成本 构建容器单独挂载加速 sidecar,构建机不受影响 构建提速
多出口审计 要求记录每条流量的归属与出口选择 全局加速无法解释「走了哪个出口」 规则命中即产生可导出的决策记录(仅元数据) 可审计
合规与隐私 要求零日志、密钥不落盘、数据不出境 日志含访问明细、配置留存凭据 白名单日志 + 内存加密 + 关闭 core dump 可交付审计

五类场景可以叠加使用:例如集群场景中同时满足合规要求时,DaemonSet 挂载的规则文件与注入方式不变,只是额外开启决策元数据导出。各场景的完整部署顺序见 部署文档。

02 · 场景一

场景一:宿主机已有出口

宿主机上已经跑着网关、软路由或另一套加速进程,是最常见的接入前提。关键不在于「选哪个」,而在于快连是否去动宿主机的路由与 DNS。

冲突从哪来

三处会互相干扰

默认网关抢占:两套工具都想写默认路由,后启动的覆盖先启动的,表现为原出口工具突然失效。

策略路由回环:加速流量注入后若被另一套规则再次捕获,形成回环,表现为连接无响应或吞吐塌陷。

DNS 劫持:两套进程各写一份解析配置,容器内解析结果与宿主机预期不一致,表现为偶发解析失败。

并存的做法

宿主机零改动

独立 netns:快连在容器自身的网络命名空间内建立独立命名空间,宿主机路由表不参与。

main 表只读:策略路由只写入容器自己的表,宿主机 main 表与默认网关保持原样。

DNS 分域:容器内使用独立的解析配置,宿主机原有 DNS 设置不被改写。

规则配置:默认直连 + 内网直连 + 按标签走加速

把规则默认值设为 direct,先保证宿主机原有出口在容器内也是默认行为,再显式声明需要加速的部分。这样即使规则写漏,也不会把不该走加速的流量送出去。

配置 · 宿主机已有出口时的 rules.yaml
default: direct

rules:
  # 1) 内网与云元数据永远直连,不进入加速链路
  - cidr: ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
    action: direct
  - cidr: "169.254.0.0/16"
    action: direct

  # 2) 明确标记为需要加速的工作负载
  - label: "kl.route=proxy"
    action: proxy
    protocol: hysteria2

  # 3) 镜像仓库直接拉取,不做额外处理
  - domain: ["registry.npmjs.org", "pypi.org"]
    action: direct
与全局加速客户端的核心差异

全局加速客户端工作在宿主机命名空间内,需要修改本机默认网关与 DNS,因此与既有出口工具必然冲突。快连只在容器内部建立独立的 netns 与策略路由表,宿主机路由零改动,两者可以长期并存。隔离原理见 隔离架构,规则维度的完整优先级见 分流规则优先级。

终端 · 验证宿主机路由未被改动
# 执行前记录宿主机默认网关
ip route show default

# 启动加速容器
docker run -d --name kl-proxy \
  --cap-add NET_ADMIN --device /dev/net/tun \
  -v /opt/kl/rules.yaml:/etc/kl/rules.yaml:ro \
  registry.kiualanad.com.cn/kl/kl-proxy:v2.4.1 \
  --config /etc/kl/rules.yaml --mode container

# 再执行一次,输出应与启动前完全一致
ip route show default

# 容器内确认使用的是自己的策略路由表
docker exec kl-proxy ip rule show
03 · 场景二

场景二:Kubernetes 集群

集群里的问题是出口粒度:节点级的全局配置无法区分租户。做法是用 DaemonSet 在每个节点注入快连,再由命名空间与标签决定每个工作负载走哪个出口。

DaemonSet 注入与配置挂载

DaemonSet 只负责注入快连进程与规则文件;真正的分流决策来自业务 Pod 上的 kl.route 标签。

配置 · DaemonSet 片段(示例口径)
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kl-proxy
  namespace: kl-system
  labels:
    app: kl-proxy
spec:
  selector:
    matchLabels:
      app: kl-proxy
  template:
    metadata:
      labels:
        app: kl-proxy
    spec:
      initContainers:
        - name: rules-sync
          image: registry.kiualanad.com.cn/kl/kl-proxy:v2.4.1
          command: ["sh", "-c", "cp /etc/kl-base/rules.yaml /shared/rules.yaml"]
          volumeMounts:
            - name: rules
              mountPath: /shared
      containers:
        - name: kl-proxy
          image: registry.kiualanad.com.cn/kl/kl-proxy:v2.4.1
          args: ["--config", "/shared/rules.yaml", "--mode", "node"]
          securityContext:
            capabilities:
              add: ["NET_ADMIN"]
          volumeMounts:
            - name: rules
              mountPath: /shared
      volumes:
        - name: rules
          configMap:
            name: kl-rules

业务 Pod 上声明路由意图

同一集群内不同租户用不同标签表达出口需求,规则文件负责把标签映射到出口:

配置 · 业务 Pod 与 namespace 标签
# 命名空间级标签:整个租户走同一条出口
kubectl label namespace team-a kl.route=proxy --overwrite

# 工作负载级标签:单个 Deployment 单独指定
kubectl patch deployment api-gateway -n team-a -p \
  '{"spec":{"template":{"metadata":{"labels":{"kl.route":"proxy"}}}}}'
按 namespace 分流
在 namespace 上打 kl.route 标签,规则文件用 namespace 维度匹配。适合整个租户出口一致的情况,改动面小,适合先做试点。
按 label 分流
在 Pod 或 Deployment 的 spec.template.metadata.labels 上打 kl.route 标签,规则文件用 label 维度匹配。适合同一租户内不同工作负载走不同出口。
维度优先级
标签规则优先于命名空间规则。两者冲突时以更具体的工作负载标签为准,优先级完整顺序见 分流规则优先级。
规则更新方式
规则以 ConfigMap 只读挂载,修改后通过 kubectl rollout restart 让 DaemonSet 重新加载,不需要重建业务 Pod。
多租户环境不要用节点级配置

多租户集群中一个节点通常运行多个租户的 Pod。节点级配置会让该节点上所有 Pod 共用同一出口,无法满足「按工作负载授权」的要求,也无法在审计时区分租户归属。应始终使用 namespace 级标签(或工作负载级标签)表达意图,把节点级配置留作无租户差异的内部集群使用。

04 · 场景三

场景三:CI 构建

构建机的依赖拉取是超时与重试成本的主要来源。把加速挂到构建容器上而不是构建机上,构建机本身的路由与缓存目录都不受影响。

构建容器内挂载加速

终端 · 构建阶段启动 sidecar
# 加速容器与构建容器共用同一个 network 命名空间
docker run -d --name kl-build-proxy \
  --network container:builder \
  --cap-add NET_ADMIN --device /dev/net/tun \
  -v /opt/kl/rules.yaml:/etc/kl/rules.yaml:ro \
  registry.kiualanad.com.cn/kl/kl-proxy:v2.4.1 \
  --config /etc/kl/rules.yaml --mode container

# 在构建容器内验证拉取命中加速
docker exec builder sh -c 'curl -s -o /dev/null -w "%{http_code} %{time_total}\n" https://registry.npmjs.org/'

# 构建结束后销毁,构建机上不留残留
docker rm -f kl-build-proxy

GitLab CI 接入

用 services 声明加速 sidecar,把凭据放进 variables 并在流水线内注入,不写进 .gitlab-ci.yml:

配置 · .gitlab-ci.yml 片段(示例口径)
stages:
  - build

build:app:
  stage: build
  image: node:20-bookworm
  services:
    - name: registry.kiualanad.com.cn/kl/kl-proxy:v2.4.1
      alias: kl-proxy
      command: ["--config", "/etc/kl/rules.yaml", "--mode", "container"]
  variables:
    KL_RULES: /etc/kl/rules.yaml
  before_script:
    - # 凭据由 CI 变量注入,仅存在于容器内存,不写入仓库
    - test -n "$KL_SUBSCRIPTION"
    - sh -c "curl -fsS https://registry.npmjs.org/ -o /dev/null"
  script:
    - npm ci
    - npm run build
  after_script:
    - # 任务结束即销毁,容器内不留可复用副本
    - rm -f .npmrc
  artifacts:
    when: always
    expire_in: 1 day
    paths: [dist/]
只在构建阶段存在

加速 sidecar 与构建任务同生命周期:任务开始时创建,任务结束时随作业容器一起销毁。它不安装在构建机上,不写入构建缓存目录,也不进入流水线产物。因此流水线重跑、缓存复用、产物下载这三个环节都不会把加速状态或凭据带出本次构建。凭据的存放方式见 零日志隐私栈。

05 · 场景四

场景四:多出口审计

当环境里同时存在多条出口时,需要回答的不是「流量走了哪条链路」,而是「依据哪条规则走了哪条链路」。后者只能由规则命中产生的决策记录给出。

按 namespace 分出口

用出口标识(egress)把命名空间映射到具体出口,配置里不出现任何访问明细:

配置 · 多出口映射(示例口径)
default: direct

outbounds:
  hk:   { protocol: hysteria2,        server: "hk.example.net:443" }
  sg:   { protocol: tuic,              server: "sg.example.net:443" }
  direct: { protocol: direct }

rules:
  - namespace: team-a
    action: proxy
    egress: hk
  - namespace: team-b
    action: proxy
    egress: sg
  - cidr: ["10.0.0.0/8", "169.254.0.0/16"]
    action: direct

audit:
  decision_log: true      # 仅导出决策元数据
终端 · 查看出口归属
# 查看各命名空间当前命中的出口
docker exec kl-proxy kl-ctl status

# 导出决策记录用于审计(仅规则 ID / 命中维度 / 动作 / 时间戳)
docker exec kl-proxy kl-ctl export --type decision --last 24h > decisions.jsonl
审计只含决策元数据

导出的决策记录只含规则 ID、命中维度、动作与时间戳四个字段,不含访问域名、目标 IP、会话内容与账号标识。它回答「依据哪条规则走了哪个出口」,不回答「用户访问了什么」,因此可以在不记录访问明细的前提下交付审计。字段定义与导出边界见 审计与合规边界。

06 · 场景五

场景五:合规要求

合规评审关心的不是「有没有日志」,而是「日志里有什么、密钥在哪里、崩溃时会不会落盘」。快连对这四个问题都有可验证的答案。

可交付的四类材料

日志白名单说明文档
列明白名单内的四类状态事件(启动、握手、规则加载、异常)与明确排除的五类数据(访问域名、目标 IP、连接时间、流量大小、账号标识),并附验证命令。范围定义见 日志白名单。
崩溃转储关闭验证方式
提供 docker exec kl-proxy sh -c 'ulimit -c' 的验证方法,输出 0 即为生效;同时说明 core_pattern 指向与持久卷未挂载两项检查。详见 崩溃转储关闭。
密钥生命周期表
给出各类密钥的存储位置、生命周期与销毁时机(会话密钥、订阅凭据、设备标识、规则配置四类),用于说明密钥不落盘、不入 swap、使用后立即销毁。
镜像 digest 清单
记录生产所用 tag 与完整 digest,作为交付物可复现性的依据。核对方式见 来源核验与防钓鱼,协议与端口清单见 镜像矩阵。
提交材料时的注意事项

材料中请勿附带订阅地址、访问域名清单或任何抓包内容;决策记录导出件只包含元数据,可以提交。正式材料的提交渠道与备案信息见 备案与联系方式,技术口径的完整说明见 零日志隐私栈。

07 · 常见问题

场景相关问题

以下三条是场景落地过程中最常被问到的问题。更完整的问题清单见 快连VPN 常见问题。

宿主机已经跑了软路由,还能用快连VPN 吗?

可以,两者并存。快连VPN 在容器网络命名空间内建立独立 netns 与策略路由表,main 表只读,不修改宿主机默认网关,也不接管宿主机 DNS。宿主机原有出口照常工作,容器内流量由容器自己的规则决定走哪条链路。

CI 构建加速会不会把凭据留在构建机上?

不会。加速以 sidecar 形式与构建容器一起启动,只在构建阶段存在,任务结束即整体销毁。订阅凭据只存在于容器内存加密区域,不写入构建缓存目录、不写入日志、不写入流水线产物,构建机上不留下可复用的副本。

多租户集群应该按节点还是按命名空间配置出口?

按命名空间配置。多租户环境下一个节点上会运行多个租户的 Pod,节点级配置会让所有租户共用同一出口,无法满足按工作负载授权的要求。应使用 namespace 级标签,让 DaemonSet 注入后按 namespace/label 打标分流,实现按租户隔离。