目录
概述
测试环境安装和配置
创建UDP服务器
创建Quilkin代理服务器
创建UDP NLB外网负载均衡
配置和启动Quilkin
概述
Quilkin 是一个由谷歌团队创建并开源的 UDP 代理项目。它的主要目的是为游戏服务器提供一个通用的 UDP 接入控制层,可以做到攻击防御、访问控制、流量监控等常用功能。这个代理服务可以方便地以分布式集群的方式部署到谷歌云上,并配合谷歌负载均衡和应用防火墙对后端游戏服务做到全面的攻击防护。本文用实例介绍如何部署和配置这一服务。
本文搭建的测试环境架构如下图所示。在前端搭建一个区域负载均衡 NLB 转发客户端 UDP 请求。在 NLB 后方是一个 Quilkin 服务器实例组(本例组里只有一台)负责验证 UDP 包并向后转发。在 Quilkin 服务器后方是一组 UDP 服务器(本例组里只有一台),负责处理和响应 UDP 包,每个 UDP 服务器会有一个单独的 Token,而 Quilkin 服务器会根据客户端请求 UDP 包里携带的 Token 来匹配 UDP 服务器并定向转发。Token 无法匹配的 UDP 请求包,会在 Quilkin 服务器上被视为非法请求包而丢弃。

