AWS EC2 设置
概览
亚马逊 EC2 提供可调整的云计算能力。启动和配置虚拟服务器,完全控制网络、存储和安全设置。根据需求自动扩展。
何时使用
- Web 应用服务器
- 应用后端和 API
- 批量处理和计算作业
- 开发和测试环境
- 容器化应用(ECS)
- Kubernetes 集群(EKS)
- 数据库服务器
- VPN 和代理服务器
实施示例
1. 使用 AWS CLI 创建 EC2 实例
# 创建安全组
aws ec2 create-security-group \
--group-name web-server-sg \
--description "Web 服务器安全组" \
--vpc-id vpc-12345678
# 添加入站规则
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
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--protocol tcp \
--port 22 \
--cidr YOUR_IP/32
# 创建密钥对
aws ec2 create-key-pair \
--key-name my-app-key \
--query 'KeyMaterial' \
--output text > my-app-key.pem
chmod 400 my-app-key.pem
# 为 EC2 创建 IAM 角色
aws iam create-role \
--role-name ec2-app-role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# 附加策略
aws iam attach-role-policy \
--role-name ec2-app-role \
--policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
# 创建实例配置文件
aws iam create-instance-profile --instance-profile-name ec2-app-profile
aws iam add-role-to-instance-profile \
--instance-profile-name ec2-app-profile \
--role-name ec2-app-role
# 启动实例
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.micro \
--key-name my-app-key \
--security-group-ids sg-0123456789abcdef0 \
--iam-instance-profile Name=ec2-app-profile \
--user-data file://user-data.sh \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-server}]'
2. 用户数据脚本
#!/bin/bash
# user-data.sh
set -e
set -x
# 更新系统
apt-get update
apt-get upgrade -y
# 安装依赖
apt-get install -y \
curl \
wget \
git \
nodejs \
npm \
postgresql-client
# 安装 Node.js 应用
mkdir -p /opt/app
cd /opt/app
git clone https://github.com/myorg/myapp.git .
npm install --production
# 创建 systemd 服务
cat > /etc/systemd/system/myapp.service << EOF
[Unit]
Description=My Node App
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/app
ExecStart=/usr/bin/node index.js
Restart=on-failure
RestartSec=5
Environment="NODE_ENV=production"
Environment="PORT=3000"
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable myapp
systemctl start myapp
# 安装和配置 CloudWatch 代理
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
dpkg -i -E ./amazon-cloudwatch-agent.deb
# 配置日志流
cat > /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json << EOF
{
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/syslog",
"log_group_name": "/aws/ec2/web-server",
"log_stream_name": "{instance_id}"
},
{
"file_path": "/opt/app/logs/*.log",
"log_group_name": "/aws/ec2/app",
"log_stream_name": "{instance_id}"
}
]
}
}
},
"metrics": {
"metrics_collected": {
"cpu": {"measurement": [{"name": "cpu_usage_idle"}]},
"mem": {"measurement": [{"name": "mem_used_percent"}]},
"disk": {"measurement": [{"name": "used_percent"}]}
}
}
}
EOF
/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config \
-m ec2 \
-s \
-c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
3. Terraform EC2 配置
# ec2.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = { Name = "main-vpc" }
}
# 公共子网
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
map_public_ip_on_launch = true
tags = { Name = "public-subnet" }
}
# 互联网网关
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = { Name = "main-igw" }
}
# 路由表
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = { Name = "public-rt" }
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# 安全组
resource "aws_security_group" "web" {
name_prefix = "web-"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["YOUR_IP/32"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# IAM 角色
resource "aws_iam_role" "ec2_role" {
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "ec2_policy" {
role = aws_iam_role.ec2_role.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
}
resource "aws_iam_instance_profile" "ec2_profile" {
role = aws_iam_role.ec2_role.name
}
# 密钥对
resource "aws_key_pair" "deployer" {
key_name = "deployer-key"
public_key = file("~/.ssh/id_rsa.pub")
}
# AMI 数据源
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
}
# EC2 实例
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
iam_instance_profile = aws_iam_instance_profile.ec2_profile.name
key_name = aws_key_pair.deployer.key_name
user_data = base64encode(file("${path.module}/user-data.sh"))
root_block_device {
volume_size = 20
volume_type = "gp3"
delete_on_termination = true
encrypted = true
}
tags = {
Name = "web-server"
}
lifecycle {
create_before_destroy = true
}
}
# 弹性 IP
resource "aws_eip" "web" {
instance = aws_instance.web.id
domain = "vpc"
tags = { Name = "web-eip" }
}
# 自动扩展组
resource "aws_launch_template" "app" {
image_id = data.aws_ami.ubuntu.id
instance_type = "t3.small"
vpc_security_group_ids = [aws_security_group.web.id]
iam_instance_profile {
name = aws_iam_instance_profile.ec2_profile.name
}
user_data = base64encode(file("${path.module}/user-data.sh"))
tag_specifications {
resource_type = "instance"
tags = {
Name = "app-instance"
}
}
}
resource "aws_autoscaling_group" "app" {
name = "app-asg"
vpc_zone_identifier = [aws_subnet.public.id]
min_size = 1
max_size = 3
desired_capacity = 2
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
health_check_type = "ELB"
health_check_grace_period = 300
tag {
key = "Name"
value = "app-asg-instance"
propagate_at_launch = true
}
}
最佳实践
✅ 执行
- 使用安全组进行网络控制
- 附加 IAM 角色以访问 AWS
- 启用 CloudWatch 监控
- 使用 AMI 进行一致的部署
- 实施自动扩展以应对变化的负载
- 使用 EBS 进行持久化存储
- 为生产环境启用终止保护
- 保持系统更新和打补丁
❌ 不要
- 使用过于宽松的安全组
- 在用户数据中存储凭据
- 忽略 CloudWatch 指标
- 使用过时的 AMI
- 创建硬编码配置
- 忘记监控成本
监控
- CloudWatch 指标和仪表板
- 来自应用程序的 CloudWatch 日志
- CloudWatch 警报阈值
- EC2 实例健康检查
- 自动扩展活动