上线全景:从代码到公网可访问

一次请求的完整链路与三种部署形态

本地 npm run dev 能打开页面,和用户在手机上打开 https://your-domain.com 是两件事。中间隔着域名解析、备案、安全组、防火墙、运行时、进程守护、反向代理、证书、备份与监控十来个环节,任何一个环节漏掉,用户看到的就是超时或 502。本章先把这些环节串成一条链路,再给出上线前的准备清单和三种部署形态的取舍。

上线链路上到底有哪些组件

组件作用国内常见选择
入口域名 + DNS 解析把域名指向公网 IP阿里云 DNS、腾讯云 DNSPod、Cloudflare
合规ICP 备案国内节点用域名对外提供服务的前置条件阿里云/腾讯云备案系统
加速CDN / 对象存储静态资源就近分发、证书卸载阿里云 CDN + OSS、腾讯云 CDN + COS
网络云安全组 + 主机防火墙两层准入控制,决定谁能连哪个端口安全组 + ufw / firewalld
主机云服务器(ECS/CVM)跑应用的计算与存储资源阿里云 ECS、腾讯云 CVM、轻量应用服务器
运行时Python / Node / Go / Java应用运行所需的语言环境pyenv、nvm、官方 tar、SDKMAN
进程Docker / systemd / Supervisor拉起进程、崩溃重启、开机自启优先 systemd,容器化优先 Docker
代理Nginx反向代理、静态站点、HTTPS 终止、gzipNginx 官方源或发行版包
证书TLS 证书加密传输,浏览器不报不安全阿里云/腾讯云免费证书、Let's Encrypt
数据MySQL / Redis / 对象存储业务数据与缓存云数据库 RDS、自建容器
保障备份 + 监控 + 日志出事能恢复、出事能提前知道定时 dump 到 OSS、Uptime 探活、日志轮转

自顶向下的链路图

用户浏览器 / App
   ↓ ① DNS 解析:example.com → 47.x.x.x(TTL 决定生效快慢)
   ↓ ② CDN(可选):静态资源命中边缘节点,回源到 Nginx
   ↓ ③ 云安全组:放行 80 / 443,其余端口默认拒绝
   ↓ ④ 主机防火墙(ufw / firewalld):只放行 22 / 80 / 443
Nginx(HTTPS 终止 + 反向代理 + 静态站点)
   ↓ ⑤ proxy_pass 到上游
应用进程 127.0.0.1:8000(Docker 容器 / systemd 服务)
   ↓ ⑥ 读写数据
MySQL 127.0.0.1:3306 / Redis 127.0.0.1:6379(绝不监听 0.0.0.0)
   ↓ ⑦ 备份与监控
每日 dump 上传对象存储 + 探活告警 + 日志轮转

排障时倒着看这张图:浏览器打不开就先查 ① 解析,curl 通但浏览器红字就查证书,Nginx 返回 502 就往 ⑤ 后面的应用进程查,几乎不会错。

三种部署形态对比

维度裸机 + systemd/SupervisorDocker / ComposeKubernetes
适用规模1~3 台、单体应用1~10 台、多服务单体集群多集群、多团队、需要弹性伸缩
环境一致性靠文档和自律,容易漂移镜像即环境,一致性好同 Docker,且声明式编排
首次上手成本最低,会写 unit 文件即可中,需要懂镜像与网络高,集群、Ingress、存储一堆概念
回滚速度换目录 + reload,秒级换镜像 tag,秒级换镜像 tag,秒级
资源开销最小,无额外常驻进程每容器几十 MB 开销控制面自身就要几 GB
典型痛点依赖冲突、机器多了难同步数据卷与网络要提前规划复杂度过剩,小团队维护不动

选择建议很直接:单机部署用 systemd 或 Compose 就够;只有当服务数量、机器数量、发布频率三者同时上升,K8s 的复杂度才换得回收益。先跑通再优化,一开始就上 K8s 的项目,多数时间花在运维平台而不是业务上。

上线前的准备清单

检查项完成标准漏掉会怎样
域名与解析dig +short 域名 返回目标 IP用户根本找不到你
ICP 备案备案号已下发且接入商正确国内节点 80/443 被拦截,域名无法访问
TLS 证书浏览器无警告,curl -I https:// 返回 200被标记不安全,转化率直线下降
端口规划只开 22/80/443,应用端口仅监听 127.0.0.1数据库或调试端口被扫,数据泄露
运行时版本python -V/node -v/go version 与开发一致“本地能跑线上报错”的经典事故
配置与密钥走环境变量或密钥文件,权限 600,未提交 Git密钥泄露,被刷账单或被盗数据
数据备份已做一次手工全量 dump 并验证可恢复迁移或升级失败时无路可退
健康检查提供一个不需要鉴权的 /healthz无法自动判断新版本是否真的起来了
日志与轮转日志落盘并配置轮转,不写进容器 stdout 无限增长磁盘写满导致整机不可用
回滚方案保留上一个可用的镜像 tag 或代码目录出问题时只能现场改代码,越改越乱

关键概念逐条解释

  • 弹性公网 IP:与实例解绑后还能绑定到另一台机器,换机器时不用改 DNS,是比“直接绑公网 IP”更值钱的选择。
  • 云安全组 vs 主机防火墙:安全组在实例外面,由云平台执行,实例没起来也生效;主机防火墙在系统里面,规则随系统走。两层都留,别只做一层。
  • 反向代理:Nginx 代表后端接收请求再转发,后端只监听 127.0.0.1,公网永远连不到应用端口。
  • 健康检查:返回 200 且带上依赖状态(数据库能否连通)的接口,是滚动更新时判断“新版本能不能接流量”的唯一依据。
  • TTL:解析记录的缓存时间。切 IP 前先把 TTL 调到 60 秒,等旧 TTL 过期再切,用户才不会分散打到两台机器上。

验证方法

# 1) 解析是否正确
dig +short example.com

# 2) 端口是否按预期监听(0.0.0.0 表示对外,127.0.0.1 表示仅本机)
sudo ss -lntp

# 3) HTTP 与 HTTPS 是否通,响应头是否符合预期
curl -I http://example.com
curl -I https://example.com

# 4) 应用进程与容器状态
systemctl status myapp --no-pager
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'

# 5) 本机自测上游,确认不是 Nginx 的问题
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8000/healthz

五条命令全绿,说明“域名 → 网络 → 代理 → 应用”这条链路是通的;哪一条红,问题就锁定在哪一层。

常见坑

现象正确做法
只放行安全组,忘了主机防火墙本机 curl 通,外部超时两层规则同时放行,或明确只用一层
应用监听 0.0.0.0:3306数据库被外网扫描爆破监听 127.0.0.1,公网只留 80/443
没备案就配 443国内节点域名访问被重置先备案,或临时用海外节点与 IP 访问
容器日志无轮转磁盘 100% 后系统拒绝写入配置 log-opts max-size 与应用日志轮转
直接在服务器上改代码无法回滚,改动去向不明只部署产物,代码走 Git 与构建流程
没留健康检查接口新版本起来但连不上库,流量已经切过去健康检查里真连一次数据库或缓存

小结:上线是一条从 DNS 到数据的完整链路,先把组件、端口、检查项在纸上列清再动手;单机用 systemd 或 Compose,规模不大就别上 Kubernetes;每一层都要有可验证的命令和可回退的方案,跑通之后再去谈性能与高可用。

笔记加载中…