测试环境安装和配置
创建 UDP 服务器
用下面命令创建一台 Ubuntu 虚机,并配置其防火墙规则。放行 UDP 8000端口是为了允许前端 UDP 请求通过,允许 TCP 80端口是为了让负载均衡健康检查请求通过,允许 TCP 22端口是为了方便 SSH 登录安装和配置所需要的服务,允许 TCP 9091是为了访问 Quilkin 的管理界面。
gcloud compute instances create udp-server --project=youzhi-lab --zone=asia-southeast1-b --machine-type=n1-standard-1 --network-interface=network-tier=PREMIUM,subnet=default --maintenance-policy=MIGRATE --tags=udp-server --create-disk=auto-delete=yes,boot=yes,device-name=udp-server,image=projects/ubuntu-os-cloud/global/images/ubuntu-1804-bionic-v20211115,mode=rw,size=100,type=projects/youzhi-lab/zones/asia-southeast1-b/diskTypes/pd-balanced --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any
gcloud compute --project=youzhi-lab firewall-rules create default-vpc-all-udp --direction=INGRESS --priority=1000 --network=default --action=ALLOW --rules=tcp:22,80,8000,9091,udp:8000 --source-ranges=0.0.0.0/0 --target-tags=udp-server |
通过 SSH 登录到刚创建好的 udp-server 虚机上,安装 nginx 以便响应健康检查请求。
sudo apt update sudo apt install nginx |
运行以下命令将 ncat 启动为一个后台进程,并使其向 UDP 请求端返回相同内容的 UDP 包。
nohup ncat -e $(which cat) -k -u -l 8000 & |
创建Quilkin 代理服务器
用下面命令创建一台 Ubuntu 虚机,并使用与 udp-server 相同的网络标签来共用之前的防火墙规则。
gcloud compute instances create quilkin-proxy --project=youzhi-lab --zone=asia-southeast1-b --machine-type=n1-standard-1 --network-interface=network-tier=PREMIUM,subnet=default --maintenance-policy=MIGRATE --tags=udp-server --create-disk=auto-delete=yes,boot=yes,device-name=udp-server,image=projects/ubuntu-os-cloud/global/images/ubuntu-1804-bionic-v20211115,mode=rw,size=100,type=projects/youzhi-lab/zones/asia-southeast1-b/diskTypes/pd-balanced --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any |
通过 SSH 登录到刚创建好的 udp-server 虚机上,安装 nginx 以便响应健康检查请求。
sudo apt update sudo apt install nginx |
安装 GCP 监控服务客户端 agent,以便监控内存等资源消耗。
curl -sSO https://dl.google.com/cloudagents/add-monitoring-agent-repo.sh sudo bash add-monitoring-agent-repo.sh --also-install |
从 quilkin 的 release 列表页找到并下载最新版本的 quilkin 安装包,并解压安装。
wget https://github.com/googleforgames/quilkin/releases/download/v0.2.0/quilkin-0.2.0.zip unzip quilkin-0.2.0.zip cp target/x86_64-unknown-linux-gnu/release/quilkin ./ |
创建 UDP NLB 外网负载均衡
为了让 quilin 代理服务器池化,需要创建一个外网 UDP 网络负载均衡(Network Load Balance),以便将客户端从互联网发来的 UDP 请求均匀分发到各 quilkin 代理服务器。注意本示例为了简化安装过程只配置了一台 quilkin 代理服务器。通过下面命令创建组成网络负载均衡的各组件,包括实例组、后端服务以及转发规则。健康检查可以复用前面创建的 HTTP 健康检查而不用再创建。
gcloud compute instance-groups unmanaged create umig-quilkin-proxy --project=youzhi-lab --zone=asia-southeast1-b
gcloud compute instance-groups unmanaged add-instances umig-quilkin-proxy --project=youzhi-lab --zone=asia-southeast1-b --instances=quilkin-proxy
gcloud compute backend-services create be-quilkin-proxy-nlb --protocol=udp --region=asia-southeast1 --health-checks=hc-quilkin-http-80 --health-checks-region=asia-southeast1
gcloud compute backend-services add-backend be-quilkin-proxy-nlb --region=asia-southeast1 --instance-group=umig-quilkin-proxy --instance-group-zone=asia-southeast1-b
gcloud compute forwarding-rules create fr-quilkin-proxy-nlb --region=asia-southeast1 --load-balancing-scheme=external --ip-protocol=UDP --ports=8000 --backend-service=be-quilkin-proxy-nlb --backend-service-region=asia-southeast1 |
命令执行完成后,可以在控制台负载均衡列表页找到这个新建的 UDP 网络负载均衡,并查看其详情状态。注意查看其前端 IP,以便后面配置给发送请求的客户端。
配置和启动 Quilkin
谷歌云的网络负载均衡是通过将 LB IP 加到各后端服务器 iptables 的方式将客户端请求包透明转发到服务器,而不做 NAT 地址翻译。其回包为 DSR 方式,但是默认会使用服务器的内网 IP 作为源地址,然后在出网前被 GCE 网关替换为该虚机的公网 IP,而不是LB IP。这样客户端的操作系统收到回包后会因为不识别回包中的源 IP 而将其丢弃,而不转交给应用。为了解决这个问题,可以在 quilkin 代理服务器上配置一个 iptables 规则,改写入向 UDP 包的目的地址,以及出向 UDP 包的源地址。操作如下。
登录到 quilkin-proxy 虚机上运行以下命令。其中34.124.214.188是 UDP 网络负载均衡的前端 IP。
LOCAL_IP=`curl -H Metadata-Flavor:Google http://metadata/computeMetadata/v1/instance/network-interfaces/0/ip` sudo iptables -t nat -A POSTROUTING -j RETURN -d $LOCAL_IP -p udp --dport 8000 sudo iptables -t nat -A PREROUTING -j DNAT --to-destination $LOCAL_IP -d 34.124.214.188 -p udp --dport 8000 |
下面配置和启动 Quilkin 服务。登录到 quilkin-proxy 代理服务器上创建一个配置文件,其中配置一个转发端点为10.148.15.204,即 UDP 服务器的内网地址。
version: v1alpha1 proxy: port: 8000 static: filters: - name: quilkin.extensions.filters.debug.v1alpha1.Debug config: id: debug-1 - name: quilkin.extensions.filters.capture_bytes.v1alpha1.CaptureBytes config: strategy: PREFIX metadataKey: myapp.com/security_token size: 4 remove: false - name: quilkin.extensions.filters.token_router.v1alpha1.TokenRouter config: metadataKey: myapp.com/security_token endpoints: - address: 10.148.15.204:8000 metadata: quilkin.dev: tokens: - MTIzNA== |
注意配置中开启了 debug filter,这样会将所有包的处理打印在标准输出,方便查看效果。另外用到了 CaptureBytes 和 TokenRouter 两种 filter,实现从入向 UDP 包的前部截取安全口令,然后通过口令来转发到匹配的后端端点。而唯一一个合法端点的口令设置为了“MTIzNA==”,即“1234”的 Base64字符串。
配置完后启动 Quilkin 服务,并保留窗口观察其输出。
./quilkin run --config proxy.yaml |
在笔记本上打开一个 Terminal 窗口,并执行如下命令nc -u 34.124.214.188 8000 1234 1234 test |
可以看到 Quilkin 的输出窗口有以下日志输出,表明“1234”这个包被匹配和转发到了10.148.15.204这个端点,即我们配置的内网负载均衡,而“test”这个包则在收到后没有匹配到端点,被丢弃了。这个结果说明 Quilkin 的配置正确并符合预期。
{"msg":"Read filter event","level":"INFO","ts":"2021-12-05T10:36:26.062553342+00:00","id":"debug-1","source":"extensions::Debug","source":"run","contents":"1234","from":"203.208.61.208:34763"} {"msg":"Write filter event","level":"INFO","ts":"2021-12-05T10:36:26.065945594+00:00","id":"debug-1","source":"extensions::Debug","source":"run","contents":"1234","to":"203.208.61.208:34763","from":"10.148.15.204:8000","endpoint":"10.148.15.204:8000"} {"msg":"Read filter event","level":"INFO","ts":"2021-12-05T10:37:12.553678852+00:00","id":"debug-1","source":"extensions::Debug","source":"run","contents":"test","from":"203.208.61.208:34763"} |
现在,注释掉 proxy.yaml 中 debug filter,然后再用后台进程方式启动 quilkin 代理。
#- name: quilkin.extensions.filters.debug.v1alpha1.Debug #config: #id: debug-1 |
nohup ./quilkin run --config proxy.yaml & |
在浏览器打开 http://34.87.5.28:9091/metrics 可以看到这台虚机上 Quilkin 服务的监控指标。
