Vultr 速通 — API + Snapshot + 按小时起 VM
不是 Vultr 介绍,是 对 agquant.com / ex/elixir 项目真正有用 的 8 个能力。
这课不讲”什么是 VM”——你已经知道。讲的是 Vultr 表面下真正改变游戏规则的 8 个能力:
- API 起 VM — 30 行代码从 0 起一个 production 节点
- 按小时计费 — halt 不计费,destroy 不计费
- Snapshot + cloud-init — cold start 15-30s 的关键
- Object Storage — S3 兼容,$5/TB/月
- Firewall Group — default-deny + CF IP 白名单
- Startup Scripts — 模板化 cloud-init
- Block Storage — 100GB + $10/月挂载
- Marketplace Apps — 1-click deploy OpenLiteSpeed / GitLab 等
**预计时间:**60 分钟。
一、为什么选 Vultr(不选 AWS / DigitalOcean / Hetzner)
| 维度 | Vultr | AWS EC2 | DigitalOcean | Hetzner |
|---|---|---|---|---|
| 按小时计费 | ✅ 原生 | ✅ | ❌ 月费 | ✅ 部分 |
| $5/月起 | ✅ 1GB | ✅ t3.nano | ✅ 1GB | €4.35 CX22 |
| Snapshot 价 | $0.05/GB/月 | $0.05/GB/月 | $1/GB/月 ❌ | €0.01/GB/月 |
| API 质量 | v2 设计干净 | 300+ 服务,复杂 | 简单 | 简单 |
| CF 兼容 | ✅ | ✅ | ✅ | ✅ |
| 中国节点 | ❌ | 宁夏 (CN) | ❌ | ❌ |
| Document quality | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
- 按小时计费 + Snapshot 廉价 = 按需起 VM 经济模型可行(详见 lesson 0006)
- API 干净 = 30 行代码自动化
- Snapshot 价 $0.05/GB = 4GB VM 快照 $0.20/月(DO 同样 4GB = $4/月,20x 贵)
详见 [concepts-vultr-glossary.md §Vultr vs 其他云](../concepts-vultr-glossary)。
二、API 起 VM(30 行代码)
2.1 API 鉴权
CF Dashboard → Account → API → 创建 Personal Access Token。
export VULTR_API_KEY="VTLxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 列出现有 VM
curl -H "Authorization: Bearer $VULTR_API_KEY" https://api.vultr.com/v2/instances
2.2 Elixir wrapper(你 ex/elixir 项目可加)
defmodule Vultr do
@base "https://api.vultr.com/v2"
defp req(method, path, body \\ nil) do
headers = [
{"authorization", "Bearer #{System.fetch_env!("VULTR_API_KEY")}"},
{"content-type", "application/json"}
]
body_json = if body, do: Jason.encode!(body), else: ""
case HTTPoison.request(method, "#{@base}#{path}", body_json, headers, recv_timeout: 30_000) do
{:ok, %{status: code, body: resp}} when code in 200..299 ->
if resp == "", do: {:ok, nil}, else: {:ok, Jason.decode!(resp)}
{:ok, %{status: code, body: resp}} ->
{:error, {code, Jason.decode!(resp)}}
{:error, reason} -> {:error, reason}
end
end
def list_instances, do: req(:get, "/instances")
def get_instance(id), do: req(:get, "/instances/#{id}")
def create_instance(attrs) do
req(:post, "/instances", Map.merge(%{
region: "sgp",
plan: "vc2-2c-4gb",
label: "pipeline-#{:os.system_time(:second)}"
}, attrs))
end
def delete_instance(id), do: req(:delete, "/instances/#{id}")
def halt_instance(id), do: req(:post, "/instances/#{id}/halt")
def start_instance(id), do: req(:post, "/instances/#{id}/start")
end
2.3 完整 spin-up 流程
defmodule VultrAutoscaler do
def spin_up_worker do
case Vultr.create_instance(%{
os_id: 1743, # from snapshot
snapshot_id: System.fetch_env!("VULTR_SNAPSHOT_ID"),
hostname: "worker-#{:os.system_time(:second)}",
user_data: cloud_init_script()
}) do
{:ok, %{"instance" => %{"id" => id, "main_ip" => ip, "status" => status}}} ->
Mix.shell().info("✓ VM #{id} created at #{ip}, status=#{status}")
# 等 ~30s VM 起来,cloud-init 跑完
wait_until_ready(id, timeout: 90_000)
{:ok, %{id: id, ip: ip}}
{:error, reason} ->
Mix.raise("✗ Failed: #{inspect(reason)}")
end
end
defp wait_until_ready(id, timeout) do
deadline = System.monotonic_time(:millisecond) + timeout
poll_until(deadline, fn ->
case Vultr.get_instance(id) do
{:ok, %{"instance" => %{"status" => "running", "server_status" => "ok"}}} ->
:ready
_ -> nil
end
end)
end
defp poll_until(deadline, fun) do
if System.monotonic_time(:millisecond) > deadline do
:timeout
else
case fun.() do
:ready -> :ready
_ ->
Process.sleep(2_000)
poll_until(deadline, fun)
end
end
end
end
三、Snapshot + cloud-init(按需起 VM 的关键技术)
3.1 Snapshot 是什么
Snapshot = 整个 VM 磁盘状态(OS + 你的代码 + 依赖 + 配置)。从 snapshot 起新 VM 只需 15-30s(vs 从 ISO 装 OS 要 2-3 分钟)。
3.2 怎么用
# 1. 创建基础 VM(手动或 API)
vultr-cli instance create --region sgp --plan vc2-2c-4gb --os-id 1743 --label "base"
# 2. SSH 进去装好所有依赖
ssh root@<base-vm-ip> << 'EOF'
apt update
apt install -y curl git libpq-dev
mix local.hex --force
mix local.rebar --force
# ... 你的所有安装
EOF
# 3. 拍 snapshot
vultr-cli snapshot create --instance-id <base-vm-id> --description "pipeline-prod-v0.1.0"
# 4. 从 snapshot 起新 VM
vultr-cli instance create --region sgp --plan vc2-2c-4gb --os-id 1743 \
--snapshot-id <snapshot-id> --label "worker-01"
3.3 cloud-init 注入(user_data)
#cloud-config
write_files:
- path: /opt/pipeline.env
permissions: '0600'
content: |
DATABASE_URL=postgres://user:pass@db.example.com/pipeline_prod
LLM_URL=https://api.openai.com/v1
LLM_KEY=sk-xxx
SECRET_KEY_BASE=$(openssl rand -hex 64)
LIBCLUSTER_SEEDS=sgp-pipeline-01
runcmd:
- curl -L https://github.com/your/repo/releases/download/v0.1.0/pipeline.tgz -o /tmp/pipeline.tgz
- tar xzf /tmp/pipeline.tgz -C /opt
- useradd -r -s /bin/false pipeline
- chown -R pipeline:pipeline /opt/pipeline
- systemctl enable /opt/pipeline/_build/prod/rel/pipeline/bin/pipeline
- systemctl start pipeline
- curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared -o /usr/local/bin/cloudflared
- chmod +x /usr/local/bin/cloudflared
- cloudflared service install --token=$CLOUDFLARE_TUNNEL_TOKEN
- systemctl enable cloudflared
- systemctl start cloudflared
final_message: "Pipeline worker $HOSTNAME ready"
3.4 cold start 时间线
| 阶段 | 耗时 |
|---|---|
| Vultr API 接收 + 排队 | 5-10s |
| 启动 snapshot VM | 10-20s |
| cloud-init 拉 release + 起服务 | 15-30s |
| 总计 | 30-60s |
vs Spring Boot 2-3 分钟,4x 快——这是 Elixir + Vultr “按需起 VM” 能 work 的技术基础。
四、按小时计费(核心经济模型)
Vultr 的核心差异化——halt 不计费、destroy 不计费、只按实际开机时间按小时计。
defmodule VultrBilling do
def current_month_cost do
{:ok, %{"billing" => %{"balance" => balance}}} = req(:get, "/billing")
balance
end
def vm_hourly_cost(plan_id) do
{:ok, %{"plans" => plans}} = req(:get, "/plans")
case Enum.find(plans, &(&1["id"] == plan_id)) do
nil -> 0
plan -> plan["monthly_cost"] / 730
end
end
end
# 例:vc2-2c-4gb = $20/月 = 730 小时 = $0.027/h
# 每月跑 50 小时 = $1.37(vs 24/7 跑 = $20)
五、Object Storage(S3 兼容,$5/TB)
存 release 产物、用户上传的 xlsx/PDF、课程视频——S3 兼容但便宜 4x:
| 服务 | 存储 | Egress | API |
|---|---|---|---|
| AWS S3 | $0.023/GB | $0.09/GB | S3 |
| GCP Cloud Storage | $0.020/GB | $0.12/GB | S3 |
| Vultr Object Storage | $0.020/GB | $0.01/GB | S3 |
| Cloudflare R2 | $0.015/GB | $0 | S3 |
结论:Vultr Object Storage 适合 Vultr VM 内网访问(免费 egress),跨云访问用 R2。
# 创建 bucket
aws s3 --endpoint-url https://sgp1.vultrobjects.com mb s3://pipeline-releases
# 上传 release 产物
aws s3 --endpoint-url https://sgp1.vultrobjects.com \
cp pipeline.tgz s3://pipeline-releases/pipeline-v0.1.0.tgz
# 读(在 Vultr VM 内网,免费)
aws s3 --endpoint-url https://sgp1.vultrobjects.com \
cp s3://pipeline-releases/pipeline-v0.1.0.tgz /tmp/
# 公开读(给 CDN 用)
https://sgp1.vultrobjects.com/pipeline-releases/pipeline-v0.1.0.tgz
六、Firewall Group(CF IP 白名单)
关键:Vultr Firewall 是 default-deny——新 VM 所有端口都封。必须显式开端口。
# 1. 创建 group
curl -X POST -H "Authorization: Bearer $VULTR_API_KEY" \
-d '{"description":"agquant CF whitelist"}' \
https://api.vultr.com/v2/firewall-groups
# 2. 加 CF IP 段(必须限制来源 IP,不能 0.0.0.0/0)
# CF IP 列表:https://www.cloudflare.com/ips/
# Cloudflare IPv4
curl -X POST -H "Authorization: Bearer $VULTR_API_KEY" \
-d '{"ip_type":"v4","protocol":"tcp","port":"8002","subnet":"173.245.48.0","subnet_size":20}' \
https://api.vultr.com/v2/firewall-groups/<group-id>/rules
# Cloudflare IPv6
curl -X POST ... -d '{"ip_type":"v6","protocol":"tcp","port":"8002","subnet":"2400:cb00::","subnet_size":32}' ...
# 3. SSH 限制(仅你的 IP)
curl -X POST ... -d '{"ip_type":"v4","protocol":"tcp","port":"22","subnet":"YOUR.IP","subnet_size":32}' ...
# 4. attach 到 VM
curl -X POST -H "Authorization: Bearer $VULTR_API_KEY" \
-d '{"firewall_group_id":"<group-id>","instance_id":"<vm-id>"}' \
https://api.vultr.com/v2/firewall-groups/<group-id>/attachments
0.0.0.0/0:8002!Vultr VM 会被全世界扫描、挖矿、感染。正确做法:只开 CF IP 段(200+ 城市节点),VM 在公网上 8002 端口只能从 CF 进。
七、Startup Scripts(模板化 cloud-init)
把”起 VM 流程”保存为模板,所有 VM 复用:
# 1. 创建 template
curl -X POST -H "Authorization: Bearer $VULTR_API_KEY" \
-d '{"name":"agquant-pipeline","type":"boot","script":"#cloud-config\nwrite_files:\n - path: /opt/pipeline.env\n content: |\n DATABASE_URL=postgres://..."}' \
https://api.vultr.com/v2/startup-scripts
# 2. 创建 VM 时引用
curl -X POST ... -d '{
"region":"sgp",
"plan":"vc2-2c-4gb",
"os_id":1743,
"snapshot_id":"...",
"script_id":"<template-id>"
}' https://api.vultr.com/v2/instances
模板可以分版本(v0.1.0, v0.1.1, v0.2.0)——CI 流水线自动更新。
八、Block Storage(额外磁盘)
当 OS 盘不够(一般 25-100GB),挂块存储:
| 规格 | 月费 |
|---|---|
| 100 GB | $10 |
| 250 GB | $25 |
| 500 GB | $50 |
| 1 TB | $100 |
# 创建 + attach
curl -X POST -d '{"region":"sgp","size_gb":100,"label":"data"}' https://api.vultr.com/v2/block-storage
# 在 VM 内 mount
mkfs.ext4 /dev/vdb
mount /dev/vdb /mnt/data
echo "/dev/vdb /mnt/data ext4 defaults 0 0" >> /etc/fstab
agquant.com 场景:ETS 大表(GB 级)或 mnesia 数据放这里。
九、Marketplace Apps(1-click 部署)
不想自己装?直接装预制应用:
| App | 用途 |
|---|---|
| OpenLiteSpeed | 高性能 HTTP 服务器(比 nginx 快 3x) |
| Docker | 容器 runtime |
| GitLab CE | 自托管 Git |
| Mastodon | 自托管社交 |
| LEMP / LAMP | WordPress 之类 |
| Nextcloud | 自托管网盘 |
CLI:vultr-cli instance create --image-id <marketplace-image-id> ...
十、其他 6 个高级功能
| 功能 | 用途 | 价格 |
|---|---|---|
| Load Balancer | L4/L7 LB(支持 SSL 终止) | $10/月 |
| Reserved IP | 弹性公网 IP(可 detach/attach) | 免费(只付 VM 费) |
| Bare Metal | 独享硬件(不是虚拟化) | $120/月起 |
| High Frequency (vhf-) | 3.8GHz+ CPU(适合编译) | $128/月起 |
| VKE (Kubernetes) | 托管 K8s(比 EKS 便宜 50%) | $0(按节点付) |
| Direct Connect | 到其他云的内网专线 | $0.05/GB |
十一、agquant.com 实战:先做这 3 件事
- 10 分钟:开 Personal Access Token → 验证 API(
curl /v2/instances) - 30 分钟:做一个 base VM → 装好所有依赖 → 拍 snapshot
- 30 分钟:写 cloud-init → 验证从 snapshot 起 VM 能在 60s 内 ready
这三步做完,你就有”按需起 VM”的物质基础了。剩下的就是代码:autoscaler + CF Tunnel + load balancer。
十二、测验(12 道)
Vultr 区别于 AWS EC2 / DigitalOcean 的最大优势是?
halt 和 destroy 的区别?
Vultr Firewall 默认是?
Snapshot 价(每 GB 每月)?
从 Snapshot 起一个新 VM 需多久?
cloud-init 配置在哪里传给 Vultr?
Vultr Object Storage 跟 AWS S3 的 API 兼容?
Vultr Firewall Group 必须配置的是?
Vultr Reserved IP 用途?
vc2-2c-4gb 套餐月费?
Vultr 月费上限机制?
1GB 套餐 vc2-1c-1gb 月费 + 时费?
**下一步:**看 Lesson 0009 · SEO 速通。