Skip to content

Gateway K8s Manifests (OpenResty + Redis) #233

@test3207

Description

@test3207

Gateway Config: OpenResty + Redis + Lua 导流

Parent Issue: #204

Status: ⏸️ Phase 1 Complete, Lua 导流待实现


架构设计

多 Region 数据隔离

  • 不同 region 的 DB 不互通
  • 用户通过 GitHub ID 绑定到特定 region
  • Gateway + Redis 负责导流

导流逻辑

┌─────────────────────────────────────────────────────────────────┐
│                   Gateway (OpenResty + Lua)                     │
│                                                                 │
│  Request 进入 →                                                 │
│    1. 检查 Header: X-M3W-Region                                 │
│       ├── 有 → 直接导流到对应 region backend                    │
│       └── 无 → 继续                                             │
│    2. 检查是否登录 (有 JWT/Cookie)                              │
│       ├── 有 → 解析 GitHub ID → 查 Redis                       │
│       │       ├── 找到 → 导流到对应 region                      │
│       │       └── 没找到 → 就近分配 (新用户)                    │
│       └── 无 → 就近分配 (未登录)                                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

场景处理

场景 Gateway 行为 Backend 行为
已登录 + Header 直接导流 正常处理
已登录 + 无 Header 查 Redis 导流 正常处理
新用户 就近分配 + 写 Redis 注册成功返回 X-M3W-Region
未登录老用户 随便走 走错了返回 X-M3W-Region: <correct>
走错 region - 检测 GitHub ID 不存在 → 返回正确 Header

Redis 数据结构

# GitHub ID → Region 映射
SET user:region:12345 "jp"
SET user:region:67890 "sea"

# 可选: TTL 刷新
SETEX user:region:12345 86400 "jp"

当前状态 (2025-12-21)

✅ 已完成

  • OpenResty 容器运行
  • SSL 配置 (Let's Encrypt)
  • client_max_body_size 100M
  • Proxy 到 K3s via WireGuard
  • Redis 容器运行

⏳ 待实现 (多 region 时)

  • Lua 脚本解析 JWT/Cookie
  • Lua 查询 Redis 获取 region
  • 新用户写入 Redis
  • Backend 返回 X-M3W-Region Header
  • Frontend 存储并发送 Header

Lua 导流脚本 (设计)

-- /usr/local/openresty/nginx/lua/route.lua

local redis = require "resty.redis"
local jwt = require "resty.jwt"

local function get_user_region()
    -- 1. 检查 Header
    local region = ngx.req.get_headers()["X-M3W-Region"]
    if region then
        return region
    end
    
    -- 2. 解析 JWT 获取 GitHub ID
    local auth = ngx.req.get_headers()["Authorization"]
    if not auth then
        return nil  -- 未登录,就近分配
    end
    
    local jwt_obj = jwt:load_jwt(auth:sub(8))  -- 去掉 "Bearer "
    if not jwt_obj.valid then
        return nil
    end
    
    local github_id = jwt_obj.payload.sub
    
    -- 3. 查 Redis
    local red = redis:new()
    red:connect("127.0.0.1", 6379)
    local region = red:get("user:region:" .. github_id)
    red:close()
    
    if region and region ~= ngx.null then
        return region
    end
    
    return nil  -- 新用户
end

local function route_to_backend()
    local region = get_user_region()
    
    local backends = {
        jp = "10.10.0.2:30080",
        sea = "10.10.0.3:30080",  -- 未来
    }
    
    -- 默认就近 (根据 Gateway 位置)
    local default_region = os.getenv("GATEWAY_REGION") or "jp"
    local target = backends[region] or backends[default_region]
    
    ngx.var.backend = target
end

route_to_backend()

nginx 配置 (设计)

http {
    lua_package_path "/usr/local/openresty/nginx/lua/?.lua;;";
    
    upstream backend {
        server 0.0.0.1;  # placeholder
        balancer_by_lua_block {
            local balancer = require "ngx.balancer"
            balancer.set_current_peer(ngx.var.backend)
        }
    }
    
    server {
        set $backend "";
        
        location /api/ {
            access_by_lua_file /usr/local/openresty/nginx/lua/route.lua;
            proxy_pass http://backend;
        }
    }
}

当前简化配置

单 region 时不需要 Lua 导流,直接 proxy:

server {
    listen 443 ssl http2;
    client_max_body_size 100M;
    
    location / {
        proxy_pass http://10.10.0.2:30080;  # 唯一 backend
    }
}

相关 Issue

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions