简介:这是一套面向域名服务运营者与SaaS平台开发者的DNS二级域名分发系统重构版,解决多云DNS统一纳管、会员化运营与合规风控等核心业务痛点。资源包含1371个文件,主体为681个JavaScript与400个CSS前端交互及样式文件,辅以73个PHP后端逻辑脚本、67个HTML页面模板及多种静态资源(PNG/GIF/SVG/字体等),整体压缩包仅16.93MB,轻量高效且模块边界清晰。目前已有191人学习下载,适合具备Web全栈基础的开发者二次开发或快速部署私有域名分发平台。用户可直接获得完整可运行系统:涵盖腾讯云/阿里云/Cloudflare等14家主流DNS厂商API集成代码、会员等级与折扣配置后台、多级套餐策略模板、三要素实名认证流程及违规内容实时监测逻辑,所有功能均通过可视化后台与插件化架构实现灵活扩展。
1. 派小星DNS二级域名分发V2.0重构版:不是配个bind就完事,而是让每个测试环境、每个CI流水线、每个临时分支都自动拥有「可销毁、可复现、不冲突」的二级域名
你有没有遇到过这样的场景:前端团队每天要并行测5个PR,每个PR需要独立访问地址(比如pr123.feature.demo.pai-xiao-xing.com),运维手动在DNS控制台加CNAME?后端微服务上线灰度,要临时切流到v2.api.internal.pai-xiao-xing.com,但DNS TTL设成300秒,等生效等到怀疑人生?更糟的是——某次误操作把*.demo.pai-xiao-xing.com指向了测试环境IP,生产流量全进沙箱,凌晨三点被电话叫醒。派小星DNS二级域名分发V2.0重构版,就是为解决这类「域名即资源、分发即API、失效即原子」问题而生的:它不依赖传统DNS厂商控制台,不靠人工维护Zone文件,也不用改bind配置重启服务;而是把二级域名当作可编程对象,通过HTTP API动态注册/注销,底层自动同步至权威DNS集群,并内置健康检查、权重路由、生命周期管理。适合DevOps工程师、SRE、平台基建组——如果你的团队已用上K8s Ingress、Argo CD或GitOps工作流,却还在用Excel表格管理测试域名,那这个V2.0就是你该立刻落地的「域名基础设施层」。
2. 为什么必须重构?从V1.0硬编码到V2.0声明式分发的三个技术拐点
V1.0版本本质是「DNS记录生成器」:读取一个YAML配置文件,调用云厂商SDK批量创建CNAME记录。看似能用,但实际踩坑无数——CI流水线并发创建时触发API限频、域名过期后无法自动清理、不同环境共用同一主域名导致权限越界。V2.0重构不是功能叠加,而是架构重置。我们拆解出三个不可绕过的拐点,决定了所有后续设计:
2.1 域名生命周期必须脱离「配置即终态」,走向「状态机驱动」
V1.0把域名当静态资源:create → exists → manual delete。但真实场景中,域名需响应事件:
- Git分支删除 → 对应二级域名应48小时内自动下线(非立即,防误删)
- 服务Pod就绪探针失败 → 该域名应降权至0%,而非直接删除(避免抖动)
- CI构建失败 → 该PR域名应标记为
invalid,禁止解析,但保留记录供审计
V2.0引入状态机:pending → active → degraded → expired → archived。每个状态变更触发Hook(如Slack通知、Prometheus打标、写入审计日志)。核心逻辑不在代码里硬写if-else,而由state_transition_rules.yaml定义:
# state_transition_rules.yaml - from: pending to: active condition: "dns_health_check.passed && k8s_service.ready_replicas > 0" action: ["set_ttl_60s", "send_slack_alert"] - from: active to: degraded condition: "dns_health_check.failed_count > 3" action: ["set_weight_0", "alert_pagerduty"]提示:状态机引擎选用Stateless(Java库),非自研——它支持热加载规则、可回滚版本、自带Metrics埋点。别重复造轮子,尤其当你的SLA要求99.99%时。
2.2 分发策略必须解耦「域名生成」与「DNS写入」,支持多后端混布
V1.0只支持阿里云DNS API。但现实是:核心业务用自建PowerDNS集群(合规要求),内部工具链用Cloudflare(免费额度够用),IoT设备固件升级用私有BIND+TSIG(安全隔离)。V2.0抽象出DnsProvider接口:
public interface DnsProvider { boolean upsertRecord(Hostname hostname, RecordType type, String value, int ttl); boolean deleteRecord(Hostname hostname, RecordType type); List<DnsRecord> listRecords(Hostname domainPrefix); // 仅用于审计,非运行时依赖 }对应实现类:
AliyunDnsProvider:调用AlibabaCloud SDK v5.0+,启用RequestSigner防重放PowerDnsProvider:走PowerDNS REST API v4.7,强制X-API-Key校验+IP白名单CloudflareProvider:用cloudflare-go库,支持proxied=false直通模式(避免CDN缓存干扰测试)
关键设计:所有Provider必须幂等。upsertRecord调用10次和1次效果完全一致——这是并发安全的基石。我们用hostname + record_type + value生成MD5作为幂等Key,写入Redis(带30分钟TTL),失败时查Key是否存在再决定是否重试。
2.3 主域名授权必须从「全量授权」转向「路径级委派」,杜绝越权风险
V1.0给服务账号分配pai-xiao-xing.com全域DNS管理权限。这是高危操作:一旦该账号密钥泄露,攻击者可篡改mail.pai-xiao-xing.comMX记录劫持邮件。V2.0采用DNS委派(Delegation)方案:
- 在权威DNS(如PowerDNS)中,为
demo.pai-xiao-xing.com、api.pai-xiao-xing.com、internal.pai-xiao-xing.com分别创建NS记录,指向派小星DNS服务的专用递归服务器集群 - 派小星服务只管理自己NS下的子域(如
*.demo.pai-xiao-xing.com),无权触碰pai-xiao-xing.com根域任何记录 - NS记录TTL设为300秒,变更后5分钟内全球生效,比CNAME传播快3倍
实操命令(PowerDNS CLI):
# 创建委派:将 demo.pai-xiao-xing.com 委托给派小星DNS集群 pdnsutil add-record pai-xiao-xing.com demo NS 300 "ns1.pai-xiao-xing-dns.internal." pdnsutil add-record pai-xiao-xing.com demo NS 300 "ns2.pai-xiao-xing-dns.internal." pdnsutil add-record pai-xiao-xing.com demo NS 300 "ns3.pai-xiao-xing-dns.internal." pdnsutil increase-serial pai-xiao-xing.com注意:
ns1.pai-xiao-xing-dns.internal.必须是派小星DNS集群的内网域名,且该域名本身由另一套独立DNS系统管理(形成信任链)。公网用户查询test.demo.pai-xiao-xing.com时,会先查根→查.com→查pai-xiao-xing.com的NS→再查demo.pai-xiao-xing.com的NS→最终到派小星集群。整个链路可审计、可隔离。
3. 本地跑通最小可用:用Docker Compose启动派小星V2.0核心服务(含PowerDNS后端)
别急着部署到生产。先在本地验证「域名注册→DNS生效→健康检查→自动降权」闭环。以下步骤基于macOS/Linux,Windows请用WSL2。
3.1 准备环境:拉取镜像、创建网络、初始化数据库
我们不编译源码,直接用官方发布的paixiaoxing/dns-distributor:v2.0.3镜像(SHA256:a1b2c3...)。注意:V2.0要求PostgreSQL 13+,MySQL不支持JSONB字段(用于存储状态机上下文)。
# 创建专用网络,避免端口冲突 docker network create paixiaoxing-dns-net # 启动PostgreSQL(数据持久化到当前目录/pgdata) docker run -d \ --name paixiaoxing-postgres \ --network paixiaoxing-dns-net \ -v $(pwd)/pgdata:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD=paixiaoxing2024 \ -p 5432:5432 \ -d postgres:13-alpine # 等待PostgreSQL就绪(约10秒) sleep 10 # 初始化表结构(执行SQL脚本) cat << 'EOF' | docker exec -i paixiaoxing-postgres psql -U postgres -d postgres CREATE DATABASE paixiaoxing_dns; \c paixiaoxing_dns CREATE TABLE domains ( id SERIAL PRIMARY KEY, hostname VARCHAR(255) NOT NULL UNIQUE, provider VARCHAR(50) NOT NULL, state VARCHAR(20) DEFAULT 'pending', created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), metadata JSONB ); CREATE INDEX idx_hostname_state ON domains(hostname, state); EOF3.2 启动派小星核心服务(含嵌入式PowerDNS)
V2.0内置轻量级PowerDNS Recursor(非权威模式),专用于健康检查和本地解析测试。生产环境才对接外部权威DNS。
# 启动派小星服务(配置通过环境变量注入) docker run -d \ --name paixiaoxing-distributor \ --network paixiaoxing-dns-net \ -e SPRING_DATASOURCE_URL=jdbc:postgresql://paixiaoxing-postgres:5432/paixiaoxing_dns \ -e SPRING_DATASOURCE_USERNAME=postgres \ -e SPRING_DATASOURCE_PASSWORD=paixiaoxing2024 \ -e DNS_PROVIDER=powerdns \ -e POWERDNS_API_URL=http://localhost:8081 \ -e POWERDNS_API_KEY=paixiaoxing-test-key \ -e MAIN_DOMAIN=demo.pai-xiao-xing.com \ -p 8080:8080 \ -p 53:53/udp \ -p 53:53/tcp \ paixiaoxing/dns-distributor:v2.0.3逻辑说明:
-p 53:53/udp暴露DNS端口,让本机dig命令可直连;POWERDNS_API_URL指向同网络内的PowerDNS容器(下一步启动);MAIN_DOMAIN定义委派根域,所有二级域名必须以此为后缀(如test.demo.pai-xiao-xing.com)。
3.3 启动嵌入式PowerDNS Recursor(仅用于本地验证)
# 启动PowerDNS Recursor(监听53端口,上游指向114.114.114.114) docker run -d \ --name paixiaoxing-powerdns \ --network paixiaoxing-dns-net \ -p 8081:8081 \ -e PDNS_RECURSOR_UPSTREAMS="114.114.114.114" \ -e PDNS_RECURSOR_LOCAL_ADDRESS="0.0.0.0:53" \ -e PDNS_RECURSOR_API_KEY="paixiaoxing-test-key" \ -e PDNS_RECURSOR_WEB_SERVER="yes" \ -e PDNS_RECURSOR_WEB_SERVER_PORT="8081" \ -e PDNS_RECURSOR_DNSSEC="no" \ -e PDNS_RECURSOR_CACHE_SIZE="1000000" \ -d powerdns/recursor:4.9.2-alpine3.4 发送第一条分发请求:curl注册test.demo.pai-xiao-xing.com
curl -X POST http://localhost:8080/api/v1/domains \ -H "Content-Type: application/json" \ -d '{ "hostname": "test.demo.pai-xiao-xing.com", "target": "127.0.0.1", "type": "A", "ttl": 60, "health_check": { "url": "http://localhost:8080/health", "interval_seconds": 10, "timeout_seconds": 3, "unhealthy_threshold": 2 } }'成功返回:
{ "id": 1, "hostname": "test.demo.pai-xiao-xing.com", "state": "pending", "created_at": "2024-06-15T10:20:33.123Z" }此时查数据库:
SELECT hostname, state, metadata FROM domains WHERE hostname = 'test.demo.pai-xiao-xing.com'; -- 返回 state=pending, metadata包含health_check配置3.5 验证DNS解析:dig命令看到A记录,且健康检查生效
# 设置本机DNS为派小星服务(临时) echo "nameserver 127.0.0.1" | sudo tee /etc/resolver/paixiaoxing # 查询解析结果(应返回127.0.0.1) dig @127.0.0.1 test.demo.pai-xiao-xing.com A +short # 查看健康检查日志(派小星服务日志) docker logs paixiaoxing-distributor | grep "health check for test.demo" # 模拟服务宕机:停掉派小星服务,观察状态是否变为degraded docker stop paixiaoxing-distributor sleep 15 docker logs paixiaoxing-distributor 2>&1 | grep "degraded"参数说明:
ttl=60是DNS缓存时间,V2.0默认设为60秒(非传统300秒),因二级域名生命周期短;health_check.interval_seconds=10表示每10秒探测一次,配合unhealthy_threshold=2,连续2次失败即触发降权;target="127.0.0.1"是测试IP,生产环境替换为K8s Service ClusterIP或Ingress IP。
4. 避坑指南:V2.0上线前必须跨过的5个血泪深坑
V2.0重构最大的教训是:DNS不是状态less服务,而是强状态、弱一致性、高敏感的基础设施。以下5个坑,我们在线上环境真实踩过,修复耗时合计127小时。
4.1 现象:域名注册后DNS解析始终超时,dig返回SERVFAIL
原因:PowerDNS Recursor配置中PDNS_RECURSOR_DNSSEC="yes"(默认值),但派小星委派的demo.pai-xiao-xing.com未配置DS记录,导致DNSSEC验证失败。Recursor拒绝返回结果。
解决:启动PowerDNS时显式设置-e PDNS_RECURSOR_DNSSEC="no"。生产环境若需DNSSEC,必须在父域(pai-xiao-xing.com)的DNS提供商处添加DS记录,且派小星集群需配置对应的DNSKEY。
4.2 现象:并发注册100个域名时,部分请求返回500 Internal Server Error
原因:PostgreSQL连接池默认最大连接数10,V2.0的健康检查线程池(默认20线程)和API线程池争抢连接,触发org.postgresql.util.PSQLException: FATAL: remaining connection slots are reserved for non-replication superuser connections。
解决:在application.yml中调大连接池:
spring: datasource: hikari: maximum-pool-size: 50 minimum-idle: 10 connection-timeout: 30000同时限制健康检查线程数:health.check.thread.pool.size=10。
4.3 现象:*.demo.pai-xiao-xing.com泛解析生效,但test.demo.pai-xiao-xing.com具体记录不生效
原因:PowerDNS权威模式下,泛解析(wildcard)记录优先级高于精确匹配。V2.0默认为每个域名创建独立A记录,但若管理员手动在PowerDNS中添加了*.demo.pai-xiao-xing.comCNAME,会覆盖精确记录。
解决:禁用泛解析!在PowerDNS Zone配置中移除所有*记录。V2.0的「按需创建」机制已足够支撑动态分发,泛解析是反模式。
4.4 现象:修改MAIN_DOMAIN配置后,旧域名无法自动迁移,新域名注册失败
原因:MAIN_DOMAIN是硬编码在状态机规则和Provider路由中的。V2.0不支持运行时热切换主域名,必须停服更新。
解决:制定迁移计划——
- 新建
v2-demo.pai-xiao-xing.com委派(与旧demo.pai-xiao-xing.com并存) - 将新业务流量导向新域,旧域进入只读(禁止新注册)
- 旧域下所有域名自然过期(
expired状态)后,执行DELETE FROM domains WHERE main_domain = 'demo.pai-xiao-xing.com' - 更新配置,重启服务
血泪经验:主域名是DNA级配置,V2.0设计时就应预留
domain_alias字段,支持多主域共存。我们已在V2.1 PR中补上。
4.5 现象:K8s Pod IP变更后,DNS记录未自动更新,仍指向旧IP
原因:V2.0的健康检查只判断服务是否存活(HTTP 200),不感知IP变化。当Deployment滚动更新时,新Pod IP写入Service Endpoints,但派小星未监听K8s Event。
解决:启用K8s Webhook集成(非默认开启)。在application.yml中配置:
kubernetes: enabled: true config: kubeconfig-path: "/etc/kube/config" namespace: "default" service-name: "my-service"派小星会监听Endpoints事件,IP变更时触发upsertRecord。注意:此功能要求K8s RBAC权限endpoints/list,endpoints/watch。
5. 进阶技巧:用Webhook实现「Git分支→二级域名→自动HTTPS」全链路闭环
V2.0最值得投入的进阶用法,不是堆功能,而是打通「代码提交」到「域名可用」的最后一公里。我们用GitHub Webhook + Certbot + Nginx Ingress,实现:git push origin feat/login → GitHub触发Webhook → 派小星创建feat-login.demo.pai-xiao-xing.com → Nginx Ingress自动申请Let's Encrypt证书 → 前端可HTTPS访问
5.1 步骤一:配置GitHub Webhook,推送分支事件
在GitHub仓库Settings → Webhooks → Add webhook:
- Payload URL:
http://your-paixiaoxing-host:8080/api/v1/webhook/github - Content type:
application/json - Which events:
Pull requests,Branches(勾选Create和Delete) - Secret:
gh-webhook-secret-2024(V2.0配置github.webhook.secret)
V2.0内置Webhook处理器,自动解析事件:
ref_type == "branch"且ref == "feat/login"→ 创建feat-login.demo.pai-xiao-xing.comref_type == "branch"且ref == "feat/login"且action == "deleted"→ 标记域名expired
5.2 步骤二:Nginx Ingress自动签发HTTPS证书(Certbot + DNS-01)
关键:不用HTTP-01(需暴露80端口),用DNS-01挑战,全程内网完成。
在K8s集群中部署Certbot + RFC2136插件(支持PowerDNS):
# certbot-rfc2136.yaml apiVersion: batch/v1 kind: Job metadata: name: certbot-dns-01 spec: template: spec: containers: - name: certbot image: certbot/certbot:latest args: - certonly - --non-interactive - --agree-tos - --email admin@pai-xiao-xing.com - --dns-rfc2136 - --dns-rfc2136-credentials /etc/rfc2136/credentials.ini - --dns-rfc2136-propagation-seconds 30 - -d feat-login.demo.pai-xiao-xing.com volumeMounts: - name: credentials mountPath: /etc/rfc2136/credentials.ini subPath: credentials.ini volumes: - name: credentials secret: secretName: rfc2136-credentialsrfc2136-credentials.ini内容(PowerDNS API Key):
[default] server = paixiaoxing-powerdns.paixiaoxing-dns-net.svc.cluster.local port = 53 key_name = paixiaoxing-test-key key_secret = base64-encoded-key algorithm = HMAC-SHA512注意:Certbot的RFC2136插件要求PowerDNS开启
allow-axfr-ips和allow-notify,且key_secret必须Base64编码(echo -n "your-key" | base64)。
5.3 步骤三:Nginx Ingress关联证书,自动路由
Ingress资源定义(自动绑定证书):
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: feat-login-ingress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: "letsencrypt-prod" spec: tls: - hosts: - feat-login.demo.pai-xiao-xing.com secretName: feat-login-tls # Certbot生成的Secret名 rules: - host: feat-login.demo.pai-xiao-xing.com http: paths: - path: / pathType: Prefix backend: service: name: feat-login-service port: number: 805.4 效果验证:从提交到HTTPS可用,全流程耗时统计
| 步骤 | 耗时 | 触发条件 | 验证方式 |
|---|---|---|---|
| GitHub Push → Webhook到达派小星 | <1s | GitHub事件推送 | docker logs paixiaoxing-distributor | grep "webhook received" |
| 派小星创建域名记录 | 2.3s | 调用PowerDNS API | dig feat-login.demo.pai-xiao-xing.com A +short返回IP |
| Nginx Ingress发现新Host → 触发Certbot | 8s | Ingress Controller监听 | kubectl get certificate显示Ready=True |
| Let's Encrypt DNS-01验证完成 | 45s | PowerDNS写入TXT记录 | dig _acme-challenge.feat-login.demo.pai-xiao-xing.com TXT |
| 浏览器访问HTTPS | ≤60s | 浏览器发起TLS握手 | curl -I https://feat-login.demo.pai-xiao-xing.com返回200 OK |
总耗时 ≤60秒。对比V1.0人工操作(平均12分钟),效率提升12倍。更重要的是:零人工干预、零配置漂移、零证书过期风险。
我坚持把这套流程写进CI/CD文档,而不是藏在某个工程师脑子里。去年Q3,我们团队用这套方案支撑了217个并行分支,峰值同时在线域名432个,全年DNS相关故障0起。真正的稳定性,不是靠人盯,而是靠设计——让每个环节都有明确的输入、确定的输出、可验证的状态。希望帮到你。
本文还有配套的精品资源,点击获取