

# 开始通过 Amazon CLI 使用 Amazon VPC
<a name="getting-started-with-amazon-vpc-using-the-aws-cli"></a>

本教程将指导您使用 Amazon 命令行界面（Amazon CLI）创建虚拟私有云（VPC）。您将了解如何设置包含公有子网和私有子网的 VPC、配置互联网连接，并部署 EC2 实例以演示常见的 Web 应用程序架构。

## 先决条件
<a name="prerequisites"></a>

在开始本教程之前，请确保您具有以下各项：

1. Amazon CLI。如需安装，请遵循 [Amazon CLI 安装指南](https://docs.amazonaws.cn/cli/latest/userguide/getting-started-install.html)。

1. 已使用适当的凭证配置 Amazon CLI。如果尚未设置凭证，请运行 `aws configure`。

1. 有关网络概念的基础知识。

1. 用于在 Amazon 账户中创建和管理 VPC 资源的 [适用于 Amazon VPC 的 Identity and Access Management](security-iam.md)。

### 成本考虑因素
<a name="cost-considerations"></a>

本教程创建的 Amazon 资源可能会让您的账户产生费用。费用主要来自 NAT 网关（每小时 0.045 美元，外加数据处理费用）和 EC2 实例（t2.micro，每个实例每小时约 0.0116 美元）。如果您在一小时内完成本教程并清理所有资源，则总费用约为 0.07 美元。要在开发环境中优化成本，可以考虑使用 NAT 实例代替 NAT 网关，这样可以显著降低成本。

在继续操作之前，让我们确认 Amazon CLI 是否已正确配置。

```
aws configure list
```

您应该会看到 Amazon 访问密钥、私有密钥和默认区域。此外，请确认您是否具有创建 VPC 资源所需的权限。

```
aws sts get-caller-identity
```

此命令会显示 Amazon 账户 ID、用户 ID 和 ARN，确认您的凭证有效。

## 创建 VPC
<a name="create-a-vpc"></a>

虚拟私有云（VPC）是专用于您 Amazon 账户的虚拟网络。在本部分中，您将创建 CIDR 块为 10.0.0.0/16 的 VPC，该 CIDR 块最多可提供 65536 个 IP 地址。

**创建 VPC**

以下命令会创建新的 VPC，并为其分配名称标签。

```
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=MyVPC}]'
```

记下输出中的 VPC ID，以便在后续命令中使用。在本教程中，我们将使用“vpc-0123456789abcdef0”作为示例 VPC ID。在所有命令中，请将其替换为实际的 VPC ID。

**启用 DNS 支持和主机名**

默认情况下，新 VPC 中会禁用 DNS 解析和 DNS 主机名。启用这些功能让 VPC 中的实例可以解析域名。

```
aws ec2 modify-vpc-attribute --vpc-id vpc-0123456789abcdef0 --enable-dns-support
aws ec2 modify-vpc-attribute --vpc-id vpc-0123456789abcdef0 --enable-dns-hostnames
```

如果成功，这些命令不会产生输出。VPC 现已启用 DNS 支持和主机名解析。

## 创建子网
<a name="vpc-tutorial-cli-create-subnets"></a>

子网是 VPC 的 IP 地址范围分段，您可以在其中放置隔离的资源组。在本部分中，您将在两个可用区中创建公有子网和私有子网以实现高可用性。

**获取可用的可用区**

首先，检索所在区域中可用的可用区。

```
aws ec2 describe-availability-zones
```

在本教程中，我们将使用前两个可用区。记下它们在输出中的名称（例如“us-east-1a”和“us-east-1b”）。

**创建公有子网**

公有子网用于需要从互联网访问的资源，例如 Web 服务器。

```
aws ec2 create-subnet \
  --vpc-id vpc-0123456789abcdef0 \
  --cidr-block 10.0.0.0/24 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Public-Subnet-AZ1}]'
```

记下输出中的子网 ID。在本教程中，我们将以“subnet-0123456789abcdef0”作为第一个公有子网的示例。

```
aws ec2 create-subnet \
  --vpc-id vpc-0123456789abcdef0 \
  --cidr-block 10.0.1.0/24 \
  --availability-zone us-east-1b \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Public-Subnet-AZ2}]'
```

记下输出中的子网 ID。在本教程中，我们将以“subnet-0123456789abcdef1”作为第二个公有子网的示例。

**创建私有子网**

私有子网用于不应直接从互联网访问的资源，例如数据库。

```
aws ec2 create-subnet \
  --vpc-id vpc-0123456789abcdef0 \
  --cidr-block 10.0.2.0/24 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Private-Subnet-AZ1}]'
```

记下输出中的子网 ID。在本教程中，我们将以“subnet-0123456789abcdef2”作为第一个私有子网的示例。

```
aws ec2 create-subnet \
  --vpc-id vpc-0123456789abcdef0 \
  --cidr-block 10.0.3.0/24 \
  --availability-zone us-east-1b \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Private-Subnet-AZ2}]'
```

记下输出中的子网 ID。在本教程中，我们将以“subnet-0123456789abcdef3”作为第二个私有子网的示例。

您现在拥有四个子网：两个公有子网和两个私有子网，它们分布在两个可用区中。

**提示**：规划 CIDR 块时，请确保其不会与现有网络重叠。对于生产环境，请分配足够的 IP 地址以满足未来的增长需求，同时保持合理的子网大小以确保安全且便于管理。

## 配置互联网连接
<a name="configure-internet-connectivity"></a>

要允许 VPC 中的资源与互联网通信，您需要创建并附加互联网网关。在本部分中，您将为 VPC 设置互联网连接。

**创建 Internet 网关**

通过互联网网关，可以实现 VPC 和互联网之间的通信。

```
aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=MyIGW}]'
```

记下输出中的互联网网关 ID。在本教程中，我们将以“igw-0123456789abcdef0”作为示例。

**将互联网网关附加到 VPC**

创建互联网网关后，可将其附加到 VPC。

```
aws ec2 attach-internet-gateway --internet-gateway-id igw-0123456789abcdef0 --vpc-id vpc-0123456789abcdef0
```

**创建和配置路由表**

路由表包含决定了将网络流量定向到何处的规则（路由）。首先，为公有子网创建路由表。

```
aws ec2 create-route-table \
  --vpc-id vpc-0123456789abcdef0 \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=Public-RT}]'
```

记下输出中的路由表 ID。在本教程中，我们将以“rtb-0123456789abcdef0”作为公有路由表的示例。

在公有路由表中添加一条指向互联网网关的路由。

```
aws ec2 create-route --route-table-id rtb-0123456789abcdef0 --destination-cidr-block 0.0.0.0/0 --gateway-id igw-0123456789abcdef0
```

将公有子网与公有路由表关联。

```
aws ec2 associate-route-table --route-table-id rtb-0123456789abcdef0 --subnet-id subnet-0123456789abcdef0
aws ec2 associate-route-table --route-table-id rtb-0123456789abcdef0 --subnet-id subnet-0123456789abcdef1
```

现在，为私有子网创建路由表。

```
aws ec2 create-route-table \
  --vpc-id vpc-0123456789abcdef0 \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=Private-RT}]'
```

记下输出中的路由表 ID。在本教程中，我们将以“rtb-0123456789abcdef1”作为私有路由表的示例。

将私有子网与私有路由表关联。

```
aws ec2 associate-route-table --route-table-id rtb-0123456789abcdef1 --subnet-id subnet-0123456789abcdef2
aws ec2 associate-route-table --route-table-id rtb-0123456789abcdef1 --subnet-id subnet-0123456789abcdef3
```

## 创建 NAT 网关
<a name="create-a-nat-gateway"></a>

NAT 网关允许私有子网中的实例启动流向互联网的出站流量，同时阻止来自互联网的入站流量。对于需要下载更新或访问外部服务的实例而言，这至关重要。

**分配弹性 IP**

首先，为 NAT 网关分配弹性 IP 地址。

```
aws ec2 allocate-address --domain vpc
```

记下输出中的分配 ID。在本教程中，我们将以“eipalloc-0123456789abcdef0”作为示例。

**创建 NAT 网关**

使用分配的弹性 IP 在其中一个公有子网中创建 NAT 网关。

```
aws ec2 create-nat-gateway \
  --subnet-id subnet-0123456789abcdef0 \
  --allocation-id eipalloc-0123456789abcdef0 \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=MyNATGateway}]'
```

记下输出中的 NAT 网关 ID。在本教程中，我们将以“nat-0123456789abcdef0”作为示例。

等待 NAT 网关变为可用后，再继续操作。

```
aws ec2 wait nat-gateway-available --nat-gateway-ids nat-0123456789abcdef0
```

**向 NAT 网关添加路由**

在私有路由表中添加一条指向 NAT 网关的路由，以允许私有子网中的实例访问互联网。

```
aws ec2 create-route --route-table-id rtb-0123456789abcdef1 --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0123456789abcdef0
```

**注意**：对于生产环境，请考虑在每个拥有私有子网的可用区中创建一个 NAT 网关，以消除单点故障。

## 配置子网设置
<a name="configure-subnet-settings"></a>

配置公有子网，以便为在其中启动的实例自动分配公有 IP 地址。

```
aws ec2 modify-subnet-attribute --subnet-id subnet-0123456789abcdef0 --map-public-ip-on-launch
aws ec2 modify-subnet-attribute --subnet-id subnet-0123456789abcdef1 --map-public-ip-on-launch
```

这可确保在公有子网中启动的实例在默认情况下会收到公有 IP 地址，从而可从互联网访问这些实例。

## 创建安全组
<a name="create-security-groups"></a>

安全组充当实例的虚拟防火墙以控制入站和出站流量。在本部分中，您将为 Web 服务器和数据库服务器创建安全组。

**为 Web 服务器创建安全组**

```
aws ec2 create-security-group \
  --group-name WebServerSG \
  --description "Security group for web servers" \
  --vpc-id vpc-0123456789abcdef0
```

记下输出中的安全组 ID。在本教程中，我们将以“sg-0123456789abcdef0”作为 Web 服务器安全组的示例。

允许 HTTP 和 HTTPS 流量访问 Web 服务器。

```
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0 --protocol tcp --port 443 --cidr 0.0.0.0/0
```

**注意**：对于生产环境，请将入站流量限制为特定 IP 范围，而不是允许来自 0.0.0.0/0（任何 IP 地址）的流量。

**为数据库服务器创建安全组**

```
aws ec2 create-security-group \
  --group-name DBServerSG \
  --description "Security group for database servers" \
  --vpc-id vpc-0123456789abcdef0
```

记下输出中的安全组 ID。在本教程中，我们将以“sg-0123456789abcdef1”作为数据库服务器安全组的示例。

仅允许来自 Web 服务器的 MySQL/Aurora 流量。

```
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef1 --protocol tcp --port 3306 --source-group sg-0123456789abcdef0
```

此配置遵循最低权限原则，确保只有 Web 服务器安全组中的实例才能通过端口 3306 连接到数据库服务器。

## 验证您的 VPC 配置
<a name="verify-your-vpc-configuration"></a>

所有必要组件创建完成后，请验证 VPC 配置以确保各项均已正确设置。

**检查 VPC**

```
aws ec2 describe-vpcs --vpc-id vpc-0123456789abcdef0
```

**检查子网**

```
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-0123456789abcdef0"
```

**检查路由表**

```
aws ec2 describe-route-tables --filters "Name=vpc-id,Values=vpc-0123456789abcdef0"
```

**检查互联网网关**

```
aws ec2 describe-internet-gateways --filters "Name=attachment.vpc-id,Values=vpc-0123456789abcdef0"
```

**检查 NAT 网关**

```
aws ec2 describe-nat-gateways --filter "Name=vpc-id,Values=vpc-0123456789abcdef0"
```

**检查安全组**

```
aws ec2 describe-security-groups --filters "Name=vpc-id,Values=vpc-0123456789abcdef0"
```

这些命令提供了有关 VPC 每个组件的详细信息，便于您验证各项是否配置正确。

## 部署 EC2 实例
<a name="deploy-ec2-instances"></a>

现在，您已经创建 VPC 基础设施，可以部署 EC2 实例来演示架构如何工作。您将在公有子网中启动 Web 服务器，并在私有子网中启动数据库服务器。

**创建用于访问 SSH 的密钥对**

首先，创建密钥对以安全地连接到实例：

```
aws ec2 create-key-pair --key-name vpc-tutorial-key --query 'KeyMaterial' --output text > vpc-tutorial-key.pem
chmod 400 vpc-tutorial-key.pem
```

此命令会创建新的密钥对，并将私有密钥保存到具有受限权限的文件中。

**查找最新的 Amazon Linux 2 AMI**

查找用于实例的最新 Amazon Linux 2 AMI：

```
aws ec2 describe-images --owners amazon \
  --filters "Name=name,Values=amzn2-ami-hvm-*-x86_64-gp2" "Name=state,Values=available" \
  --query "sort_by(Images, &CreationDate)[-1].ImageId" --output text
```

记下输出中的 AMI ID。在本教程中，我们将以“ami-0123456789abcdef0”作为示例。

**在公有子网中启动 Web 服务器**

现在，在公有子网中启动 EC2 实例作为 Web 服务器：

```
aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --count 1 \
  --instance-type t2.micro \
  --key-name vpc-tutorial-key \
  --security-group-ids sg-0123456789abcdef0 \
  --subnet-id subnet-0123456789abcdef0 \
  --associate-public-ip-address \
  --user-data '#!/bin/bash
                yum update -y
                yum install -y httpd
                systemctl start httpd
                systemctl enable httpd
                echo "<h1>Hello from $(hostname -f)</h1>" > /var/www/html/index.html' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=WebServer}]'
```

记下输出中的实例 ID。在本教程中，我们将使以“i-0123456789abcdef0”作为 Web 服务器实例的示例。

**在私有子网中启动数据库服务器**

接下来，在私有子网中启动 EC2 实例作为数据库服务器：

```
aws ec2 run-instances \
  --image-id ami-0123456789abcdef0 \
  --count 1 \
  --instance-type t2.micro \
  --key-name vpc-tutorial-key \
  --security-group-ids sg-0123456789abcdef1 \
  --subnet-id subnet-0123456789abcdef2 \
  --user-data '#!/bin/bash
                yum update -y
                yum install -y mariadb-server
                systemctl start mariadb
                systemctl enable mariadb' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=DBServer}]'
```

记下输出中的实例 ID。在本教程中，我们将以“i-0123456789abcdef1”作为数据库服务器实例的示例。

**访问 Web 服务器**

Web 服务器实例开始运行后，便可使用其公有 IP 地址对其进行访问：

```
aws ec2 describe-instances \
  --instance-ids i-0123456789abcdef0 \
  --query 'Reservations[0].Instances[0].PublicIpAddress' \
  --output text
```

此命令将输出 Web 服务器的公有 IP 地址。在本教程中，我们将以“203.0.113.10”作为示例。

现在，您可以在 Web 浏览器中打开此 URL：http://203.0.113.10

**使用 SSH 连接到您的实例**

要连接到 Web 服务器，请执行以下操作：

```
ssh -i vpc-tutorial-key.pem ec2-user@203.0.113.10
```

要连接到数据库服务器，需要先通过 SSH 连接到 Web 服务器，然后再连接到数据库服务器：

```
# Get the private IP of the database server
aws ec2 describe-instances \
  --instance-ids i-0123456789abcdef1 \
  --query 'Reservations[0].Instances[0].PrivateIpAddress' \
  --output text
```

此命令将输出数据库服务器的私有 IP 地址。在本教程中，我们将以“10.0.2.10”作为示例。

```
# First SSH to web server, then to database server
ssh -i vpc-tutorial-key.pem -A ec2-user@203.0.113.10
ssh ec2-user@10.0.2.10
```

这演示了您创建的网络架构：Web 服务器可公开访问，而数据库服务器只能从 VPC 内部访问。

## 问题排查
<a name="troubleshooting"></a>

以下是创建 VPC 时可能遇到的一些常见问题及其解决方法：

**CIDR 块重叠**

如果您收到有关 CIDR 块重叠的错误，请确保 VPC 和子网的 CIDR 块不会与账户中的现有 VPC 或子网重叠。

**权限错误**

如果遇到权限错误，请验证 IAM 用户或角色是否具有创建和管理 VPC 资源所需的权限。您可能需要附加 `AmazonVPCFullAccess` 策略或创建具有所需权限的自定义策略。

**资源限制**

Amazon 账户对您可以创建的 VPC、子网及其他资源的数量施加了默认限制。如果您达到这些限制，可通过 Amazon Support Center 请求提高限制。

**清理期间出现依赖项故障**

清理资源时，如果尝试以错误顺序删除资源，可能会遇到依赖项错误。始终按照与创建顺序相反的顺序删除资源，从依赖程度最高的资源开始。

## 清理 资源
<a name="clean-up-resources"></a>

完成 VPC 的使用后，可以清理资源以避免产生费用。按照与创建顺序相反的顺序删除资源，以正确处理依赖项。

**终止 EC2 实例**

```
aws ec2 terminate-instances --instance-ids i-0123456789abcdef0 i-0123456789abcdef1
aws ec2 wait instance-terminated --instance-ids i-0123456789abcdef0 i-0123456789abcdef1
```

**删除密钥对**

```
aws ec2 delete-key-pair --key-name vpc-tutorial-key
rm vpc-tutorial-key.pem
```

**删除 NAT 网关**

```
aws ec2 delete-nat-gateway --nat-gateway-id nat-0123456789abcdef0
aws ec2 wait nat-gateway-deleted --nat-gateway-ids nat-0123456789abcdef0
```

**释放弹性 IP**

```
aws ec2 release-address --allocation-id eipalloc-0123456789abcdef0
```

**删除安全组**

```
aws ec2 delete-security-group --group-id sg-0123456789abcdef1
aws ec2 delete-security-group --group-id sg-0123456789abcdef0
```

**删除路由表**

首先，查找路由表关联 ID：

```
aws ec2 describe-route-tables --route-table-id rtb-0123456789abcdef0
aws ec2 describe-route-tables --route-table-id rtb-0123456789abcdef1
```

然后取消路由表与子网的关联（将关联 ID 替换为输出中实际的 ID）：

```
aws ec2 disassociate-route-table --association-id rtbassoc-0123456789abcdef0
aws ec2 disassociate-route-table --association-id rtbassoc-0123456789abcdef1
aws ec2 disassociate-route-table --association-id rtbassoc-0123456789abcdef2
aws ec2 disassociate-route-table --association-id rtbassoc-0123456789abcdef3
```

然后删除路由表：

```
aws ec2 delete-route-table --route-table-id rtb-0123456789abcdef1
aws ec2 delete-route-table --route-table-id rtb-0123456789abcdef0
```

**分离并删除互联网网关**

```
aws ec2 detach-internet-gateway --internet-gateway-id igw-0123456789abcdef0 --vpc-id vpc-0123456789abcdef0
aws ec2 delete-internet-gateway --internet-gateway-id igw-0123456789abcdef0
```

**删除子网**

```
aws ec2 delete-subnet --subnet-id subnet-0123456789abcdef0
aws ec2 delete-subnet --subnet-id subnet-0123456789abcdef1
aws ec2 delete-subnet --subnet-id subnet-0123456789abcdef2
aws ec2 delete-subnet --subnet-id subnet-0123456789abcdef3
```

**删除 VPC**

```
aws ec2 delete-vpc --vpc-id vpc-0123456789abcdef0
```

## 投入生产
<a name="going-to-production"></a>

本教程旨在帮助您了解如何使用 Amazon CLI 创建 VPC。对于生产环境，请考虑以下安全和架构最佳实践：

1. **安全组规则**：将入站流量限制为特定 IP 范围内，而不是允许来自 0.0.0.0/0 的流量。

1. **高可用性**：在拥有私有子网的每个可用区部署 NAT 网关，以消除单点故障。

1. **网络 ACL**：实施网络 ACL 作为安全组之外的额外安全层。

1. **VPC 流日志**：启用 VPC 流日志来监控和分析网络流量模式。

1. **资源标记**：实施全面的标记策略，以更好地管理资源。

有关构建生产就绪架构的更多信息，请参阅 [Amazon Well-Architected 框架](https://docs.amazonaws.cn/wellarchitected/latest/framework/welcome.html)和 [Amazon 安全最佳实践](https://www.amazonaws.cn/architecture/security-identity-compliance)。

## 后续步骤
<a name="next-steps"></a>

现在，您已创建包含公有子网和私有子网的 VPC，可以：

1. 在公有子网或私有子网中[启动 EC2 实例](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/EC2_GetStarted.html)。

1. [部署负载均衡器](https://docs.amazonaws.cn/elasticloadbalancing/latest/userguide/load-balancer-getting-started.html)，以在多个实例之间分配流量。

1. [设置自动扩缩组](https://docs.amazonaws.cn/autoscaling/ec2/userguide/get-started-with-ec2-auto-scaling.html)，以实现高可用性和可扩展性。

1. 在私有子网中[配置 RDS 数据库](https://docs.amazonaws.cn/AmazonRDS/latest/UserGuide/CHAP_GettingStarted.html)。

1. [实施 VPC 对等连接](https://docs.amazonaws.cn/vpc/latest/peering/what-is-vpc-peering.html)，以连接其他 VPC。

1. [设置 VPN 连接](https://docs.amazonaws.cn/vpn/latest/s2svpn/SetUpVPNConnections.html)，以将 VPC 连接到本地网络。