6.10 云网络基础——VPC、安全组与 cloud-init
预计阅读时间:13 分钟
📖 目录
学习目标
读完本章后,你将能够:
- 理解 VPC、子网、CIDR 的概念及规划原则
- 区分安全组与网络 ACL 的适用场景
- 配置 SNAT / DNAT 让私有子网访问互联网
- 编写 cloud-init 用户数据实现服务器初始化自动化
- 通过元数据服务获取实例运行时信息
- 用阿里云 CLI / Terraform 完成基础网络资源编排
核心知识
| 概念 | 一句话定义 | 云厂商对应 |
|---|---|---|
| VPC | 云上隔离的私有网络环境 | aliyun vpc / AWS VPC |
| 子网(vSwitch) | VPC 内的 IP 段划分,关联可用区 | aliyun vswitch / AWS subnet |
| 安全组 | 实例级有状态防火墙(白名单) | aliyun SecurityGroup / AWS SG |
| 网络 ACL | 子网级无状态防火墙(规则有顺序) | aliyun NetworkAcl / AWS NACL |
| NAT 网关 | 让私有子网通过共享公网 IP 上网 | aliyun NAT Gateway / AWS NAT GW |
| EIP | 可独立持有的弹性公网 IP 地址 | aliyun EIP / AWS Elastic IP |
| cloud-init | 实例首次启动的自动化配置引擎 | 跨平台标准(所有云都支持) |
| 元数据服务 | 实例通过内网 HTTP 端点查询自身属性 | aliyun 100.100.100.200 / AWS 169.254.169.254 |
知识关联
- 前置知识:4.5:网络故障排查 网络故障排查(IP/路由/DNS 概念)、4.15:Terraform 入门 Terraform 入门(IaC 编排云资源)
- 后续影响:6.2:Kubernetes 入门 Kubernetes 入门(K8s 网络依赖 VPC/SecurityGroup 基础)、6.9:OpenTelemetry 与可观测性 OpenTelemetry(云原生环境下的可观测性)
- 配套技术:VPC + 安全组 + NAT 网关是云网络三件套,cloud-init 实现跨云初始化标准化,Terraform 管理云资源生命周期
原理讲解
VPC 隔离模型
物理服务器时代,网络拓扑是固定的——交换机配 VLAN、物理网线连接、机房走线。上云之后,网络变为虚拟化的:物理交换机 → 虚拟交换机(vSwitch),物理路由器 → 虚拟路由器(VRouter),物理防火墙 → 安全组 + ACL。VPC 就是云平台在共享物理网络上划出的逻辑隔离空间,每个 VPC 独占一个 CIDR 网段,互不可达(除非通过对等连接或云企业网打通)。
CIDR 与子网设计
VPC 创建的第一个决策是CIDR 网段——一旦创建无法修改。每个子网必须关联一个可用区,同一 VPC 内的子网通过默认路由互通。每个子网的第一个、第二个和最后一个 IP 被云平台保留(网络地址、网关、广播地址),加上默认路由实际可用 IP = 总数 − 5。
安全组 vs 网络 ACL
| 维度 | 安全组(Security Group) | 网络 ACL |
|---|---|---|
| 作用范围 | 实例级别(ENI) | 子网级别 |
| 状态 | 有状态(出方向响应自动放行) | 无状态(出入规则各自独立) |
| 规则 | 白名单,仅允许规则 | 白名单 + 黑名单,规则按编号顺序匹配 |
| 默认行为 | 入方向拒绝,出方向放行 | 出入均拒绝 |
生产环境通常组合使用:安全组做实例层精细控制,网络 ACL 做子网层粗粒度容灾(例如批量封禁恶意 IP)。
NAT 网关与 EIP
EIP(弹性公网 IP)是可以独立持有、随时绑定/解绑到云资源的公网 IP。NAT 网关则进一步实现了共享上网:私有子网的多个实例共用 NAT 网关的 EIP 访问互联网。SNAT 将内网源地址转换为公网 IP,DNAT 则将公网端口的入向流量转发到指定内网实例。
cloud-init 执行阶段
cloud-init 按顺序执行以下阶段:
- init-local:最早启动,解析数据源(如阿里云元数据服务)
- init:网络就绪后运行,应用 cloud-config 指令
- modules-config:配置模块如
write_files、users - modules-final:执行
runcmd、package_update等后期动作
元数据服务
云平台在每个实例内部提供一个内网可达的 HTTP 端点,用于查询实例元数据:实例 ID、区域、VPC ID、安全组、公网 IP、主机名等。这是 cloud-init 的底层数据源,也能被任意脚本直接调用。
多可用区与高可用设计
可用区(Availability Zone)是机房级别的故障隔离单元:不同可用区有独立的电力、网络和制冷。单可用区架构遇到机房故障(断电、光纤被挖断)时整体不可用,多可用区架构则能继续服务。生产设计的核心原则:
- 跨可用区部署:同一层(Web/App)至少部署在两个可用区,前端负载均衡器自动转发健康流量
- 数据库主备跨可用区:主库在可用区 A,备库在可用区 B,故障自动切换(阿里云 PolarDB/RDS 自动完成,传统自建 MySQL 用半同步复制)
- 子网与可用区绑定:每个可用区放一个子网,实例按可用区分散——所以规划子网时不要只按"层"划,还要按"可用区 × 层"划
# 多可用区子网规划示例(以 2 个可用区为例)
VPC: 10.0.0.0/16
├── 可用区 A(az-a)
│ ├── 10.0.1.0/24 web-a ← 3 台 Web
│ ├── 10.0.2.0/24 app-a ← 3 台 App
│ └── 10.0.3.0/24 db-a ← 主库/主 Redis
└── 可用区 B(az-b)
├── 10.0.11.0/24 web-b ← 3 台 Web
├── 10.0.12.0/24 app-b ← 3 台 App
└── 10.0.13.0/24 db-b ← 备库/备 Redis
# 故障演练:az-a 整体宕机时
# 负载均衡(SLB)自动把流量全部切到 az-b 的实例
# 数据库自动切换到 db-b 的备库(RTO 秒级-分钟级)
VPC 互通——对等连接、云企业网与 VPN
VPC 之间默认隔离。业务发展到多个 VPC(不同环境、不同区域、不同账号)时,需要按需打通:
| 方案 | 适用场景 | 特点 |
|---|---|---|
| VPC 对等连接(Peering) | 同区域、少量 VPC 互通 | 简单免费(流量费另计);CIDR 不能重叠;不能传递(A-B 互通不等于 A-C 互通) |
| 云企业网(CEN) | 多区域、多 VPC、复杂拓扑 | 星型/网状互联,自动路由分发,支持跨账号 |
| VPN 网关 / 专线 | 本地 IDC 与云上 VPC 互通 | VPN 走公网加密(低成本慢速);专线走物理链路(高可靠低延迟) |
# VPC 互通排查三板斧(ping 不通时按顺序查)
# ① 路由表:对端网段是否在路由表中(VPC 互通=互相加路由条目)
ip route show
# ② 安全组:对端来源是否放行(安全组是最后一道关卡)
# ③ 防火墙/ACL:云防火墙与网络 ACL 是否拦截
# 常见坑:两个 VPC 用了相同 CIDR(10.0.0.0/16 对 10.0.0.0/16),路由无法区分 → 无解,只能重建 VPC
示例代码
CIDR 规划与计算
# 大 VPC + 多子网(推荐)
VPC CIDR: 10.0.0.0/16 (65536 个 IP)
├── 子网 1: 10.0.1.0/24 (公网业务层) — 256 IP
├── 子网 2: 10.0.2.0/24 (应用层) — 256 IP
├── 子网 3: 10.0.10.0/24 (数据库层) — 256 IP
├── 子网 4: 10.0.20.0/24 (缓存层) — 256 IP
└── 保留子网: 10.0.128.0/17 (未来扩展) — 32768 IP
# 必须避免的冲突
# 总部 IDC: 10.0.0.0/8
# VPC 1: 10.0.0.0/16 ❌ 冲突!
# VPC 2: 172.16.0.0/16 ✅ 不冲突
# 使用 ipcalc 工具计算 CIDR
# apt install ipcalc
ipcalc 10.0.0.0/16
# 输出: Address: 10.0.0.0
# Netmask: 255.255.0.0 = 16
# Network: 10.0.0.0/16
# HostMin: 10.0.0.1
# HostMax: 10.255.255.254
# Broadcast: 10.255.255.255
# Hosts/Net: 65534
安全组规则(阿里云 CLI)
# 创建安全组
aliyun ecs CreateSecurityGroup --security-group-name sg_web
# 允许 HTTP/HTTPS
aliyun ecs AuthorizeSecurityGroup \
--SecurityGroupId sg-xxx \
--IpProtocol tcp \
--PortRange 80/80 \
--SourceCidrIp 0.0.0.0/0
# 允许特定安全组访问(sg_app 访问 sg_db 的 3306)
aliyun ecs AuthorizeSecurityGroup \
--SecurityGroupId sg-db \
--IpProtocol tcp \
--PortRange 3306/3306 \
--SourceGroupId sg-app
NAT 网关(Terraform)
resource "alicloud_nat_gateway" "default" {
vpc_id = alicloud_vpc.main.id
nat_type = "Enhanced"
payment_type = "PayAsYouGo"
}
resource "alicloud_snat_entry" "default" {
snat_table_id = alicloud_nat_gateway.default.snat_table_ids
source_vswitch_id = alicloud_vswitch.private.id
snat_ip = alicloud_eip.nat.ip_address
}
cloud-init 完整用户数据
#cloud-config
hostname: webserver-01
manage_etc_hosts: true
timezone: Asia/Shanghai
package_update: true
package_upgrade: true
packages:
- nginx
- certbot
- htop
- fail2ban
write_files:
- path: /etc/nginx/sites-available/myapp
content: |
server {
listen 80;
root /var/www/html;
server_name _;
}
permissions: '0644'
runcmd:
- [systemctl, enable, nginx]
- [systemctl, start, nginx]
- [ufw, allow, 22/tcp]
- [ufw, allow, 80/tcp]
- [ufw, allow, 443/tcp]
- [ufw, --force, enable]
- [ln, -sf, /etc/nginx/sites-available/myapp, /etc/nginx/sites-enabled/]
users:
- name: deploy
groups: sudo
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAAC3... user@example.com
sudo: ['ALL=(ALL) NOPASSWD:ALL']
验证 cloud-init 执行状态
cloud-init status
# status: done ← 全部执行成功
# status: error ← 部分失败
less /var/log/cloud-init-output.log
# 调试时重新执行
cloud-init clean --logs
cloud-init init
调用元数据服务
# 获取实例 ID
curl -s http://100.100.100.200/latest/meta-data/instance-id
# 获取 VPC ID
curl -s http://100.100.100.200/latest/meta-data/vpc-id
# 获取公网 IP
curl -s http://100.100.100.200/latest/meta-data/public-ipv4
Terraform 完整网络模块(VPC + 子网 + 安全组)
# network.tf —— 一个可复用的基础网络模块
# 阿里云 VPC:逻辑隔离的私有网络,CIDR 一旦创建不可修改
resource "alicloud_vpc" "main" {
vpc_name = "prod-vpc"
cidr_block = "10.0.0.0/16" # 65536 个 IP,足够中大型集群使用
}
# 多可用区 × 多层子网(用 for_each 避免重复代码)
# 子网绑定可用区 = 故障隔离到机房级别
locals {
subnets = {
"web-a" = { zone = "cn-hangzhou-a", cidr = "10.0.1.0/24" } # Web 层 A 区
"web-b" = { zone = "cn-hangzhou-b", cidr = "10.0.11.0/24" } # Web 层 B 区
"app-a" = { zone = "cn-hangzhou-a", cidr = "10.0.2.0/24" } # 应用层 A 区
"app-b" = { zone = "cn-hangzhou-b", cidr = "10.0.12.0/24" } # 应用层 B 区
"db-a" = { zone = "cn-hangzhou-a", cidr = "10.0.3.0/24" } # 数据库层 A 区(主库)
"db-b" = { zone = "cn-hangzhou-b", cidr = "10.0.13.0/24" } # 数据库层 B 区(备库)
}
}
# 批量创建子网(for_each 避免每个子网写一遍 resource)
resource "alicloud_vswitch" "this" {
for_each = local.subnets
vpc_id = alicloud_vpc.main.id
cidr_block = each.value.cidr
zone_id = each.value.zone
vswitch_name = each.key
}
# 应用层安全组:只允许来自 Web 安全组的 8080 访问
# 安全组间引用(而非 IP 段)= 网络随资源动态变化而规则不变
resource "alicloud_security_group" "app" {
name = "sg-app"
vpc_id = alicloud_vpc.main.id
}
# 入站规则:源安全组 sg-web → 目标端口 8080
resource "alicloud_security_group_rule" "app_from_web" {
type = "ingress"
ip_protocol = "tcp"
port_range = "8080/8080"
security_group_id = alicloud_security_group.app.id
# 引用其他安全组需先定义对应资源(本例仅演示 app 组内互访)
source_security_group_id = alicloud_security_group.app.id
}
# 用 Terraform 变量实现环境复用(dev/prod 用不同 CIDR)
# variable "env_cidr" { default = "10.0.0.0/16" }
terraform destroy,不会留下孤儿资源。常见错误
| 错误 | 后果 | 解决 |
|---|---|---|
| VPC CIDR 选得过小 | IP 耗尽无法扩容 | 至少分配 /16,预留 /17 扩展段 |
| CIDR 与 IDC 冲突 | 无法内网互通 | 规划前确认本地及对端网段 |
| 安全组出方向全拒绝 | apt update / yum 超时 | 安全组有状态,出方向至少放行响应 |
| NAT 网关未配 SNAT | 私有子网无法联网 | 添加 SNAT 条目指向 NAT 的 EIP |
| cloud-init 格式错误 | 初始化静默跳过 | cloud-init status --long 查看失败阶段 |
| 误用 #! 代替 #cloud-config | cloud-init 不识别 YAML | 用户数据首行必须是 #cloud-config |
| 元数据服务当公网用 | 请求走公网路由超时 | 元数据仅内网可达,走默认路由即可 |
最佳实践
- CIDR 规划:为每个环境(dev/staging/prod)分配独立大段(/16),各环境内按层划分子网(/24)并预留至少一段连续大段(/17)供未来扩展
- 安全组分层:按 Web / App / DB 三层设计安全组,层间通过安全组 ID 而非 IP 段授权;SSH 只放行堡垒机 IP
- NAT 高可用:生产环境为 NAT 网关附加至少 2 个 EIP 做 SNAT 条目,避免单 IP 被限速或被封
- cloud-init 幂等:runcmd 内使用
[ -f /flag ] || (command && touch /flag)模式,保证重复初始化不产生副作用 - 用户数据分离:将 cloud-init 模板纳入版本控制,配合 Terraform 的
user_data参数一起管理 - 元数据走内网:所有通过元数据获取到的信息(如实例 ID)通过日志输出,便于故障时关联工单
- 避免安全组规则膨胀:定期审计安全组,清理未关联实例的冗余安全组和已废弃的规则
练习题
- 规划一个 3 层 Web 应用的 VPC 网络(Web / App / DB),每个层一个子网,CIDR 从 10.0.0.0/16 中分配,并留出 /17 的扩展段
- 写一条安全组规则:只允许来自
sg_bastion的 SSH 访问(端口 22) - 用 cloud-init 在实例首次启动时安装 Docker 并启动一个 nginx 容器
- NAT 网关配好了但私有子网仍然无法
apt update,列出至少 3 种排查方向 - 通过元数据服务获取当前实例的
vpc-id和zone-id,写入/etc/metadata文件 - 写一条 DNAT 规则将公网 IP 的 8080 端口映射到内网 10.0.1.100 的 80 端口
点击查看答案
- 示例规划:Web=10.0.1.0/24, App=10.0.2.0/24, DB=10.0.3.0/24。预留 10.0.128.0/17 为扩展段。
aws ec2 authorize-security-group-ingress --group-id sg-web --protocol tcp --port 22 --source-group sg-bastion(CLI)或云控制台指定源安全组。- user-data:
#cloud-config\npackage_update: true\npackages: [docker.io]\nruncmd: [docker run -d -p 80:80 nginx]。 - 排查方向:① NAT 网关是否绑定 EIP/弹性公网;② 私有子网路由表是否指向 NAT;③ NAT 网关所在公共子网的安全组/ACL 是否放行出站;④ 目标是否在 NAT 支持列表中。
curl -s http://100.100.100.200/latest/meta-data/vpc-id > /etc/metadata && curl -s http://100.100.100.200/latest/meta-data/zone-id >> /etc/metadata(阿里云链路)。DNAT --to-destination 10.0.1.100:80。云平台配置 DNAT 转发规则映射公网 IP:8080→内网 IP:80。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释 VPC、子网、路由表、NAT 网关的概念 | 尝试向他人讲解 |
| 命令操作 | 能不查文档完成 VPC 网络规划和安全组配置 | 在终端实际执行 |
| 原理掌握 | 能说出云网络的流量转发和防火墙过滤原理 | 画出流程图 |
| 故障排查 | 能独立排查 VPC 内实例无法互相通信的问题 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么需要划分公网子网和私网子网 | 对比不同方案 |
本章总结
速查表
| 概念 | 一句话 |
|---|---|
| VPC | 云上的私有网络,隔离于其他用户 |
| 子网 | VPC 内的 IP 段划分,关联可用区 |
| 安全组 | 有状态白名单防火墙,支持安全组级引用 |
| NAT 网关 | 允许私有子网访问互联网(出站) |
| cloud-init | 实例首次启动的自动化配置脚本 |
| 元数据服务 | 实例查询自身信息的 API(链路本地地址) |
云网络的核心思维转变在于:网络不再是物理设备,而是通过 API 创建的虚拟构件。掌握 VPC CIDR 规划、安全组规则设计、NAT 网关共享上网和 cloud-init 自动化配置,是高效使用云资源的基础能力。
上云网络清单:
- VPC CIDR:选一个不与本地和其他云环境冲突的大段(如 /16)
- 子网划分:按层(web/app/db)划分,预留扩展空间
- 安全组:最小权限,只放行必要端口,来源限制到指定安全组
- NAT 网关:私有子网通过 NAT 正常访问互联网
- cloud-init:把服务器初始化自动化,让新 ECS 开箱即用
延伸阅读
- 阿里云 VPC 文档:https://help.aliyun.com/product/27706.html
- cloud-init 官方文档:https://cloudinit.readthedocs.io/
- RFC 1918 — 私有地址空间分配标准
- Terraform alicloud 提供商文档:https://registry.terraform.io/providers/aliyun/alicloud/latest/docs
- 《阿里云上云最佳实践白皮书》中网络章节