Fly.io:边缘计算应用托管的全面解析
NOTE
本文档最后更新于 2026年4月,深入剖析 Fly.io 的边缘计算架构、多区域部署策略、持久化存储方案,以及与 Cloudflare Workers 的对比分析。
目录
- 概述与技术架构
- 核心概念解析
- Fly Volumes 持久存储
- Fly Machines 微虚拟机
- 多区域部署策略
- 价格模型详解
- 与 Cloudflare Workers 对比
- 实战部署指南
- 选型建议
概述与技术架构
什么是 Fly.io
Fly.io 是一个专注于边缘计算的应用托管平台,允许开发者将应用部署到全球多个数据中心,实现低延迟、高可用的服务。与传统云服务不同,Fly.io 的核心理念是将应用逻辑推送到离用户最近的位置,而非让用户连接到遥远的中心化服务器。
Fly.io 支持多种应用类型:
- Web 应用:Node.js、Python、Ruby、Go、Rust 等
- 容器化应用:Docker 镜像
- 静态站点:配合 Flyctl CDN
- 长连接应用:WebSocket、gRPC、游戏服务器
技术架构
Fly.io 的底层架构融合了两种核心技术:
| 组件 | 技术 | 作用 |
|---|---|---|
| 全球负载均衡 | Anycast | 就近路由、健康检查 |
| 网络隧道 | WireGuard | 安全通信、加密传输 |
| 计算资源 | Firecracker VMs | 轻量级虚拟机隔离 |
| 持久存储 | NVMe SSD | 高性能本地存储 |
Anycast 路由机制
用户请求 → 最近数据中心(通过 Anycast)
↓
Fly Proxy(边缘代理)
↓
┌───────────┴───────────┐
↓ ↓
Fly Machine Fly Machine
(香港) (新加坡)
↓ ↓
Fly Volume Fly Volume
(本地存储) (本地存储)
Anycast 确保用户请求自动路由到物理距离最近的数据中心,无需手动配置区域选择。
WireGuard 网络隧道
Fly.io 使用 WireGuard 构建全球私有网络:
# WireGuard 配置示例(自动生成)
[Interface]
PrivateKey = <auto-generated>
Address = 10.0.0.2/16
MTU = 1420
[Peer]
PublicKey = <fly-proxy-pubkey>
Endpoint = 34.120.50.1:51820
AllowedIPs = 10.0.0.0/16
PersistentKeepalive = 15所有 Fly 应用之间的通信都通过加密隧道进行,确保数据安全。
全球数据中心分布
| 区域 | 位置 | 覆盖范围 |
|---|---|---|
| 北美 | 纽约、旧金山、洛杉矶、达拉斯、西雅图 | 北美用户 |
| 欧洲 | 阿姆斯特丹、法兰克福、伦敦、巴黎 | 欧洲用户 |
| 亚太 | 香港、新加坡、东京、悉尼、首尔 | 亚太用户 |
| 南美 | 圣保罗 | 南美用户 |
IMPORTANT
Fly.io 持续扩展数据中心,具体可用区域请参考
flyctl platform regions输出。
核心概念解析
1. Fly Application
Fly 应用是部署和管理的核心单位:
# fly.toml - 应用配置
app = "my-app-name"
# 基础配置
kill_signal = "SIGINT"
kill_timeout = "5s"
# 扩展性配置
[deploy]
strategy = "rolling"
# 健康检查
[[services]]
internal_port = 3000
[[services.ports]]
port = 80
handlers = ["http"]
[[services.ports]]
port = 443
handlers = ["tls", "http"]
[[services.checks]]
path = "/health"
interval = "10s"
timeout = "2s"2. Fly Proxy
Fly Proxy 是边缘流量管理器,负责:
| 功能 | 说明 |
|---|---|
| 负载均衡 | 自动分发流量到多个实例 |
| SSL 终止 | 自动 HTTPS 证书管理 |
| 健康检查 | 自动移除不健康实例 |
| 流量加密 | 内部通信加密传输 |
| 速率限制 | 防止 DDoS 和滥用 |
3. Fly Machine
Fly Machine 是 Fly.io 的核心计算单元:
{
"id": "mach-abc123",
"name": "web-0",
"config": {
"image": "registry.fly.io/myapp:latest",
"env": {
"NODE_ENV": "production"
},
"services": {
"ports": [{"port": 3000}],
"checks": [{
"type": "http",
"path": "/health",
"interval": "10s"
}]
}
},
"region": "hkg",
"state": "started"
}4. 热迁移
Fly.io 支持机器的热迁移,可在不停机的情况下转移实例:
迁移前:香港 Machine(负载高)
↓ 执行热迁移
迁移后:新加坡 Machine(负载均衡)
热迁移优势:
- 零停机时间
- 保持会话连接
- 自动更新就近部署
Fly Volumes 持久存储
概述
Fly Volumes 是 Fly.io 提供的本地持久化存储解决方案,基于 NVMe SSD,为每个应用提供独立的存储卷。
NOTE
Fly Volumes 与传统云存储(如 AWS EBS)的核心区别在于:数据存储在本地,提供极低的读写延迟,但只能在同一区域内访问。
核心特性
| 特性 | 说明 |
|---|---|
| 持久性 | 数据在重启后保留 |
| 本地性能 | NVMe SSD,延迟 < 1ms |
| 独立卷 | 每个应用独享存储 |
| 区域限制 | 只能在创建区域内挂载 |
| 容量选择 | 1GB 到 256GB 可选 |
创建和使用 Volume
# 创建 Volume
fly volumes create my_data --region hkg --size 10
# 查看 Volume
fly volumes list
# 输出示例
ID Name Region SizeGB UsedGB Encryption
vol_abc123 my_data hkg 10 2.3 aes-256Volume 配置
# fly.toml 中配置 Volume
[mounts]
source = "my_data"
destination = "/data"应用示例:数据库存储
# PostgreSQL 使用 Fly Volume
import os
DATABASE_URL = os.getenv("DATABASE_URL",
"postgresql://user:pass@localhost:5432/mydb")
# Fly.io 自动注入的 Volume 路径
DATA_DIR = "/data/postgres"
# 应用配置
FLASK_ENV = "production"
SQLALCHEMY_DATABASE_URI = DATABASE_URL
SQLALCHEMY_TRACK_MODIFICATIONS = FalseVolume 限制与注意事项
| 限制 | 说明 |
|---|---|
| 区域绑定 | Volume 不能跨区域移动 |
| 单写原则 | 同时只有一个 Machine 可写 |
| 容量固定 | 创建后不能动态扩容(需创建新 Volume) |
| 备份依赖 | 需自行实现数据备份 |
IMPORTANT
Fly Volumes 不支持多实例共享写入。如果需要多实例共享存储,考虑使用 Tigris(Fly.io 对象存储)或外部数据库服务。
备份策略
# 方案 1:备份到 Tigris(Fly.io 对象存储)
flyctl storage create
# 方案 2:定时备份脚本
#!/bin/bash
# backup.sh
DATE=$(date +%Y%m%d_%H%M%S)
pg_dump -Fc mydb > /tmp/backup_$DATE.dump
curl -X PUT -T /tmp/backup_$DATE.dump \
https://storage.googleapis.com/my-bucket/Fly Machines 微虚拟机
什么是 Fly Machines
Fly Machines 是基于 Firecracker 微虚拟机的计算单元,每个 Machine 是一个轻量级独立虚拟机,提供比容器更强的隔离性,同时保持毫秒级启动速度。
Firecracker 技术
Firecracker 是 AWS 开源的微虚拟机技术,特性:
| 特性 | 说明 |
|---|---|
| 启动时间 | < 125ms(冷启动) |
| 内存开销 | ~5MB 基础内存 |
| 安全隔离 | 硬件虚拟化(KVM) |
| 资源效率 | 可在裸机上运行数百个实例 |
Machine 配置
# machine.yaml
version: "2"
kind: machine
services:
- protocol: tcp
internal_port: 8080
machine:
image: "registry.fly.io/myapp:v1"
# 计算资源
resources:
cpu: 2 # vCPU 数量
memory: 512mb # 内存大小
# 自动扩缩容
auto_destroy: false
size: "performance"
# 健康检查
checks:
- type: http
path: /health
interval: 10s
timeout: 2s
# 环境变量
env:
NODE_ENV: production
PORT: "8080"Machine 生命周期
创建 → 启动 → 运行 → 健康检查 → 自动恢复
↓
扩展/缩减
↓
停止/销毁
Fly Apps V2 架构
Fly.io 的新版架构允许更细粒度的 Machine 管理:
# 使用 Fly Python SDK 管理 Machines
from fly.api import Fly
client = Fly()
# 创建 Machine
machine = client.machines.create(
name="api-server-1",
config={
"image": "registry.fly.io/myapp:latest",
"cpus": 2,
"memory_mb": 512,
"region": "hkg",
"env": {"PORT": "8080"}
}
)
# 列出所有 Machines
machines = client.machines.list()
for m in machines:
print(f"{m.name}: {m.state}")
# 停止 Machine
client.machines.stop(machine.id)
# 删除 Machine
client.machines.destroy(machine.id)多区域部署策略
自动就近路由
Fly.io 的 Anycast 网络自动将用户路由到最近数据中心:
用户(上海)→ Fly Proxy → 香港数据中心(延迟 ~30ms)
用户(北京)→ Fly Proxy → 香港数据中心(延迟 ~50ms)
用户(纽约)→ Fly Proxy → 纽约数据中心(延迟 ~10ms)
手动区域配置
# 指定部署区域
[deploy]
release_command = "npm run migrate"
strategy = "rolling"
# 区域配置
[env]
PRIMARY_REGION = "hkg"
[regions]
default = "hkg"
zones = ["hkg", "sin", "nrt", "syd"]跨区域数据库同步
# 多区域数据库配置
import os
class DatabaseConfig:
# Fly.io 自动注入的区域信息
FLY_REGION = os.getenv("FLY_REGION", "unknown")
# 根据区域选择数据库
DB_URLS = {
"hkg": "postgresql://hkg.db.internal:5432/mydb",
"sin": "postgresql://sin.db.internal:5432/mydb",
"nrt": "postgresql://nrt.db.internal:5432/mydb",
}
@classmethod
def get_url(cls):
return cls.DB_URLS.get(cls.FLY_REGION, cls.DB_URLS["hkg"])
@classmethod
def is_primary(cls):
return cls.FLY_REGION == os.getenv("PRIMARY_REGION", "hkg")全球复制策略
┌─────────────────────────────────────────────────┐
│ Fly.io 全球复制 │
├─────────────────────────────────────────────────┤
│ │
│ Primary (香港) ←→ Replica (新加坡) │
│ ↓ ↓ │
│ 写入/更新 只读查询 │
│ ↓ ↓ │
│ 实时同步 延迟复制 │
│ │
└─────────────────────────────────────────────────┘
价格模型详解
按量付费 vs 月付计划
| 计费方式 | 说明 | 适用场景 |
|---|---|---|
| 按量付费 | 按实际使用计费 | 开发测试、低流量应用 |
| 月付计划 | 固定月费 + 配额 | 生产应用、可预估流量 |
按量付费明细
| 资源 | 单价 | 说明 |
|---|---|---|
| vCPU | $3.194/vCPU/天 | 基础 VM 小型 |
| 内存 | $0.348/GB/天 | |
| 卷存储 | $0.15/GB/月 | |
| 出站流量 | $0.12/GB | 前 10TB |
| 入站流量 | 免费 | |
| Anycast IP | $2/月 |
月付计划
| 计划 | 价格 | 包含资源 |
|---|---|---|
| Hobby | 免费 | 1x 共享 CPU, 256MB RAM, 1GB 存储 |
| Standard | $5/月 | 1x vCPU, 512MB RAM, 3GB 存储 |
| Pro | $20/月 | 2x vCPU, 1GB RAM, 10GB 存储 |
| Pro Plus | $50/月 | 4x vCPU, 2GB RAM, 50GB 存储 |
成本计算示例
应用配置:
- 2 个 vCPU
- 1GB 内存
- 20GB 存储
- 100GB 月流量
计算:
CPU: 2 × $3.194/天 × 30天 = $191.64
内存: 1GB × $0.348/天 × 30天 = $10.44
存储: 20GB × $0.15/月 = $3.00
流量: 100GB × $0.12 = $12.00
─────────────────────────────────
总计: $217.08/月
TIP
对于低流量应用,使用月付计划更经济。例如 Standard 计划 $5/月相当于 2.5 个 vCPU 小时,远低于按量付费。
免费配额
| 资源 | 免费额度 |
|---|---|
| 共享 CPU | 3 台机器/月 |
| 带宽 | 160GB 出站/月 |
| Volume | 3GB/月 |
| 构建时间 | 无限制 |
与 Cloudflare Workers 对比
核心定位差异
| 维度 | Fly.io | Cloudflare Workers |
|---|---|---|
| 计算模型 | 持久进程(VM) | Serverless 函数 |
| 冷启动 | ~200ms | < 5ms |
| 执行时长 | 无限制 | 50ms - 30s(付费可达 60min) |
| WebSocket | ✅ 原生支持 | ⚠️ Durable Objects |
| 持久存储 | ✅ Volumes | ⚠️ D1/KV/R2 |
| 地理位置 | 边缘数据中心 | 300+ PoPs |
| 定价模型 | 按资源计费 | 按请求计费 |
功能对比表
| 功能 | Fly.io | Cloudflare Workers |
|---|---|---|
| Node.js | ✅ 完整支持 | ✅ 完整支持 |
| Python | ✅ | ✅ |
| Go | ✅ | ✅(WASM) |
| Rust | ✅ | ✅(WASM) |
| Docker | ✅ | ❌(Workers only) |
| WebSocket | ✅ | ⚠️ DO required |
| gRPC | ✅ | ❌ |
| 长连接 | ✅ | ❌ |
| 持久计算 | ✅ | ❌(Durable Objects) |
| 边缘数据库 | ❌ | ✅ D1 |
| 边缘 KV | ❌ | ✅ Workers KV |
| 对象存储 | ✅ Tigris | ✅ R2 |
性能对比
| 测试场景 | Fly.io | Cloudflare Workers |
|---|---|---|
| API 响应时间(亚太) | ~80ms | ~20ms |
| 冷启动时间 | 200-500ms | < 5ms |
| 吞吐量 | 高 | 极高 |
| 持久连接 | 优秀 | 一般 |
| 复杂计算 | 优秀 | 受限 |
选型建议
| 场景 | 推荐 | 理由 |
|---|---|---|
| API 后端 | Fly.io | 持久进程、无时长限制 |
| 静态 + 简单逻辑 | Workers | 超低延迟、全球覆盖 |
| WebSocket 应用 | Fly.io | 原生支持 |
| 实时游戏 | Fly.io | 无冷启动延迟 |
| CDN 边缘计算 | Workers | 全球 300+ PoPs |
| 数据库密集型 | Fly.io | Volumes 性能好 |
| 简单 SSR | 两者皆可 | 根据生态选择 |
实战部署指南
1. 初始化项目
# 安装 flyctl
curl -L https://fly.io/install.sh | sh
# 登录
flyctl auth login
# 初始化应用
cd my-project
flyctl launch2. 配置应用
# fly.toml
app = "my-app-name"
primary_region = "hkg"
[build]
builder = "heroku/buildpacks:20"
[env]
PORT = "8080"
NODE_ENV = "production"
[[services]]
internal_port = 8080
[services.concurrency]
hard_limit = 25
soft_limit = 20
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[[services.ports]]
handlers = ["http"]
port = 80
[[services.checks]]
path = "/health"
interval = "10s"
timeout = "2s"3. 部署命令
# 部署
flyctl deploy
# 查看状态
flyctl status
# 查看日志
flyctl logs
# SSH 进入机器
flyctl ssh console4. 自定义 Dockerfile 部署
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]# fly.toml 中指定 Dockerfile
[build]
dockerfile = "Dockerfile"5. 数据库部署
# 部署 PostgreSQL
flyctl postgres create --name my-db --region hkg
# 附加到应用
flyctl postgres attach --app my-app my-db
# 获取连接信息
flyctl postgres connect -a my-db6. 自动扩缩容
# 自动扩缩容配置
[autoscale]
min_machines = 1
max_machines = 10
[autoscale.memory]
min_mb = 256
max_mb = 1024
[autoscale.cpu]
threshold = 70 # CPU 使用率阈值选型建议
选择 Fly.io 的充分条件
- ✅ 需要持久进程或长连接
- ✅ 需要 WebSocket/gRPC 支持
- ✅ 应用需要 > 30s 执行时间
- ✅ 需要本地持久存储
- ✅ 需要完整的 Linux 环境
- ✅ 需要多区域部署
- ✅ 预算可控(按资源计费)
不选择 Fly.io 的场景
- ❌ 超简单边缘函数(选择 Cloudflare Workers)
- ❌ 严格预算控制(选择 Vercel/Netlify)
- ❌ 主要使用 AWS 生态(选择 AWS Lambda)
- ❌ 需要免费托管静态站点(选择 Vercel)
混合使用策略
Edge 层:Cloudflare Workers(静态资源、简单路由)
↓
Backend 层:Fly.io(API、WebSocket、持久计算)
↓
Database 层:PlanetScale/Turso(分布式数据库)
参考资料
| 资源 | 链接 |
|---|---|
| 官方文档 | https://fly.io/docs/ |
| Flyctl CLI | https://fly.io/docs/flyctl/ |
| 价格计算器 | https://fly.io/pricing |
| GitHub | https://github.com/superfly/flyctl |
| Fly.io Blog | https://fly.io/blog/ |
服务概述与定位
Fly.io 在现代边缘计算中的角色
Fly.io 是边缘计算领域的创新者,它将「让应用靠近用户」这一理念做到了极致。与传统云服务将数据中心作为中心不同,Fly.io 通过 Anycast 路由和 Firecracker 微虚拟机技术,将应用部署到全球多个边缘节点。
平台核心价值
┌─────────────────────────────────────────────────────────────────────┐
│ Fly.io 核心价值体系 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 就近计算 │ │
│ │ │ │
│ │ 用户(上海) ────────→ Fly Edge(香港) ───→ 延迟 ~30ms │ │
│ │ 用户(北京) ────────→ Fly Edge(香港) ───→ 延迟 ~50ms │ │
│ │ 用户(纽约) ────────→ Fly Edge(纽约) ───→ 延迟 ~10ms │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 容器级隔离 │ │
│ │ │ │
│ │ Firecracker VM → 毫秒启动 → 硬件虚拟化隔离 │ │
│ │ 与容器相比:更强隔离性 + 更低开销 │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ 持久存储 │ │
│ │ │ │
│ │ Fly Volumes → NVMe SSD → 区域绑定 → 高性能本地存储 │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
技术栈全景
# Fly.io 技术栈
flyio_stack = {
# 计算层
"compute": {
"machines": "Firecracker VMs",
"isolation": "硬件虚拟化 (KVM)",
"startup_time": "< 125ms",
"memory_overhead": "~5MB",
},
# 网络层
"network": {
"routing": "Anycast",
"tunnel": "WireGuard",
"tls": "自动 Let's Encrypt",
"load_balancing": "Fly Proxy",
},
# 存储层
"storage": {
"volumes": "NVMe SSD",
"object_storage": "Tigris",
"regions": "区域绑定",
},
# 支持的应用
"supported_apps": [
"Docker 容器",
"Node.js",
"Python (FastAPI/Flask/Django)",
"Go",
"Ruby",
"PHP",
"Rust",
"Elixir",
"Static Sites",
"gRPC",
"WebSocket",
],
}完整配置教程
安装 Flyctl CLI
# macOS
brew install flyctl
# Linux
curl -L https://fly.io/install.sh | sh
# Windows (PowerShell)
iwr https://fly.io/install.ps1 -useb | iex
# npm
npm install -g @flydotio/dockerfile
# 验证安装
flyctl version认证和初始化
# 登录
flyctl auth login
# 使用 GitHub 登录
flyctl auth login --browser github
# 查看当前登录状态
flyctl auth whoami
# 登出
flyctl auth logout
# 组织登录
flyctl auth login --org my-org创建应用
# 方法 1: 交互式创建
flyctl apps create
# 输入应用名称
# 选择组织
# 方法 2: 从 Dockerfile
flyctl launch --image nginx:latest
# 方法 3: 从现有配置
flyctl launch --no-generate
# 方法 4: 从 GitHub
flyctl launch --from https://github.com/username/repo
# 查看应用列表
flyctl apps list
# 查看应用详情
flyctl apps info myappfly.toml 完整配置
# fly.toml - Fly.io 应用配置
# ─────────────────────────────────────────────────────────
# 应用基础配置
# ─────────────────────────────────────────────────────────
app = "my-app-name"
primary_region = "hkg" # 主要区域
# Kill 信号和超时
kill_signal = "SIGINT"
kill_timeout = "5s"
# ─────────────────────────────────────────────────────────
# 构建配置
# ─────────────────────────────────────────────────────────
[build]
# 使用预构建镜像
image = "nginx:alpine"
# 或使用 Dockerfile
# dockerfile = "Dockerfile"
# 或使用 Buildpacks
# builder = "heroku/buildpacks:20"
# ─────────────────────────────────────────────────────────
# 环境变量
# ─────────────────────────────────────────────────────────
[env]
PORT = "8080"
NODE_ENV = "production"
LOG_LEVEL = "info"
# ─────────────────────────────────────────────────────────
# 挂载卷
# ─────────────────────────────────────────────────────────
[mounts]
source = "my_data"
destination = "/data"
# ─────────────────────────────────────────────────────────
# 服务配置(HTTP/HTTPS)
# ─────────────────────────────────────────────────────────
[[services]]
# 内部端口
internal_port = 8080
# 并发限制
[services.concurrency]
hard_limit = 25
soft_limit = 20
# HTTP 端口
[[services.ports]]
port = "80"
handlers = ["http"]
force_https = true
# HTTPS 端口
[[services.ports]]
port = "443"
handlers = ["tls", "http"]
# 健康检查
[[services.checks]]
name = "health"
path = "/health"
interval = "10s"
timeout = "2s"
retries = 3
grace_period = "10s"
method = "get"
protocol = "http"
# TCP 检查
[[services.checks]]
name = "tcp-check"
port = 5432
interval = "10s"
timeout = "5s"
# ─────────────────────────────────────────────────────────
# 区域配置
# ─────────────────────────────────────────────────────────
# 主要区域
[regions]
default = "hkg"
# 允许的区域
[regions.distant]
regions = ["sin", "nrt", "syd"]
# 区域HA(高可用)
[ha]
regions = ["hkg", "sin"]
# ─────────────────────────────────────────────────────────
# 部署策略
# ─────────────────────────────────────────────────────────
[deploy]
strategy = "rolling" # rolling, canary, immediate, blue
release_command = "npm run migrate"
max_unavailable = 0.25
max_surge = 1
# ─────────────────────────────────────────────────────────
# 自动扩缩容
# ─────────────────────────────────────────────────────────
[autoscale]
min_machines = 1
max_machines = 10
[autoscale.memory]
min_mb = 256
max_mb = 1024
target_mem_percent = 70
[autoscale.cpu]
threshold = 75
# ─────────────────────────────────────────────────────────
# HTTP/2 和 WebSocket
# ─────────────────────────────────────────────────────────
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ["app"]
# ─────────────────────────────────────────────────────────
# SSH 配置
# ─────────────────────────────────────────────────────────
[vm]
size = "shared-cpu-1x"
memory = "512mb"
cpu_kind = "shared"
cpus = 1
# ─────────────────────────────────────────────────────────
# 监控
# ─────────────────────────────────────────────────────────
[metrics]
port = 9090
path = "/metrics"
# ─────────────────────────────────────────────────────────
# Secrets
# ─────────────────────────────────────────────────────────
# 使用 flyctl secrets set 设置敏感数据
# flyctl secrets set DATABASE_URL=xxx
# flyctl secrets set API_KEY=xxx核心功能详解
Fly Machines 深度解析
Machine 配置选项
# machine.yaml - Machine 详细配置
version: "2"
kind: machine
# 服务配置
services:
- protocol: tcp
internal_port: 8080
concurrency:
type: "connection"
hard_limit: 25
soft_limit: 20
# Machine 配置
machine:
# 镜像
image: "registry.fly.io/myapp:v1"
# 自动销毁
auto_destroy: true
# 机器大小
size: "performance-2x"
# 区域
region: "hkg"
# 计算资源
resources:
cpu: 2
memory: 1024mb
# 自动停止(节省成本)
auto_stop: true
auto_start: true
# 休眠时间(分钟)
guest_preparation_time: 3
# 健康检查
checks:
- type: "http"
name: "http-check"
interval: "10s"
timeout: "2s"
retries: 3
path: "/health"
method: "GET"
# 环境变量
env:
NODE_ENV: "production"
PORT: "8080"
# 挂载
mounts:
- volume: "my_data"
path: "/data"
# 启动命令
cmd: ["node", "server.js"]
# 入口点
entrypoint: ["/bin/sh", "-c"]Machine 生命周期管理
# 使用 Fly API 管理 Machines
import requests
class FlyMachines:
def __init__(self, api_token):
self.api_token = api_token
self.base_url = "https://api.machines.dev"
self.headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json",
}
def create_machine(self, app_name, config):
"""创建新 Machine"""
url = f"{self.base_url}/v1/apps/{app_name}/machines"
response = requests.post(url, headers=self.headers, json=config)
return response.json()
def list_machines(self, app_name):
"""列出所有 Machines"""
url = f"{self.base_url}/v1/apps/{app_name}/machines"
response = requests.get(url, headers=self.headers)
return response.json()
def get_machine(self, machine_id):
"""获取 Machine 详情"""
url = f"{self.base_url}/v1/machines/{machine_id}"
response = requests.get(url, headers=self.headers)
return response.json()
def start_machine(self, machine_id):
"""启动 Machine"""
url = f"{self.base_url}/v1/machines/{machine_id}/start"
response = requests.post(url, headers=self.headers)
return response.json()
def stop_machine(self, machine_id):
"""停止 Machine"""
url = f"{self.base_url}/v1/machines/{machine_id}/stop"
response = requests.post(url, headers=self.headers)
return response.json()
def delete_machine(self, machine_id):
"""删除 Machine"""
url = f"{self.base_url}/v1/machines/{machine_id}"
response = requests.delete(url, headers=self.headers)
return response.json()
def wait_for_state(self, machine_id, target_state, timeout=60):
"""等待 Machine 进入目标状态"""
import time
start = time.time()
while time.time() - start < timeout:
machine = self.get_machine(machine_id)
if machine.get("state") == target_state:
return True
time.sleep(1)
return FalseFly Volumes 深度解析
卷的高级配置
# 创建带加密的卷
fly volumes create my_data \
--region hkg \
--size 10 \
--encrypted
# 查看卷详情
fly volumes show vol_abc123
# 列出卷
fly volumes list
# 删除卷
fly volumes destroy vol_abc123
# 调整卷大小(创建新卷)
fly volumes create my_data_new --region hkg --size 20
# 然后迁移数据数据库存储配置
# PostgreSQL 使用 Fly Volumes
import os
# 获取卷路径
DATA_DIR = os.getenv("FLY_VOLUMES_DIR", "/data")
POSTGRES_DATA_DIR = f"{DATA_DIR}/postgres"
# 环境变量
DATABASE_URL = os.getenv("DATABASE_URL",
f"postgresql://user:pass@localhost:5432/mydb")
# 启动脚本
STARTUP_SCRIPT = """
#!/bin/bash
mkdir -p {data_dir}
chown postgres:postgres {data_dir}
exec postgres \
-D {data_dir} \
-c config_file=/etc/postgresql/postgresql.conf
""".format(data_dir=POSTGRES_DATA_DIR)网络深度配置
自定义域名
# 添加域名
fly certs add example.com
fly certs add www.example.com
# 检查证书状态
fly certs show example.com
# 删除证书
fly certs remove example.com
# 查看 DNS 配置说明
fly certs add example.com --show-dns内网服务
# fly.toml - 内网服务配置
# 内网服务不需要公开端口
[[services]]
internal_port = 8080
# 只允许内网访问
[[services.ports]]
handlers = ["tls"]
port = 443
# 内网连接
[[services.tcp]]
host = "my-internal-service.fly.dev"
port = 8080
# 服务间连接
# 使用 .internal 域名
# myapp.internal.fly.dev
# 或机器 IP部署配置
多种部署方式
1. Dockerfile 部署
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8080
# Fly.io 会自动设置 PORT
CMD ["node", "server.js"]# fly.toml
[build]
dockerfile = "Dockerfile"
[[services]]
internal_port = 8080
[[services.ports]]
handlers = ["http", "tls"]
port = 4432. 多阶段构建
# Dockerfile
# ─────────────────────────────────────────────────────────
# Build stage
# ─────────────────────────────────────────────────────────
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ─────────────────────────────────────────────────────────
# Production stage
# ─────────────────────────────────────────────────────────
FROM node:20-alpine AS production
WORKDIR /app
# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
USER nodejs
EXPOSE 8080
CMD ["node", "dist/server.js"]3. 预构建镜像部署
# 直接使用预构建镜像
fly launch --image nginx:alpine
# 自定义镜像
fly launch --imageregistry.fly.io/myapp:v1
# Docker Hub 镜像
fly launch --image redis:7-alpine多区域部署
# fly.toml - 多区域配置
primary_region = "hkg"
# 默认区域
[regions]
default = "hkg"
# 全球分布
[regions.distant]
regions = ["sin", "nrt", "syd", "lax", "ewr", "ams"]
# 高可用配置
[ha]
regions = ["hkg", "sin"]# 应用级区域路由
from flask import Flask, request
app = Flask(__name__)
# Fly.io 自动设置 FLY_REGION
REGION = os.getenv("FLY_REGION", "unknown")
@app.route('/api/data')
def get_data():
# 根据区域选择数据源
if REGION == "hkg":
data = get_from_hk_database()
elif REGION == "sin":
data = get_from_sg_database()
else:
data = get_from_default_database()
return {
"region": REGION,
"data": data
}环境变量与密钥管理
Secrets 管理
# 设置 secrets
fly secrets set DATABASE_URL=postgresql://xxx
fly secrets set API_KEY=xxx
fly secrets set JWT_SECRET=xxx
# 批量设置
fly secrets set \
DATABASE_URL=xxx \
API_KEY=xxx \
STRIPE_KEY=xxx
# 从文件设置
fly secrets set --file .env.production
# 查看 secrets
fly secrets list
# 删除 secret
fly secrets unset API_KEY
# Secrets 命名规范
# 使用大写下划线命名
# DATABASE_URL
# API_SECRET_KEY
# JWT_PRIVATE_KEY多环境配置
# 创建 secrets 文件
# .secrets
DATABASE_URL=postgresql://user:pass@prod.db:5432/mydb
API_KEY=prod_api_key
JWT_SECRET=prod_jwt_secret
# 设置到生产环境
fly secrets set --app myapp-prod --file .secrets
# 查看环境
fly config env --app myapp-prodCI/CD 集成
GitHub Actions
# .github/workflows/fly-deploy.yml
name: Fly.io Deployment
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Flyctl
uses: superfly/flyctl-actions/setup-flyctl@master
with:
flyctl-auth-token: ${{ secrets.FLY_API_TOKEN }}
- name: Deploy to Fly.io
run: |
flyctl deploy \
--app ${{ secrets.FLY_APP_NAME }} \
--region hkg \
--strategy rolling
- name: Health Check
run: |
sleep 10
curl -f https://${{ secrets.FLY_APP_NAME }}.fly.dev/health || exit 1
- name: Show logs
if: failure()
run: flyctl logs --app ${{ secrets.FLY_APP_NAME }}GitLab CI
# .gitlab-ci.yml
stages:
- deploy
deploy:
stage: deploy
image: ubuntu:22.04
before_script:
- apt-get update && apt-get install -y curl
- curl -L https://fly.io/install.sh | sh
- export FLYCTL_INSTALL="/root/.fly"
- export PATH="$FLYCTL_INSTALL/bin:$PATH"
script:
- flyctl auth login --token $FLY_API_TOKEN
- flyctl deploy --app $FLY_APP_NAME --region hkg
only:
- main
environment:
name: production
url: https://$FLY_APP_NAME.fly.dev性能优化与缓存策略
机器大小选择
# fly.toml - 机器配置
[vm]
size = "performance-2x" # 2 vCPU, 4GB RAM
cpus = 2
memory = "4096mb"| 规格 | vCPU | 内存 | 适用场景 |
|---|---|---|---|
| shared-cpu-1x | 1 | 256MB | 开发/测试 |
| shared-cpu-2x | 2 | 512MB | 小型应用 |
| performance-1x | 1 | 2GB | 中型应用 |
| performance-2x | 2 | 4GB | 大型应用 |
| performance-4x | 4 | 8GB | 高性能需求 |
| performance-8x | 8 | 16GB | 旗舰配置 |
自动扩缩容
# fly.toml - 自动扩缩容配置
[autoscale]
min_machines = 1
max_machines = 10
[autoscale.memory]
min_mb = 256
max_mb = 2048
target_mem_percent = 70
[autoscale.cpu]
threshold = 80缓存策略
# Fly Volumes 上的 Redis 配置
# redis.conf
bind 0.0.0.0
port 6379
maxmemory 256mb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec
# Fly Volumes 路径
dir /data
dbfilename dump.rdb成本估算与选型建议
成本计算器
# Fly.io 成本计算
class FlyCostCalculator:
# 基础价格(按量付费)
pricing = {
"cpu_per_vcpu_day": 3.194,
"memory_per_gb_day": 0.348,
"volume_per_gb_month": 0.15,
"outbound_bandwidth_per_gb": 0.12,
"anycast_ip_month": 2.00,
}
# 月付计划
plans = {
"hobby": {
"price": 0,
"cpu": "shared-cpu",
"memory": 256,
"storage": 3,
"bandwidth": 160, # GB
},
"standard": {
"price": 5,
"cpu": "shared-cpu",
"memory": 512,
"storage": 10,
"bandwidth": "unlimited",
},
"pro": {
"price": 20,
"cpu": "performance",
"memory": 2048,
"storage": 50,
"bandwidth": "unlimited",
},
}
def calculate_usage_cost(
self,
cpu_vcpus: float,
memory_gb: float,
storage_gb: float,
bandwidth_gb: float,
days: int = 30
) -> dict:
"""计算按量付费成本"""
costs = {
"cpu": cpu_vcpus * self.pricing["cpu_per_vcpu_day"] * days,
"memory": memory_gb * self.pricing["memory_per_gb_day"] * days,
"storage": storage_gb * self.pricing["volume_per_gb_month"],
"bandwidth": max(0, bandwidth_gb - 160) * self.pricing["outbound_bandwidth_per_gb"],
}
costs["total"] = sum(costs.values())
return costs
def compare_plans(
self,
cpu_vcpus: float,
memory_gb: float,
storage_gb: float
) -> dict:
"""比较月付计划和按量付费"""
results = {}
# 计算按量付费
usage_cost = self.calculate_usage_cost(cpu_vcpus, memory_gb, storage_gb, 0)
results["usage"] = usage_cost["total"]
# 检查各计划
for name, plan in self.plans.items():
if memory_gb <= plan["memory"]:
results[name] = plan["price"]
return results选型建议矩阵
| 场景 | 推荐配置 | 理由 |
|---|---|---|
| 开发/测试 | Hobby 免费版 | 免费额度足够 |
| 小型应用 | Standard $5/月 | 固定价格,易于预算 |
| 中型应用 | 按量付费 | 灵活,成本可控 |
| 高流量应用 | Pro $20/月 | 性能保证 |
| 数据库密集型 | 性能机器 + Volumes | 高 IOPS |
常见问题与解决方案
部署问题
问题:部署失败
# 检查日志
fly logs
# 常见原因:
# 1. 端口配置错误
# 确保应用监听 PORT 环境变量
# fly.toml 中 internal_port 正确
# 2. 健康检查失败
# 确保 /health 端点返回 200
curl http://localhost:8080/health
# 3. 资源不足
# flyctl scale show
# flyctl scale memory 1024问题:构建超时
# 原因:构建时间过长
# 解决方案:
# 1. 优化 Dockerfile
# 使用更小的基础镜像
FROM alpine:3.19
# 2. 增加构建超时
flyctl deploy --no-cache
# 3. 使用预构建镜像
fly launch --image node:20-alpine运行时问题
问题:应用响应慢
# 检查资源使用
flyctl status
flyctl metrics
# 增加资源
flyctl scale memory 2048
flyctl scale cpu 2
# 检查区域延迟
flyctl doctor问题:频繁重启
# 检查重启原因
flyctl events --type crash
# 常见原因:
# 1. OOM
# 增加内存
flyctl scale memory 1024
# 2. 健康检查失败
# 检查应用健康端点
# 调整健康检查配置网络问题
问题:无法访问应用
# 检查服务状态
flyctl services list
# 检查证书
flyctl certs list
# 重启应用
flyctl restart
# 检查防火墙
flyctl wireguard list存储问题
问题:卷空间不足
# 查看卷使用
fly volumes list
# 创建新卷
fly volumes create new_data --region hkg --size 50
# 扩展现有卷(创建新卷然后迁移)
# 1. 创建新卷
fly volumes create expanded_data --region hkg --size 100
# 2. 在应用中添加新挂载
# fly.toml
[mounts]
source = "expanded_data"
destination = "/data"
# 3. 迁移数据
flyctl ssh console
# 在机器内执行: cp -r /old/data/* /new/data/数据库问题
问题:PostgreSQL 连接失败
# 检查数据库状态
flyctl postgres status
# 获取连接信息
flyctl postgres connect -a mydb
# 启动数据库
flyctl postgres start -a mydb
# 停止数据库
flyctl postgres stop -a mydb
# 重启数据库
flyctl postgres restart -a mydb
# 备份数据库
flyctl postgres import -a mydb < backup.dump问题:Redis 连接失败
# 检查 Redis 状态
flyctl redis status
# 获取连接信息
flyctl redis connect -a myredis
# 查看 Redis 日志
flyctl logs --app myredis高级功能
团队协作
团队管理
# 创建组织
flyctl orgs create my-org
# 列出组织
flyctl orgs list
# 切换组织
flyctl orgs switch my-org
# 添加成员
flyctl orgs add-member user@example.com my-org
# 移除成员
flyctl orgs remove-member user@example.com my-org
# 设置成员角色
flyctl orgs update-member user@example.com --role developer
# 角色: owner, member, viewer访问控制
# fly.toml - 项目访问控制
# 在 flyctl apps create 时设置
flyctl apps create myapp --org my-org
# 转移应用
flyctl apps transfer myapp --org new-org
# 查看应用权限
flyctl access-tokens listFly Apps V2 架构
Machine API 深度使用
# 使用 Fly API 创建和管理 Machines
import requests
import json
class FlyMachinesAPI:
def __init__(self, token, app_name):
self.token = token
self.app_name = app_name
self.base_url = f"https://api.machines.dev/v1/apps/{app_name}"
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
def create_machine(self, config):
"""创建 Machine"""
url = f"{self.base_url}/machines"
response = requests.post(url, headers=self.headers, json=config)
return response.json()
def list_machines(self):
"""列出所有 Machines"""
url = f"{self.base_url}/machines"
response = requests.get(url, headers=self.headers)
return response.json()
def get_machine(self, machine_id):
"""获取 Machine 详情"""
url = f"{self.base_url}/machines/{machine_id}"
response = requests.get(url, headers=self.headers)
return response.json()
def update_machine(self, machine_id, config):
"""更新 Machine"""
url = f"{self.base_url}/machines/{machine_id}"
response = requests.post(url, headers=self.headers, json=config)
return response.json()
def delete_machine(self, machine_id):
"""删除 Machine"""
url = f"{self.base_url}/machines/{machine_id}"
response = requests.delete(url, headers=self.headers)
return response.status_code == 204
def exec_in_machine(self, machine_id, cmd):
"""在 Machine 中执行命令"""
url = f"{self.base_url}/machines/{machine_id}/exec"
response = requests.post(
url,
headers=self.headers,
json={"cmd": cmd, "timeout": 30}
)
return response.json()
# 使用示例
api = FlyMachinesAPI(token="your-token", app_name="myapp")
# 创建 Machine
config = {
"region": "hkg",
"config": {
"image": "nginx:alpine",
"auto_destroy": True,
"restart": {
"policy": "on-failure",
"max_retries": 3
}
}
}
machine = api.create_machine(config)
print(f"Created machine: {machine['id']}")
# 列出 Machines
machines = api.list_machines()
for m in machines:
print(f"{m['id']}: {m['state']}")
# 执行命令
result = api.exec_in_machine(machine['id'], "nginx -v")
print(result)监控与日志
日志管理
# 查看日志
flyctl logs
# 过滤日志
flyctl logs --filter error
flyctl logs --filter "POST /api"
# 查看特定机器日志
flyctl logs --machine mach_abc123
# 导出日志
flyctl logs > app.log
# 实时日志
flyctl logs -f
# 日志级别
# 默认: info
# 调试模式
flyctl logs --verbose指标监控
# 查看基本指标
flyctl status
# 查看详细指标
flyctl metrics
# 导出指标
flyctl metrics --json > metrics.json
# 集成 Prometheus
# 添加 Prometheus 端点
# fly.toml
[metrics]
port = 9090
path = "/metrics"
# Prometheus 配置
# prometheus.yml
scrape_configs:
- job_name: 'fly-apps'
metrics_path: '/metrics'
static_configs:
- targets: ['myapp.fly.dev']备份与恢复
数据库备份
# PostgreSQL 备份
# 1. 连接到数据库
flyctl postgres connect -a mydb
# 2. 执行备份
pg_dump -Fc mydb > backup.dump
# 3. 上传到存储
flyctl storage create
# 使用 Tigris 存储
# 恢复备份
pg_restore -Fc -d mydb backup.dump
# 自动备份配置
# fly.toml
[backup]
enabled = true
schedule = "0 2 * * *" # 每天凌晨2点
retention = 7 # 保留7天参考资料
官方资源
| 资源 | 链接 |
|---|---|
| 官方文档 | https://fly.io/docs/ |
| CLI 文档 | https://fly.io/docs/flyctl/ |
| API 文档 | https://fly.io/docs/reference/api/ |
| 价格计算器 | https://fly.io/pricing |
| Fly.io Blog | https://fly.io/blog/ |
| GitHub | https://github.com/superfly/flyctl |
| Discord | https://discord.gg/flyio |
相关工具
| 工具 | 说明 |
|---|---|
| flyctl | 命令行工具 |
| Fly Dashboard | Web 控制台 |
| Fly Machines API | 编程式管理 |
| Tigris | 对象存储 |
| LiteFS | 分布式 SQLite |
| Fly Volumes | NVMe 存储 |
| WireGuard | 安全隧道 |
学习资源
| 资源 | 说明 |
|---|---|
| Fly.io Academy | 官方教程 |
| Fly.io Examples | 示例项目 |
| Community Tutorials | 社区教程 |
| YouTube Channel | 视频教程 |
| GitHub Discussions | 讨论区 |
SUCCESS
Fly.io 是 vibecoding 工作流中部署后端服务的优秀选择。其边缘计算架构、持久存储能力和 WebSocket 支持,使其成为需要低延迟、高可用应用的最佳平台。对于需要快速原型验证但又希望拥有生产级基础设施的开发者,Fly.io 提供了完美的平衡。