AI 时代,怎么发布自己的 Web 应用?
AI 已经能在很短的时间里写出一个能跑的 Web 应用。需求说清楚,页面、接口、数据库迁移和测试都可以交给 Coding Agent 逐步完成。到了发布这一步,事情却突然变得很传统。域名指向哪里,进程怎样常驻,证书谁来续期,日志去哪里看,服务挂了怎样恢复,这些问题一个都不会因为代码由 AI 写完而消失。
发布方式很多,常用的可以归成三种。第一种方式是买一台云服务器,自己管理运行环境。第二种方式是使用 Vercel、云函数或 Cloudflare Workers 这类 Serverless 服务。第三种方式适合准备建设内部平台的团队,把构建、镜像、域名和扩缩容统一封装,让开发者交付代码以后直接拿到一个可访问地址。
这三种方式没有固定的高低顺序。选择主要取决于应用需要多大的运行自由、团队愿意承担多少运维工作,以及同一套发布流程会不会被很多项目重复使用。
动手以前先看应用需要什么
先不要急着选云产品。把应用的运行条件写下来,答案通常已经很接近了。
- 只有静态页面,还是带服务端渲染和 API
- 是否需要常驻进程、定时任务或长连接
- 数据放在托管数据库,还是必须使用本机磁盘
- 是否依赖系统软件、GPU、特定网络或自定义运行时
- 流量平稳,还是长期空闲、偶尔突然升高
- 发布由一个人偶尔操作,还是几十个项目每天都在重复
静态站和常见前端框架通常很适合托管平台。需要完整操作系统、特殊依赖或多个常驻服务时,直接使用云服务器通常更省事。项目多到每个团队都在重复配置 CI、镜像、域名和监控时,自建平台才开始有意义。
第一种方式是买一台云服务器
阿里云 ECS、腾讯云 CVM 和其他云厂商的虚拟机都属于这种方式。买到实例以后,会得到一台带 CPU、内存、磁盘、网络和操作系统的远程计算机。应用可以直接装在系统里,也可以放进 Docker 容器。
这种方式最大的好处是运行边界宽。Node.js、Java、Python、数据库、消息队列和自定义二进制都能装,监听端口、文件目录和进程模型也由自己决定。需要固定公网 IP、私有网络、特殊系统包或稳定的常驻进程时,云服务器很直接。
选择云服务器以后,下面这些工作都要自己处理。
- 创建实例,选择地域、系统、CPU、内存和磁盘
- 用 SSH 密钥登录,关闭不需要的公网入口
- 配置安全组,只开放必要的端口
- 安装运行时或 Docker,启动应用进程
- 配置域名、反向代理和 HTTPS
- 接入日志、监控、告警和备份
- 安排系统补丁、应用升级和故障恢复
直接部署适合简单而稳定的环境
直接部署的做法很朴素。服务器安装 Node.js、JDK 或 Python,代码拉下来以后安装依赖,再用
systemd 之类的进程管理方式让应用常驻。机器上只有一个应用,运行时版本长期稳定,团队也熟悉 Linux 时,这套办法完全能用。问题出在项目增加以后。不同应用需要不同版本的运行时和系统包,部署脚本会逐渐依赖机器当前状态。某次手工修改没有写进文档,下一次迁移就很难复现。
Docker 把运行环境跟着应用一起交付
Docker 会把应用、依赖、运行时和启动方式打进容器镜像。开发机、CI 和云服务器运行同一个镜像,环境差异会少很多。一次常见的发布通常只需要运行下面几条命令。
AI 时代,怎么发布自己的 Web 应用? (bash)
docker compose up -d --build
docker compose ps
curl -I https://example.comDocker 解决的是应用如何被打包和运行。域名、证书、宿主机补丁、磁盘备份、容器重启、日志轮转和监控仍然需要有人负责。把进程放进容器以后,云服务器也不会自动变成托管平台。
数据库要格外谨慎。个人项目可以把数据库也放进 Compose,前提是已经设置持久卷和备份。只要数据重要,优先考虑云数据库或另一套经过验证的持久化方案。应用容器随时可以重建,数据库不能随便删掉重来。
云服务器适合想掌握完整环境、应用依赖比较特殊,或者希望用一台机器承载多个小服务的人。代价也很清楚,以后机器的维护和故障处理都要自己负责。
第二种方式是使用 Serverless
Serverless 把服务器、扩缩容和一部分发布流程交给平台。开发者通常连接 Git 仓库或上传代码,平台负责构建并给出访问地址。流量上来时增加实例,空闲时减少实例,有些产品可以缩到零。
这种方式内部也有不同形态,不能把所有产品当成同一种运行环境。
Vercel 适合以 Web 框架为中心的项目
Vercel 可以连接 GitHub、GitLab 和 Bitbucket。分支推送会产生 Preview Deployment,生产分支的更新会产生 Production Deployment。对 Next.js 和常见前端框架来说,构建规则、CDN、函数运行环境、预览地址和回滚都已经连在一起。
它很适合快速发布网站、管理后台、内容站和带轻量服务端逻辑的全栈应用。需要留意的地方是函数运行时间、内存、包大小、区域和并发模型。应用还要把状态放进数据库、对象存储或其他外部服务,不能依赖某个函数实例会一直活着。
云厂商的函数产品适合接入已有云资源
阿里云函数计算、腾讯云云函数等产品会托管计算资源,并通过 HTTP 请求或事件触发代码。应用已经在使用同一厂商的对象存储、消息队列、数据库和权限体系时,这类产品更容易接进现有环境。
函数产品常常同时支持代码包、Web 函数或容器镜像,具体能力以产品和地域为准。部署以前要核对触发方式、运行时、并发、超时、网络、日志和计费规则。云函数省掉了机器维护,却会要求代码遵守平台的执行模型。
Cloudflare Workers 运行在边缘节点
Cloudflare Workers 在全球网络上运行,主要执行模型基于 V8 Isolates。请求进入某个节点以后调用 Worker 的
fetch 处理函数。它启动快,适合边缘 API、鉴权、请求改写和靠近用户执行的 Web 逻辑。Workers 和普通 Node.js 服务器有差别。可用 API、状态模型、CPU 时间和资源限制都要按 Workers 文档检查。Cloudflare 也明确建议不要把可变状态寄托在全局作用域,因为两次请求没有保证落到同一个实例。
Serverless 最适合运行模型与平台契合的应用。代码一旦需要特殊系统包、长期占用本机资源、复杂网络拓扑或平台没有支持的运行时,后续迁移会很麻烦。选它以前,应当先查限制页,再看首页上的部署按钮。
三种方式对比
维度 | 云服务器 | 托管 Serverless | 自建发布平台 |
|---|---|---|---|
开发者交付物 | 代码或容器镜像 | Git 仓库、代码包或函数 | Git 仓库和少量应用配置 |
运行自由度 | 高 | 受平台运行时与配额约束 | 由平台团队定义支持范围 |
日常运维 | 自己负责 | 云平台负责大部分工作 | 平台团队集中负责 |
上线速度 | 配好以后较快 | 通常最快 | 平台建成以后很快 |
空闲成本 | 实例通常持续计费 | 常见按调用或使用量计费 | 取决于集群和缩零策略 |
适合的起点 | 特殊运行环境和常驻服务 | 个人项目与常见 Web 框架 | 多团队重复交付同类服务 |
如果目标只是尽快把一个产品放到网上,优先试托管 Serverless。遇到明确的运行限制,再转向云服务器或容器平台。为了一个应用先搭 Kubernetes、CI 系统、镜像仓库和可观测性,通常会让发布工作比应用本身还大。
如果要做基建,可以怎样设计?
团队拥有很多服务以后,问题会发生变化。开发者都在重复写 Dockerfile、CI 配置和部署脚本,平台团队又要反复检查镜像、域名、证书、资源限制和日志接入。此时可以把这些共同步骤封装成一套 Source-to-Service 平台。
理想情况下,开发者只需要输入一条命令。
AI 时代,怎么发布自己的 Web 应用? (bash)
platform deploy --repo https://github.com/example/my-app --branch main命令返回构建状态,成功后给出一个 URL。开发者提交源码和少量配置,不需要理解 Kubernetes 对象,也不必为常见语言手写 Dockerfile。
要实现这件事,可以把 Cloud Native Buildpacks、Tekton 和 Knative Serving 组合起来。
整个过程如下。
AI 时代,怎么发布自己的 Web 应用? (text)
Git 仓库
-> Tekton 拉取源码并执行构建任务
-> Cloud Native Buildpacks 检测语言和依赖
-> 生成并推送 OCI 镜像
-> 控制面创建或更新 Knative Service
-> Knative 生成 Revision、Route 和访问地址
-> 状态、日志和 URL 返回给开发者Buildpacks 负责把源码变成镜像
Cloud Native Buildpacks 会先检测源码,再选择参与构建的 Buildpack。Node.js 项目可以通过
package.json 和锁文件识别,Java、Python、Go 等语言也有各自的检测规则。随后 Buildpack 安装运行时与依赖、执行编译、设置启动进程,最后产出可运行的 OCI 镜像。Dockerfile 因此可以从常见项目里拿掉。平台团队统一维护 Builder 和 Buildpack 版本,应用团队只关心源码、依赖声明和少量构建参数。Paketo Buildpacks 已经提供多种语言的生产级实现,可以作为起点。
免写 Dockerfile 仍然需要一份清楚的应用契约。Web 服务要监听平台注入的端口,启动命令要能被识别,运行状态要放到外部存储,未被 Builder 支持的系统依赖也要有声明方式。检测失败时,平台应当给出可读错误,并允许用户补充
Procfile、构建参数,或者改用项目自带的 Dockerfile。Tekton 负责组织构建和交付步骤
Knative Serving 接收的是容器镜像,它不会从 Git 仓库构建源码。Buildpacks 能产出镜像,却不会替应用创建域名和流量规则。中间需要一个构建编排层。
Tekton 把拉取代码、运行测试、执行 Buildpacks、推送镜像和部署服务组织成 Task 与 Pipeline。每次发布对应一个 TaskRun 或 PipelineRun,平台控制面可以观察它的状态,把当前阶段和失败原因返回给 CLI 或 Web 页面。
初期没有必要立刻做完整 CI/CD。MVP 只要跑通源码、镜像和 URL 三段即可。等这个流程稳定以后,再加入测试、安全扫描、SBOM、PR Preview 和审批。
Knative 负责运行服务和管理版本流量
镜像进入仓库以后,平台控制面创建或更新 Knative Service。Service 模板里的镜像或配置发生变化时,Knative 会生成不可变的 Revision,Route 把访问地址映射到一个或多个 Revision。Knative Serving 可以根据请求自动扩缩容,在启用相关配置时把空闲服务缩到零,也能用流量比例完成灰度和蓝绿发布。
这让平台能够提供几项开发者直接感知的能力。每次发布有独立版本,失败后可以把流量切回旧 Revision,低流量应用可以减少空闲副本,测试版本也可以通过命名路由获得单独地址。
平台还要处理这些容易被忽略的工作
能够从代码生成一个可访问的 URL,只能说明基本发布流程已经跑通。准备长期使用,还要处理下面这些事情。
- Git 授权与私有仓库凭据
- 镜像仓库、镜像签名和清理策略
- 域名、DNS 与证书自动签发
- Secret、环境变量和数据库连接
- 构建日志、运行日志、指标与告警
- CPU、内存、并发构建和租户配额
- 构建缓存、Builder 预热和超时控制
- Revision 保留、回滚和故障排查入口
开发者不再处理这些细节,平台团队会统一负责。对常见应用来说,发布步骤应该尽量简单。构建失败时,平台也要说明原因,并允许开发者补充配置或改用 Dockerfile。持续运行的有状态组件则应当使用更合适的服务。
简单的构想
自建平台最容易犯的错,是一开始就支持所有语言、所有部署模型和所有云。更稳妥的 MVP 可以只支持两类无状态 HTTP 应用,例如 Node.js 和 Java,并规定统一的端口、健康检查和配置注入方式。
- 参数 Git 仓库、分支和应用名
- 触发 Tekton 构建任务
- 用 Paketo Buildpacks 生成并推送镜像
- 创建 Knative Service 并等待 Ready
- 返回构建日志、错误原因和访问 URL
- 用一个真实项目端到端验证重新发布与回滚
这个流程稳定以后,再增加 Preview 环境、自动测试、镜像扫描、自定义域名、多租户隔离和成本统计。对平台来说,重复发布是否省事,比功能多少更重要。
AI 让代码产出速度提高以后,发布系统会更频繁地被使用。个人项目通常应该先借用成熟平台,把时间留给产品。团队持续重复同一套交付动作时,再把经验做成内部平台。那时 Knative 和 Buildpacks 很合适,但用户看到的产品应该是一条清楚的发布命令、可追踪的状态,以及最终可以打开的 URL。
后续可以考虑扩展为 FaaS、BaaS 等,当然一般也不需要搞这些~