Linux 学习 - 第十四周作业

基于terraform和课程示例,完成使用terraform管理阿里云资源,包括ecs,vpc等资源

Terraform

8.1 快速入门

8.1.1 云上实验

8.1.1.1 Cloud Shell

访问: https://shell.aliyun.com

版本切换
powershell 复制代码
# 查看当前 Terraform 版本, 低于 1.2 建议切换新版
shell@Alicloud:~$ terraform version
Terraform v0.12.31

Your version of Terraform is out of date! The latest version
is 1.17.1. You can update by downloading from https://www.terraform.io/downloads.html
powershell 复制代码
# 查看当前支持的版本
shell@Alicloud:~$ tfenv list
  1.9.5
  1.5.7
  1.3.7
  0.13.7
* 0.12.31 (set by /usr/local/tfenv/version)
powershell 复制代码
# 切换到指定版本
tfenv use 1.9.5

# 确认
shell@Alicloud:~$ terraform version
Terraform v1.9.5
定制 ECS 模板
powershell 复制代码
mkdir tf-demo && cd tf-demo
cat > main.tf << 'EOF'
provider "alicloud" {
  region = var.region
}

# 资源创建的地域
variable "region" {
  default = "cn-beijing"
}

# ECS 实例名称
variable "instance_name" {
  default = "tf-cloudshell-test"
}

# ECS 实例规格
variable "instance_type" {
  default = "ecs.n2.small"
}

# 公网出带宽, 值为 0 时, 表示不开通公网
variable "internet_bandwidth" {
  default = 10
}

# ECS 系统镜像
variable "image_id" {
  default = "ubuntu_18_04_64_20G_alibase_20190624.vhd"
}

# ECS 系统盘类型
variable "disk_category" {
  default = "cloud_efficiency"
}

# ECS 实例登录密码
variable "password" {
  default = "TF-test@1234"
}

# 创建 VPC
resource "alicloud_vpc" "vpc" {
  vpc_name   = "tf_test_foo"
  cidr_block = "172.16.0.0/12"
}

# 根据实例规格和云盘类型查询存在资源的可用区
data "alicloud_zones" "default" {
  available_disk_category     = var.disk_category
  available_resource_creation = "VSwitch"
  available_instance_type     = var.instance_type
}

# 创建 vSwitch
resource "alicloud_vswitch" "vsw" {
  vpc_id     = alicloud_vpc.vpc.id
  cidr_block = "172.16.0.0/21"
  zone_id    = data.alicloud_zones.default.zones.0.id
}

# 创建安全组
resource "alicloud_security_group" "default" {
  security_group_name   = "default"
  vpc_id = alicloud_vpc.vpc.id
}

# 创建安全组入方向规则
resource "alicloud_security_group_rule" "allow_all_tcp" {
  type              = "ingress"
  ip_protocol       = "tcp"
  nic_type          = "intranet"
  policy            = "accept"
  port_range        = "1/65535"
  priority          = 1
  security_group_id = alicloud_security_group.default.id
  cidr_ip           = "0.0.0.0/0"
}

resource "alicloud_instance" "instance" {
  # 绑定安全组
  security_groups = alicloud_security_group.default.*.id
  instance_type = var.instance_type
  system_disk_category = var.disk_category
  image_id = var.image_id
  instance_name = var.instance_name
  # 所在交换机
  vswitch_id = alicloud_vswitch.vsw.id
  internet_max_bandwidth_out = var.internet_bandwidth
  password  = var.password
}
EOF
初始化环境
powershell 复制代码
terraform init
powershell 复制代码
文件解读
shell@Alicloud:~/tf-demo$ ls -a
main.tf             # Terraform 配置文件
.terraform          # terraform init 生成的目录, 存储已下载的 Provider 插件
.terraform.lock.hcl # 锁文件, 记录了 Provider 的源和版本
powershell 复制代码
# 重新初始化
terraform init -force-copy

# 更新方式初始化
terraform init -upgrade
查看资源创建计划
powershell 复制代码
terraform plan
powershell 复制代码
符号解读
加号 (+) : 资源旁边的加号意味着 Terraform 将创建该资源, 并展示将要设置的属性
减号斜线加号 (-/+) : 表示 Terraform 将销毁当前资源并重新创建一个新的资源, 而不是就地更新它的属性
波浪号 (~) : 表示 Terraform 将就地更新资源属性
减号 (-) : 表示销毁当前资源实例
powershell 复制代码
# 将生成的计划保存为文件, 之后可以将文件作为执行计划传递给 terraform apply 来执行
terraform plan -out=tf.tfplan
执行计划
powershell 复制代码
terraform apply
...
  Enter a value: yes # 输入 yes 确认执行
...
# 注意输出的各资源 ID
alicloud_vpc.vpc: Creation complete after 6s [id=vpc-2ze7zzyf0hp1qzr6gfkkm]
...
alicloud_security_group.default: Creation complete after 1s [id=sg-2ze64iasa1glc7tzjd5e]
...
alicloud_vswitch.vsw: Creation complete after 4s [id=vsw-2zeruztpu0viyg1i2k7y3]
...
alicloud_instance.instance: Creation complete after 16s [id=i-2ze0iy1k84ivvoq6vwd3]

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.

浏览器查看阿里云 ECS

8.1.1.2 Cloud Shell 命令
查看概览信息
powershell 复制代码
# 查看资源状态
shell@Alicloud:~/tf-demo$ terraform state list
data.alicloud_zones.default
alicloud_instance.instance
alicloud_security_group.default
alicloud_security_group_rule.allow_all_tcp
alicloud_vpc.vpc
alicloud_vswitch.vsw

# 查看 ECS 实例的详细状态
terraform state show alicloud_instance.instance

# 查看资源依赖关系
terraform graph
查看详细信息
powershell 复制代码
# 查看 VPC 详情
aliyun vpc DescribeVpcs --VpcId "vpc-2ze7zzyf0hp1qzr6gfkkm" --RegionId cn-beijing

# 查看交换机详情
aliyun vpc DescribeVSwitches --VSwitchId "vsw-2zeruztpu0viyg1i2k7y3" --RegionId cn-beijing

# 查看安全组所有出入站规则
aliyun ecs DescribeSecurityGroupAttribute --SecurityGroupId "sg-2ze64iasa1glc7tzjd5e" --RegionId cn-beijing

# 查看 ECS 实例详情, 确认规格、带宽、镜像等
aliyun ecs DescribeInstances --InstanceIds "['i-2ze0iy1k84ivvoq6vwd3']" --RegionId cn-beijing
获取统计信息脚本
powershell 复制代码
cat > get_resource_info.sh << 'EOF'
#!/bin/bash
# *************************************
# * 功能: 获取ECS相关的信息
# * 作者:
# * 联系:
# * 版本:
# *************************************

# 核心资源 ID 配置
VPC_ID="vpc-2ze7zzyf0hp1qzr6gfkkm"
VSWITCH_ID="vsw-2zeruztpu0viyg1i2k7y3"
SG_ID="sg-2ze64iasa1glc7tzjd5e"
ECS_ID="i-2ze0iy1k84ivvoq6vwd3"
REGION="cn-beijing"

# 统一处理: 去除所有缩进/空格, 便于精准匹配
get_vpc_info() {
  aliyun vpc DescribeVpcs --VpcId $VPC_ID --RegionId $REGION | tr -d '\t '
}
get_vswitch_info() {
  aliyun vpc DescribeVSwitches --VSwitchId $VSWITCH_ID --RegionId $REGION | tr -d '\t '
}
get_sg_info() {
  aliyun ecs DescribeSecurityGroupAttribute --SecurityGroupId $SG_ID --RegionId $REGION | tr -d '\t '
}
get_ecs_info() {
  aliyun ecs DescribeInstances --InstanceIds "[\"$ECS_ID\"]" --RegionId $REGION | tr -d '\t '
}

# 1. 验证 VPC (兼容缩进, 精准提取)
echo -e "【VPC】"
echo "名称: $(get_vpc_info | grep -o '"VpcName":"[^"]*' | cut -d'"' -f4)"
echo "ID: $VPC_ID"
echo "地域: $REGION"
echo "网段: $(get_vpc_info | grep -o '"CidrBlock":"[^"]*' | cut -d'"' -f4)"
echo "状态: $(get_vpc_info | grep -o '"Status":"[^"]*' | cut -d'"' -f4)"

# 2. 验证交换机
echo -e "\n【交换机】"
echo "ID: $VSWITCH_ID"
echo "所属VPC: $(get_vswitch_info | grep -o '"VpcId":"[^"]*' | cut -d'"' -f4)"
echo "地域: $REGION"
echo "可用区: $(get_vswitch_info | grep -o '"ZoneId":"[^"]*' | cut -d'"' -f4)"
echo "网段: $(get_vswitch_info | grep -o '"CidrBlock":"[^"]*' | cut -d'"' -f4)"
echo "状态: $(get_vswitch_info | grep -o '"Status":"[^"]*' | cut -d'"' -f4)"

# 3. 验证安全组规则
echo -e "\n【安全组规则】"
echo "安全组ID: $SG_ID"
echo "地域: $REGION"
echo "协议: $(get_sg_info | grep -o '"IpProtocol":"[^"]*' | cut -d'"' -f4)"
echo "端口范围: $(get_sg_info | grep -o '"PortRange":"[^"]*' | cut -d'"' -f4)"
echo "源IP: $(get_sg_info | grep -o '"SourceCidrIp":"[^"]*' | cut -d'"' -f4)"
echo "策略: $(get_sg_info | grep -o '"Policy":"[^"]*' | cut -d'"' -f4)"

# 4. 验证 ECS 实例 (适配无引号字段)
echo -e "\n【ECS实例】"
echo "名称: $(get_ecs_info | grep -o '"InstanceName":"[^"]*' | cut -d'"' -f4)"
echo "ID: $ECS_ID"
echo "地域: $REGION"
echo "规格: $(get_ecs_info | grep -o '"InstanceType":"[^"]*' | cut -d'"' -f4)"
echo "公网带宽: $(get_ecs_info | grep -o '"InternetMaxBandwidthOut":[0-9]*' | cut -d':' -f2)"
echo "状态: $(get_ecs_info | grep -o '"Status":"[^"]*' | cut -d'"' -f4)"
EOF
powershell 复制代码
shell@Alicloud:~/tf-demo$ bash get_resource_info.sh
【VPC】
名称: tf_test_foo
ID: vpc-2ze7zzyf0hp1qzr6gfkkm
地域: cn-beijing
网段: 172.16.0.0/12
状态: Available

【交换机】
ID: vsw-2zeruztpu0viyg1i2k7y3
所属VPC: vpc-2ze7zzyf0hp1qzr6gfkkm
地域: cn-beijing
可用区: cn-beijing-g
网段: 172.16.0.0/21
状态: Available

【安全组规则】
安全组ID: sg-2ze64iasa1glc7tzjd5e
地域: cn-beijing
协议: TCP
端口范围: 1/65535
源IP: 0.0.0.0/0
策略: Accept

【ECS实例】
名称: tf-cloudshell-test
ID: i-2ze0iy1k84ivvoq6vwd3
地域: cn-beijing
规格: ecs.n2.small
公网带宽: 10
状态: Running
释放资源
powershell 复制代码
terraform destroy
...
  Enter a value: yes # 输入 yes 确认执行
powershell 复制代码
# 确认效果
terraform state list
# 输出为空
8.1.1.3 Explorer

Terraform Explorer 是阿里云基于 Terraform 开源版提供的一款在线调试 Terraform 配置文件的工具

访问: https://api.aliyun.com/terraform

创建 VPC

填入参数, 点击发起调试, 相当于 plan

powershell 复制代码
产品: VPC
资源类型: 默认 (alicloud_vp)
区域: 选择华北6
VPC私网网段: 192.168.0.0/16
VPC描述信息: 使用 Terraform 创建的 VPC

点击执行, 相当于 apply

点击 资源详情 查看详细信息

查看创建的 VPC
释放资源

点击 销毁资源

点击 执行

8.1.2 本地实践

8.1.2.1 认证环境
创建 RAM 账号

使用阿里云主账号或拥有 RAM 管理员权限的账号登录 RAM 访问控制

powershell 复制代码
用户名: terraform-test
访问方式: 勾选使用永久 AccessKey 访问
powershell 复制代码
保存 AccessKey
AccessKey ID: LTAI5t6QQZ1z3td7pLC6fSQ5
AccessKey Secret: 3k32ovlkuHW2jX0w0699ZViZxeZEb5
RAM 账号授权

权限策略里的搜索框可以搜索权限, 依次添加 6 个资源权限, 点击 确认新增授权

账号禁用方法

如果不想删除账号, 可以禁用 AccessKey

安装测试工具

安装阿里云CLI工具, 测试 账号权限

项目地址: https://github.com/aliyun/aliyun-cli/releases?spm=5176.ecscore_server.console-base_help.18.2e5c4df5wYX5i2

powershell 复制代码
# 下载最新版解压
curl https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz | tar -xzv

# 下载历史版本解压
curl -L https://aliyuncli.alicdn.com/aliyun-cli-linux-3.0.170-amd64.tgz | tar -xzv

mv aliyun /usr/local/bin/
powershell 复制代码
# 非交互式配置 RAM 账号的 
aliyun configure set \
  --profile default \
  --access-key-id LTAI5t6QQZ1z3td7pLC6fSQ5 \
  --access-key-secret 3k32ovlkuHW2jX0w0699ZViZxeZEb5 \
  --region cn-hangzhou \
  --language zh
powershell 复制代码
# 交互式配置, 推荐, 避免命令写入历史记录
[root@master1 ~ ]#aliyun configure
Configuring profile 'default' in 'AK' authenticate mode...
Access Key Id [*********************SQ5]: LTAI5t6QQZ1z3td7pLC6fSQ5
Access Key Secret [***************************Eb5]: 3k32ovlkuHW2jX0w0699ZViZxeZEb5
Default Region Id [cn-hangzhou]: 
Default Output Format [json]: json (Only support json)
Default Language [zh|en] zh: 
Saving profile[default] ...Done.

Configure Done!!!
powershell 复制代码
# 查看当前配置
aliyun configure list
查看测试
powershell 复制代码
# 测试 VPC 查询权限
aliyun vpc DescribeVpcs
powershell 复制代码
# 测试 ECS 查询权限
aliyun ecs DescribeInstances
powershell 复制代码
# 测试 SLB 查询权限
aliyun slb DescribeLoadBalancers
powershell 复制代码
# 测试 RDS 查询权限
aliyun rds DescribeDBInstances
powershell 复制代码
# 测试 EIP 查询权限
aliyun vpc DescribeEipAddresses
EIP 测试
powershell 复制代码
# 创建测试 EIP
aliyun vpc AllocateEipAddress --RegionId cn-hangzhou --Name terraform-test-eip
powershell 复制代码
# 确认 EIP 信息
aliyun vpc DescribeEipAddresses
powershell 复制代码
# 精准查询指定 EIP
aliyun vpc DescribeEipAddresses --AllocationId "eip-bp1l3hc8g0zq946rpesj6"
powershell 复制代码
# 释放 EIP
aliyun vpc ReleaseEipAddress --AllocationId "eip-bp1l3hc8g0zq946rpesj6"

# 验证 
aliyun vpc DescribeEipAddresses --AllocationId "eip-bp1l3hc8g0zq946rpesj6"
8.1.2.2 工具实践
Ubuntu 安装工具

参考网站: https://developer.hashicorp.com/terraform/install

powershell 复制代码
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
powershell 复制代码
# 确认效果
[root@ubuntu-240 ~ ]#terraform -version
Terraform v1.17.1
on linux_amd64
基础环境
powershell 复制代码
terraform init
powershell 复制代码
# 在当前用户家目录配置镜像加速
cat > ~/.terraformrc << 'EOF'
provider_installation {
  network_mirror {
    url = "https://mirrors.aliyun.com/terraform/"
    # 限制只有阿里云相关 Provider 从国内镜像源下载
    include = ["registry.terraform.io/aliyun/alicloud", 
               "registry.terraform.io/hashicorp/alicloud"
              ]
}
  direct {
    # 声明除了阿里云相关 Provider, 其它 Provider 保持原有的下载链路
    exclude = ["registry.terraform.io/aliyun/alicloud", 
               "registry.terraform.io/hashicorp/alicloud"
              ]  
  }
}
EOF
powershell 复制代码
# 如果当前环境已存在 providers, 执行命令使配置生效
terraform init -upgrade
简单实践

提前在乌兰察布区域创建一个 OSS 对象 bucket sswang-magedu-test1

注意 RAM 账号需要拥有 AliyunOSSFullAccess 权限

powershell 复制代码
# 创建配置文件
mkdir terraform-aliyun && cd terraform-aliyun
cat > main.tf << 'EOF'
terraform {
  required_providers {
    alicloud = {
      source  = "aliyun/alicloud"
      version = "~> 1.266.0"
    }
  }
  # 没有下面的配置的话, state 文件是保存到本地目录下
  backend "oss" {
    bucket = "sswang-magedu-test1"   # 替换成你已创建的 OSS bucket
    key    = "terraform.tfstate"     # 存到 bucket 里面的文件名
    region = "cn-wulanchabu"         # 必须与你 bucket 所在地域一致
  }
}

# 配置乌兰察布地域, 数据源自动继承该地域
provider "alicloud" {
  region = "cn-wulanchabu"
}

# 数据源:仅空块即可, 自动读取 Provider 的地域, 无任何多余参数
data "alicloud_zones" "default" {}

# 创建乌兰察布 VPC
resource "alicloud_vpc" "vpc" {
  vpc_name   = "tf_wulcb_vpc"
  cidr_block = "172.16.0.0/16"
}

# 创建乌兰察布交换机
resource "alicloud_vswitch" "vsw" {
  vpc_id     = alicloud_vpc.vpc.id
  cidr_block = "172.16.0.0/24"
  zone_id    = data.alicloud_zones.default.zones.0.id
}
EOF
powershell 复制代码
# 创建环境变量, 存放 RAM 账号信息
cat > terraform_secret << 'EOF'
export ALICLOUD_ACCESS_KEY="LTAI5t6QQZ1z3td7pLC6fSQ5"
export ALICLOUD_SECRET_KEY="3k32ovlkuHW2jX0w0699ZViZxeZEb5"
export ALICLOUD_REGION="cn-wulanchabu"
EOF
source terraform_secret
powershell 复制代码
# 环境初始化
terraform init
powershell 复制代码
# 预览
terraform plan
powershell 复制代码
# 执行计划
terraform apply
...
  Enter a value: yes
...
powershell 复制代码
# 确认效果
terraform state list

# 确认依赖关系
terraform graph
powershell 复制代码
# 确认 OSS 文件数量
[root@master1 ~ ]#aliyun oss ls oss://sswang-magedu-test1 -e oss-cn-wulanchabu.aliyuncs.com
LastModifiedTime                   Size(B)  StorageClass   ETAG                                  ObjectName
2026-10-31 12:45:32 +0800 CST         5629      Standard   7EC1E9968315717101256F011C47E244      oss://sswang-magedu-test1/env:/terraform.tfstate
Object Number is: 1

0.186802(s) elapsed

# 查看文件状态
[root@master1 ~ ]#aliyun oss stat oss://sswang-magedu-test1 -e oss-cn-wulanchabu.aliyuncs.com
Name                  : sswang-magedu-test1
Location              : oss-cn-wulanchabu
CreationDate          : 2026-10-31 12:39:22 +0800 CST
ExtranetEndpoint      : oss-cn-wulanchabu.aliyuncs.com
IntranetEndpoint      : oss-cn-wulanchabu-internal.aliyuncs.com
ACL                   : private
Owner                 : 1140913766715991
StorageClass          : Standard
RedundancyType        : LRS
TransferAcceleration  : Disabled
CrossRegionReplication: Disabled
AccessMonitor         : Disabled

0.185616(s) elapsed
powershell 复制代码
# 查看指定区域的 VPC
aliyun vpc DescribeVpcs --RegionId cn-wulanchabu

# 查看 VPC 信息
[root@master1 ~ ]#aliyun vpc DescribeVpcs --RegionId cn-wulanchabu | jq -r '.Vpcs.Vpc[] | "VPC名称:\(.VpcName) | 网段:\(.CidrBlock)"'
VPC名称:tf_wulcb_vpc | 网段:172.16.0.0/16

# 查看交换机信息
[root@master1 ~ ]#aliyun vpc DescribeVSwitches --RegionId cn-wulanchabu | jq -r '.VSwitches.VSwitch[] | "交换机名称:\(.VSwitchName) | 网段:\(.CidrBlock) | 可用区:\(.ZoneId) | 所属VPC:\(.VpcId)"'
交换机名称: | 网段:172.16.0.0/24 | 可用区:cn-wulanchabu-a | 所属VPC:vpc-0jlcos91cqhf213expxeg
powershell 复制代码
# 移除资源, -auto-approve 跳过确认步骤
terraform destroy -auto-approve

# 确认效果
terraform state list

8.1.3 ECS 案例

8.1.3.1 环境准备
powershell 复制代码
# 确认环境
[root@ubuntu-240 ~ ]#source terraform_secret

[root@ubuntu-240 ~ ]#env | grep ALICLOUD
ALICLOUD_REGION=cn-wulanchabu
ALICLOUD_SECRET_KEY=3k32ovlkuHW2jX0w0699ZViZxeZEb5
ALICLOUD_ACCESS_KEY=LTAI5t6QQZ1z3td7pLC6fSQ5
powershell 复制代码
# 创建项目目录
mkdir -p /data/case/ecs && cd /data/case/ecs/

# 配置镜像加速
cat > .terraformrc << 'EOF'
provider_installation {
  network_mirror {
    url = "https://mirrors.aliyun.com/terraform/"
    # 限制只有阿里云相关 Provider 从国内镜像源下载
    include = ["registry.terraform.io/aliyun/alicloud", 
               "registry.terraform.io/hashicorp/alicloud"
              ]
}
  direct {
    # 声明除了阿里云相关 Provider, 其它 Provider 保持原有的下载链路
    exclude = ["registry.terraform.io/aliyun/alicloud", 
               "registry.terraform.io/hashicorp/alicloud"
              ]  
  }
}
EOF
8.1.3.2 基础环境属性

查询镜像和规格

powershell 复制代码
# 查询镜像 ID, 默认仅方法第一页 10 条数据
aliyun ecs DescribeImages --RegionId cn-wulanchabu | awk '/ImageId/{print $1,$2}'

# 查询该地域下, 支持 ecs.e-c1m1.large 这个特定实例规格的镜像 ID
aliyun ecs DescribeImages --RegionId cn-wulanchabu --InstanceType ecs.e-c1m1.large | grep "ImageId"

# 查询第一页的 100 个镜像, 过滤出带 ubuntu 的镜像
aliyun ecs DescribeImages --RegionId cn-wulanchabu --PageSize 100 | grep -E 'ImageId' | grep ubuntu

# 循环查询 10 页, 每页 100 个 镜像, 过滤出所有带 ubuntu 的镜像
for p in {1..10};do aliyun ecs DescribeImages --RegionId cn-wulanchabu --PageNumber $p --PageSize 100 | grep ImageId | grep ubuntu; done

# 统计乌兰察布地域下, 总共有多少种可用的实例规格 
aliyun ecs DescribeInstanceTypes --RegionId cn-wulanchabu --pager | jq -r '.InstanceTypes.InstanceType[] | .InstanceTypeId' | wc -l

# 确认该地域是否有 ecs.e-c1m1.large 这个规格
aliyun ecs DescribeInstanceTypes --RegionId cn-wulanchabu --pager | jq -r '.InstanceTypes.InstanceType[] | .InstanceTypeId' | grep e-c1m1.large

配置 Provider 和版本

powershell 复制代码
cat > providers.tf << 'EOF'
# 定义 Terraform 版本和阿里云 Provider
terraform {
  required_providers {
    alicloud = {
      source  = "aliyun/alicloud"
      version = "~> 1.266.0"
    }
  }
  required_version = ">= 1.5.0"
}

# 阿里云 Provider 配置 (乌兰察布地域)
provider "alicloud" {
  region = "cn-wulanchabu"
}
EOF

配置数据源 (可用区和镜像)

powershell 复制代码
cat > data-sources.tf << 'EOF'
# 数据源1: 获取乌兰察布可用区 (自动继承 Provider 地域)
data "alicloud_zones" "default" {}

# 数据源2: 获取 Ubuntu 24.04 官方镜像
data "alicloud_images" "default" {
  name_regex  = "^ubuntu_24_04.*"
  most_recent = true
  owners      = "system"
}

# locals 本地变量兜底: 优先用匹配到的镜像 ID, 无结果则硬编码 CLI 查到的 ID
locals {
  ubuntu_image_id = data.alicloud_images.default.images != [] ? data.alicloud_images.default.images.0.id : "ubuntu_24_04_x64_20G_alibase_20261016.vhd"
}
EOF
powershell 复制代码
镜像名字匹配问题
name_regex  = "^ubuntu_24_04.*"
这个正则匹配, 有可能匹配到很多个不适合的镜像, 所以会发生报错, 解决问题就是, 匹配的方法更加精准一些, 比如
  name_regex  = "^ubuntu_24_04_x64_20G"
  name_regex  = "^ubuntu_24_04_x64_20G_alibase_20261016.vhd"
只要能够通过关键字, 找到配套的镜像名字就可以
8.1.3.3 定制网络配置
powershell 复制代码
cat > network.tf << 'EOF'
# VPC (专有网络)
resource "alicloud_vpc" "vpc" {
  vpc_name   = "ecs-practice-vpc"
  cidr_block = "172.16.0.0/16"
}

# 交换机 (VSwitch) - 关联 VPC 和可用区
resource "alicloud_vswitch" "vsw" {
  vpc_id     = alicloud_vpc.vpc.id
  cidr_block = "172.16.1.0/24"
  zone_id    = data.alicloud_zones.default.zones.0.id
}
EOF
8.1.3.4 定制 ECS 安全组
powershell 复制代码
cat > security-group.tf << 'EOF'
# ECS 安全组 (关联 VPC)
resource "alicloud_security_group" "sg" {
  security_group_name   = "ecs-practice-sg"
  vpc_id = alicloud_vpc.vpc.id
}

# 入站规则1: 开放 22 端口 (SSH 登录)
resource "alicloud_security_group_rule" "sg_ingress_22" {
  type              = "ingress"
  ip_protocol       = "tcp"
  port_range        = "22/22"
  cidr_ip           = "0.0.0.0/0"
  security_group_id = alicloud_security_group.sg.id
}

# 入站规则2: 开放 80 端口 (HTTP)
resource "alicloud_security_group_rule" "sg_ingress_80" {
  type              = "ingress"
  ip_protocol       = "tcp"
  port_range        = "80/80"
  cidr_ip           = "0.0.0.0/0"
  security_group_id = alicloud_security_group.sg.id
}
EOF
8.1.3.5 定制 ECS 配置
powershell 复制代码
cat > ecs.tf << 'EOF'
# ECS 实例配置
resource "alicloud_instance" "ecs" {
  # 基础标识
  instance_name = "ecs-practice-instance"

  # 硬件配置 (入门级, 按需计费)
  instance_type = "ecs.e-c1m1.large"
  image_id      = data.alicloud_images.default.images.0.id

  # 网络配置 (关联交换机和安全组)
  vswitch_id      = alicloud_vswitch.vsw.id
  security_groups = [alicloud_security_group.sg.id]

  # 存储配置 (20GB 云盘)
  system_disk_category = "cloud_essd_entry"
  data_disks {
    category = "cloud_essd_entry"
    size     = 20
  }

  # 标签 (便于资源管理)
  tags = {
    Environment = "Practice"
    Region      = "Wulanchabu"
    ManagedBy   = "Terraform"
  }
}
EOF
8.1.3.6 实例操作
powershell 复制代码
terraform init

terraform plan

terraform apply -auto-approve

terraform state list
8.1.3.7 更改 ECS 配置
powershell 复制代码
cat > ecs.tf << 'EOF'
# ECS 实例配置
resource "alicloud_instance" "ecs" {
  # 基础标识, 增加 主机名和 内网 IP 配置
  instance_name = "my-custom-ecs" 
  host_name = "ecs-static-ip-host" 
  private_ip = "172.16.1.100" 

  # 硬件配置 (入门级, 按需计费)
  instance_type = "ecs.e-c1m1.large"
  image_id      = data.alicloud_images.default.images.0.id

  # 网络配置 (关联交换机和安全组)
  vswitch_id      = alicloud_vswitch.vsw.id
  security_groups = [alicloud_security_group.sg.id]

  # 存储配置 (20GB 云盘)
  system_disk_category = "cloud_essd_entry"
  data_disks {
    category = "cloud_essd_entry"
    size     = 20
  }

  # 标签 (便于资源管理)
  tags = {
    Environment = "Practice"
    Region      = "Wulanchabu"
    ManagedBy   = "Terraform"
  }
}
EOF
8.1.3.8 增加 EIP
powershell 复制代码
cat > eip.tf << 'EOF'
# 创建静态公网 EIP
resource "alicloud_eip_address" "ecs_eip" {
  address_name = "ecs-static-eip"
}

# 将 EIP 绑定到 ECS (实现公网静态 IP)
resource "alicloud_eip_association" "eip_bind" {
  allocation_id = alicloud_eip_address.ecs_eip.id
  instance_id   = alicloud_instance.ecs.id
}
EOF
8.1.3.9 定制信息输出
powershell 复制代码
cat > outputs.tf << 'EOF'
# 输出 ECS 关键信息
output "ecs_instance_name" {
  value = alicloud_instance.ecs.instance_name
  description = "自定义 ECS 实例名称"
}

output "ecs_host_name" {
  value = alicloud_instance.ecs.host_name
  description = "ECS 系统主机名"
}

output "ecs_private_ip" {
  value = alicloud_instance.ecs.private_ip
  description = "定制的静态私有 IP"
}

output "ecs_public_eip" {
  value = alicloud_eip_address.ecs_eip.ip_address
  description = "绑定的静态公网 EIP"
}
EOF
8.1.3.10 实例更新
powershell 复制代码
# 重新初始化 (确保资源依赖加载)
terraform init -reconfigure

# 预览变更计划, 确认静态 IP/名称配置
terraform plan
...
  + ecs_host_name     = "ecs-static-ip-host"
  + ecs_instance_name = "my-custom-ecs"
  + ecs_private_ip    = "172.16.1.100"
  + ecs_public_eip    = (known after apply)
...

# 执行创建, 自动创建 ECS + 绑定静态 IP/EIP
terraform apply --auto-approve

# 确认信息输出效果
[root@ubuntu-240 ecs ]#terraform output
ecs_host_name = "ecs-static-ip-host"
ecs_instance_name = "my-custom-ecs"
ecs_private_ip = "172.16.1.100"
ecs_public_eip = "8.130.143.61"

# 其他信息输出
terraform state list
7.1.3.11 实例销毁
powershell 复制代码
terraform destroy --auto-approve
7.1.3.12 反复 apply 的流程
  • 配置文件未改变
    • 首次执行创建 ECS, 记录到 State
    • 后续执行对比配置文件和实际状态未发生改变, 无任何操作
  • 配置文件修改可在线更新参数
    • 例如修改实例名称
    • Terraform 发现「实例名称」不匹配, 且阿里云支持 ECS 名称在线更新
    • 直接更新旧 ECS 的名称, 不删除、不重建
  • 配置文件修改不可在线更新参数
    • 例如实例规格/镜像
    • Terraform 发现「实例规格」不匹配, 且阿里云不支持 ECS 规格在线更新
    • 先删除旧 ECS,再创建新 ECS

8.1.4 WEB 服务

8.1.4.1 Flask 应用
powershell 复制代码
# 部署 python 环境
apt update && apt -y install python3 python3-pip nginx build-essential python3-dev python3.12-venv
powershell 复制代码
# 创建 python 虚拟环境
cd /data/

python3 -m venv myflaskenv

[root@ubuntu-240 data ]#ls
case  myflaskenv

source myflaskenv/bin/activate
powershell 复制代码
# 安装 Flask 环境
# 方法一: 手工指定源
pip install flask --index-url https://mirrors.aliyun.com/pypi/simple/

# 方法二: 默认源安装
pip config set global.index-url https://pypi.doubanio.com/simple
pip config set install.trusted-host pypi.doubanio.com
pip config list global.index-url='https://pypi.doubanio.com/simple'
pip install flask
powershell 复制代码
# 创建 flask 项目
mkdir flaskapp && cd flaskapp/
cat > app.py << 'EOF'
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello, World!\n'
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=True)
EOF
powershell 复制代码
# 后台运行项目
nohup python3 app.py >/dev/null 2>&1 &
powershell 复制代码
# 测试
[root@ubuntu-240 flaskapp ]#ss -ntlp | grep 80
LISTEN 0      128          0.0.0.0:80        0.0.0.0:*    users:(("python3",pid=29955,fd=6),("python3",pid=29955,fd=5),("python3",pid=29954,fd=5))

[root@ubuntu-240 flaskapp ]#curl localhost
Hello, World!
powershell 复制代码
# 还原环境
kill -9 29954

# 退出 python 虚拟环境
deactivate
8.1.4.2 Web 应用
环境准备
powershell 复制代码
cd /data/case/ && cp -a ecs ecs-2 && cd ecs-2/ && rm -rf .terraform .terraform.lock.hcl
powershell 复制代码
# 准备测试文件
cat > app.py << 'EOF'
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello, World!\n'
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=True)
EOF
更改 ECS 属性
powershell 复制代码
# 新增变量定义, 用于 SSH 连接
cat >> providers.tf << 'EOF'

# 新增: 定义 ECS 登录密码变量
variable "ecs_password" {
  type        = string
  default     = "Admin@123"
  description = "ECS 实例 root 用户密码"
}
EOF
powershell 复制代码
# 在最后一个 } 上方新增 SSH 认证配置
vim ecs.tf
...

  # 主机密码
  password      = var.ecs_password
  # user_data 自动启用 root 密码登录
  user_data     = <<-EOF
#!/bin/bash
# 启用 SSH 密码登录
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
systemctl restart sshd
EOF
}
powershell 复制代码
user_data 是阿里云 ECS 的核心参数, 作用是:
  ECS 实例第一次启动时, 自动执行 EOF 之间的脚本 (相当于 "开机自执行脚本")
  无需手动登录 ECS, 就能完成初始化配置 (比如启用密码登录、安装软件、配置服务等)
部署应用配置
powershell 复制代码
cat > deploy_app.tf << 'EOF'
# 新增: 部署 Flask 应用的 null_resource
resource "null_resource" "deploy_flask" {
  # 触发条件: ECS 实例创建完成 + app.py 文件变更
  triggers = {
    # 触发条件1: ECS 实例 ID 变化 (比如 ECS 被重建)
    ecs_id      = alicloud_instance.ecs.id
    # 触发条件2: 本地 app.py 文件内容变化 (文件哈希值变化)
    script_hash = filesha256("app.py")  # 现在 app.py 已存在, 可正常读取
  }

  # 依赖: 等待 ECS 实例创建完成、EIP 绑定完成
  depends_on = [
    alicloud_instance.ecs,
    alicloud_eip_association.eip_bind
  ]

  # 第一步: 上传 app.py 到 ECS
  provisioner "file" {
    connection {
      type     = "ssh"
      user     = "root"
      password = var.ecs_password
      host     = alicloud_eip_address.ecs_eip.ip_address
      port     = 22
      timeout  = "5m"  # 增加超时, 避免 ECS SSH 未就绪
    }
    source      = "app.py"               # 本地 app.py 路径 (已创建)
    destination = "/tmp/app.py"          # ECS 目标路径
  }

  # 第二步: 远程执行部署命令
  provisioner "remote-exec" {
    connection {
      type     = "ssh"
      user     = "root"
      password = var.ecs_password
      host     = alicloud_eip_address.ecs_eip.ip_address
      port     = 22
      timeout  = "5m"
    }
    inline = [
      # 更新系统包 (Ubuntu 24.04 默认无 pip)
      "apt update -y",
      "apt install -y python3-pip python3-flask",
      # 安装 Flask (兼容方式)
      "pip3 install flask --upgrade",
      # 停止旧进程 (避免端口占用)
      "pkill -f 'python3 /tmp/app.py' || true",
      # 后台运行 Flask, 日志输出到 /tmp/flask.log
      "nohup python3 /tmp/app.py > /tmp/flask.log 2>&1 &",
      "sleep 3",  # 等待应用启动
      # 验证 80 端口是否监听
      "ss -ntlp | grep :80 || echo 'Flask 应用启动失败, 请查看 /tmp/flask.log'"
    ]
  }

  # 用 provisioner 的重试逻辑
  provisioner "local-exec" {
    command = "echo 'Flask 部署完成, 访问地址: http://${alicloud_eip_address.ecs_eip.ip_address}'"
  }
}
EOF
powershell 复制代码
# 新版推荐 terraform_data 替换 null_resource
resource "terraform_data" "deploy_flask" {
  # null_resource 用 triggers
  # terraform_data 用 input, 注意格式
  input = join(",", [
    alicloud_instance.ecs.id,
    filesha256("app.py")
  ])
执行计划
powershell 复制代码
terraform init

terraform plan

terraform apply --auto-approve
测试效果
powershell 复制代码
terraform state list

[root@ubuntu-240 ecs-2 ]#terraform output
ecs_host_name = "ecs-static-ip-host"
ecs_instance_name = "my-custom-ecs"
ecs_private_ip = "172.16.1.100"
ecs_public_eip = "8.130.169.240"
powershell 复制代码
# 访问公网 IP
[root@ubuntu-240 ecs-2 ]#curl http://8.130.169.240
Hello, World!
8.1.4.3 增加 MySQL
环境准备
powershell 复制代码
cd /data/case/ && cp -a ecs-2 ecs-3 && cd ecs-3/ && rm -rf .terraform .terraform.lock.hcl
powershell 复制代码
# 修改测试文件
cat > app.py << 'EOF'
from flask import Flask
import pymysql
from pymysql.err import OperationalError

# 初始化 Flask 应用
app = Flask(__name__)

# RDS MySQL 连接配置 (和 Terraform 中的 RDS 配置一致)
MYSQL_CONFIG = {
    'host': '172.16.1.202',       # RDS 的私有 IP
    'port': 3306,                 # MySQL 默认端口
    'user': 'flaskdb',            # 用户名
    'password': 'flaskdb@123',    # 密码
    'database': 'flaskdb',        # 数据库名
    'charset': 'utf8mb4'          # 字符集
}

# 测试 MySQL 连接的函数
def test_mysql_connection():
    try:
        # 建立连接
        conn = pymysql.connect(**MYSQL_CONFIG)
        # 创建游标
        cursor = conn.cursor()
        # 执行测试查询
        cursor.execute("SELECT VERSION();")
        version = cursor.fetchone()[0]
        # 关闭连接
        cursor.close()
        conn.close()
        return f"MySQL连接成功!MySQL版本:{version}"
    except OperationalError as e:
        return f"MySQL连接失败!错误信息:{str(e)}"
    except Exception as e:
        return f"未知错误:{str(e)}"

# 根路由:保留 Hello World + 输出 MySQL 连接状态
@app.route('/')
def hello_world():
    mysql_status = test_mysql_connection()
    return f"""
    <h1>Hello, World!</h1>
    <h3>{mysql_status}</h3>
    <p>RDS配置: 主机={MYSQL_CONFIG['host']}, 数据库={MYSQL_CONFIG['database']}</p>
    """

# 启动应用 (监听 80 端口, 允许所有 IP 访问)
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=True)
EOF
创建 RDS
powershell 复制代码
cat > rds.tf << 'EOF'
# RDS MySQL 实例配置 (严格适配 Provider 1.266.0)
resource "alicloud_db_instance" "flask_rds" {
  # 基础配置 (必填)
  engine               = "MySQL"
  engine_version       = "8.0"
  instance_type        = "rds.mysql.t1.small"
  instance_name        = "flask-mysql-db"
  zone_id              = data.alicloud_zones.default.zones.0.id
  vswitch_id           = alicloud_vswitch.vsw.id
  security_group_ids   = [alicloud_security_group.sg.id]

  # 存储配置 (必填)
  instance_storage     = 20

  # 网络配置 (必填)
  vpc_id               = alicloud_vpc.vpc.id
  private_ip_address   = "172.16.1.202"

  # 标签
  tags = {
    Environment = "Practice"
    Region      = "Wulanchabu"
    ManagedBy   = "Terraform"
  }
}

# 单独创建数据库账号
resource "alicloud_db_account" "flask_db_account" {
  db_instance_id   = alicloud_db_instance.flask_rds.id
  account_name     = "flaskdb"
  account_type     = "Normal"
  account_password = "flaskdb@123"
}

# 单独创建 flaskdb 数据库
resource "alicloud_db_database" "flask_db" {
  instance_id     = alicloud_db_instance.flask_rds.id
  name            = "flaskdb" 
  character_set   = "utf8mb4"
}

# 授权账号访问数据库 (适配 1.266.0)
resource "alicloud_db_account_privilege" "flask_privilege" {
  instance_id     = alicloud_db_instance.flask_rds.id
  account_name    = alicloud_db_account.flask_db_account.account_name
  db_names        = [alicloud_db_database.flask_db.name]
  privilege       = "ReadWrite"
}
EOF
完善安全组
powershell 复制代码
cat >> security-group.tf << 'EOF'

# 新增: 开放 3306 端口 (MySQL), 仅允许 VPC 内访问
resource "alicloud_security_group_rule" "sg_ingress_3306" {
  type              = "ingress"
  ip_protocol       = "tcp"
  port_range        = "3306/3306"
  cidr_ip           = "172.16.0.0/16"  # 仅允许 VPC 内 IP 访问 (更安全)
  security_group_id = alicloud_security_group.sg.id
}
EOF
ECS 完善
powershell 复制代码
# 在最后一个 EOF 上方新增 MySQL Python 依赖
vim ecs.tf
...

# 安装 MySQL Python 依赖 (关键)
apt update -y
apt install -y python3-pip python3-flask net-tools
pip3 install pymysql cryptography  # pymysql 是 Python 连接 MySQL 的核心库
EOF
}
部署应用配置
powershell 复制代码
cat > deploy_app.tf << 'EOF'
# 新增: 部署 Flask 应用的 null_resource
resource "null_resource" "deploy_flask" {
  # 触发条件: ECS 实例创建完成 + app.py 文件变更
  triggers = {
    ecs_id      = alicloud_instance.ecs.id
    script_hash = filesha256("app.py")  # 现在 app.py 已存在, 可正常读取
  }

  # 依赖: 等待 ECS 实例创建完成、EIP 绑定完成、数据库已创建
  depends_on = [
    alicloud_instance.ecs,
    alicloud_eip_association.eip_bind,  # 注意这个位置的逗号
    alicloud_db_database.flask_db       # 确保数据库已创建
  ]

  # 第一步: 上传 app.py 到 ECS
  provisioner "file" {
    connection {
      type     = "ssh"
      user     = "root"
      password = var.ecs_password
      host     = alicloud_eip_address.ecs_eip.ip_address
      port     = 22
      timeout  = "5m"  # 增加超时, 避免 ECS SSH 未就绪
    }
    source      = "app.py"               # 本地 app.py 路径 (已创建)
    destination = "/tmp/app.py"          # ECS 目标路径
  }

  # 第二步: 远程执行部署命令
  provisioner "remote-exec" {
    connection {
      type     = "ssh"
      user     = "root"
      password = var.ecs_password
      host     = alicloud_eip_address.ecs_eip.ip_address
      port     = 22
      timeout  = "5m"
    }
    inline = [
      # 更新系统包 (Ubuntu 24.04 默认无 pip)
      "apt update -y",
      # 更改如下三条命令
      "apt install -y python3-pip python3-venv python3-flask",
      "python3 -m venv /opt/flask_venv", 
      "/opt/flask_venv/bin/pip install flask pymysql --upgrade",
      "pkill -f 'python3 /tmp/app.py' || true",
      # 更改下面一条命令: 后台运行 Flask, 日志输出到 /tmp/flask.log
      "nohup /opt/flask_venv/bin/python3 /tmp/app.py > /tmp/flask.log 2>&1 &",
      "sleep 3",  # 等待应用启动
      # 验证 80 端口是否监听
      "ss -ntlp | grep :80 || echo 'Flask 应用启动失败, 请查看 /tmp/flask.log'"
    ]
  }

  # 用 provisioner 的重试逻辑
  provisioner "local-exec" {
    command = "echo 'Flask 部署完成, 访问地址: http://${alicloud_eip_address.ecs_eip.ip_address}'"
  }
}
EOF
定制输出
powershell 复制代码
cat > outputs.tf << 'EOF'
# 输出 ECS 关键信息
output "ecs_instance_name" {
  value = alicloud_instance.ecs.instance_name
  description = "自定义 ECS 实例名称"
}

output "ecs_host_name" {
  value = alicloud_instance.ecs.host_name
  description = "ECS 系统主机名"
}

output "ecs_private_ip" {
  value = alicloud_instance.ecs.private_ip
  description = "定制的静态私有 IP"
}

output "ecs_public_eip" {
  value = alicloud_eip_address.ecs_eip.ip_address
  description = "绑定的静态公网 EIP"
}

# 输出 Flask 应用访问地址
output "flask_app_url" {
  value = format("http://%s", alicloud_eip_address.ecs_eip.ip_address)
  description = "Flask 应用访问地址 (80 端口)"
}

# 新增:输出 RDS MySQL 连接信息
output "rds_mysql_info" {
  value = {
    host     = alicloud_db_instance.flask_rds.private_ip_address
    port     = 3306
    username = "flaskdb"
    password = "flaskdb@123"
    database = "flaskdb"
  }
  description = "RDS MySQL 连接信息 (VPC内访问)"
}
EOF
执行计划
powershell 复制代码
terraform init -reconfigure

terraform plan

terraform apply --auto-approve
测试效果
powershell 复制代码
terraform state list

[root@ubuntu-240 ecs-3 ]#terraform output
ecs_host_name = "ecs-static-ip-host"
ecs_instance_name = "my-custom-ecs"
ecs_private_ip = "172.16.1.100"
ecs_public_eip = "8.130.169.240"
flask_app_url = "http://8.130.169.240"
rds_mysql_info = {
  "database" = "flaskdb"
  "host" = "172.16.1.202"
  "password" = "flaskdb@123"
  "port" = 3306
  "username" = "flaskdb"
}

# 访问公网 IP
[root@ubuntu-240 ecs-3 ]#curl http://8.130.169.240

    <h1>Hello, World!</h1>
    <h3>MySQL连接成功!MySQL版本:8.0.36</h3>
    <p>RDS配置: 主机=172.16.1.202, 数据库=flaskdb</p>
8.1.4.4 增加 SLB
改造思路
powershell 复制代码
私网 CLB 的核心是:
  - 改造 flask 程序: 将 flask 应用所在 ECS 的 ip 地址信息显示出来
  - 创建两个 ECS
    基于现有 alicloud_instance.ecs 配置, 新增第二个 ECS 资源即可
    第一个 ECS ip 设为 172.16.1.100, 第二个 ECS ip 设为 172.16.1.200
  - 创建内网 CLB
    指定 CLB 类型为 intranet (私网), 关联现有 VPC 和 VSwitch
    配置 80 端口监听, 对外和对内端口均设为 80
    启用 TCP/HTTP 健康检查, 检查路径为 / (Flask 根路由)
  - 将两个 ECS 加入 CLB 后端
    基于 CLB 实例创建后端服务器组, 类型为 默认服务器组 或 自定义服务器
  - 调整 EIP 绑定
    解除 EIP 与第一个 ECS 的关联
    将 EIP 重新绑定到私网 CLB
环境准备
powershell 复制代码
cd /data/case && cp -a ecs-3 ecs-4 && cd ecs-4
powershell 复制代码
# 修改测试文件
cat > app.py << 'EOF'
from flask import Flask
import pymysql
from pymysql.err import OperationalError

# 新增: 如下模块
import socket
import fcntl
import struct

# 新增: 获取本地主机 ip 地址
def get_local_ip():
    target_nics = ['eth0', 'ens33']
    for nic in target_nics:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            nic_bytes = nic.encode('utf-8')[:15]
            ifreq = struct.pack('16sH14s', nic_bytes, socket.AF_INET, b'\x00'*14)
            res = fcntl.ioctl(s.fileno(), 0x8915, ifreq)
            ip = socket.inet_ntoa(res[20:24])
            s.close()
            if not ip.startswith('127.'):
                return ip
        except Exception as e:
            continue


# 初始化 Flask 应用
app = Flask(__name__)

# RDS MySQL 连接配置 (和 Terraform 中的 RDS 配置一致)
MYSQL_CONFIG = {
    'host': '172.16.1.202',       # RDS的私有 IP
    'port': 3306,                 # MySQL 默认端口
    'user': 'flaskdb',            # 用户名
    'password': 'flaskdb@123',    # 密码
    'database': 'flaskdb',        # 数据库名
    'charset': 'utf8mb4'          # 字符集
}

# 测试 MySQL 连接的函数
def test_mysql_connection():
    try:
        # 建立连接
        conn = pymysql.connect(**MYSQL_CONFIG)
        # 创建游标
        cursor = conn.cursor()
        # 执行测试查询
        cursor.execute("SELECT VERSION();")
        version = cursor.fetchone()[0]
        # 关闭连接
        cursor.close()
        conn.close()
        return f"MySQL 连接成功!MySQL 版本: {version}"
    except OperationalError as e:
        return f"MySQL 连接失败!错误信息: {str(e)}"
    except Exception as e:
        return f"未知错误: {str(e)}"

# 根路由: 保留 Hello World + 输出 MySQL 连接状态
@app.route('/')
def hello_world():
    mysql_status = test_mysql_connection()
    local_ip = get_local_ip()     # 新增: 本地 ip 获取逻辑
    return f"""
    <h1>Hello, World!</h1>
    <h3>本地ip: {local_ip}</h3>
    <h3>{mysql_status}</h3>
    <p>RDS配置: 主机={MYSQL_CONFIG['host']}, 数据库={MYSQL_CONFIG['database']}</p>
    """

# 启动应用 (监听 80 端口, 允许所有 IP 访问)
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=True)
EOF
调整 ECS 配置
powershell 复制代码
cat > ecs.tf << 'EOF'
# 第一个 ECS 实例
resource "alicloud_instance" "ecs_1" {
  # 自定义 ECS 实例名称、主机名、静态 IP (差异化命名)
  instance_name = "my-custom-ecs-1"
  host_name = "ecs-static-ip-host-1"
  private_ip = "172.16.1.100"

  # 基础标识 (基本不变)
  instance_type = "ecs.e-c1m1.large"
  image_id      = data.alicloud_images.default.images.0.id
  vswitch_id    = alicloud_vswitch.vsw.id
  security_groups = [alicloud_security_group.sg.id]

  # 增加主机密码
  password      = var.ecs_password
  # user_data自动启用密码登录
  user_data = <<-eof
#!/bin/bash
# 启用 SSH 密码登录
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
systemctl restart sshd

# 安装 MySQL Python 依赖 (关键)
apt update -y
apt install -y python3-pip python3-venv python3-flask net-tools
pip3 install pymysql cryptography
# ========== 解码生成 app.py ==========
echo "ZnJvbSBmbGFzayBpbXBvcnQgRmxhc2sKaW1wb3J0IHB5bXlzcWwKZnJvbSBweW15c3FsLmVyciBpbXBvcnQgT3BlcmF0aW9uYWxFcnJvcgoKIyDmlrDlop7vvJrlpoLkuIvmqKHlnZcKaW1wb3J0IHNvY2tldAppbXBvcnQgZmNudGwKaW1wb3J0IHN0cnVjdAoKIyDmlrDlop7vvJrojrflj5bmnKzlnLDkuLvmnLppcOWcsOWdgApkZWYgZ2V0X2xvY2FsX2lwKCk6CiAgICB0YXJnZXRfbmljcyA9IFsnZXRoMCcsICdlbnMzMyddCiAgICBmb3IgbmljIGluIHRhcmdldF9uaWNzOgogICAgICAgIHRyeToKICAgICAgICAgICAgcyA9IHNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQsIHNvY2tldC5TT0NLX0RHUkFNKQogICAgICAgICAgICBuaWNfYnl0ZXMgPSBuaWMuZW5jb2RlKCd1dGYtOCcpWzoxNV0KICAgICAgICAgICAgaWZyZXEgPSBzdHJ1Y3QucGFjaygnMTZzSDE0cycsIG5pY19ieXRlcywgc29ja2V0LkFGX0lORVQsIGInXHgwMCcqMTQpCiAgICAgICAgICAgIHJlcyA9IGZjbnRsLmlvY3RsKHMuZmlsZW5vKCksIDB4ODkxNSwgaWZyZXEpCiAgICAgICAgICAgIGlwID0gc29ja2V0LmluZXRfbnRvYShyZXNbMjA6MjRdKQogICAgICAgICAgICBzLmNsb3NlKCkKICAgICAgICAgICAgaWYgbm90IGlwLnN0YXJ0c3dpdGgoJzEyNy4nKToKICAgICAgICAgICAgICAgIHJldHVybiBpcAogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgY29udGludWUKCgojIOWIneWni+WMlkZsYXNr5bqU55SoCmFwcCA9IEZsYXNrKF9fbmFtZV9fKQoKIyBSRFMgTXlTUUzov57mjqXphY3nva7vvIjlkoxUZXJyYWZvcm3kuK3nmoRSRFPphY3nva7kuIDoh7TvvIkKTVlTUUxfQ09ORklHID0gewogICAgJ2hvc3QnOiAnMTcyLjE2LjEuMjAyJywgICAgICAgIyBSRFPnmoTnp4HmnIlJUAogICAgJ3BvcnQnOiAzMzA2LCAgICAgICAgICAgICAgICAgIyBNeVNRTOm7mOiupOerr+WPowogICAgJ3VzZXInOiAnZmxhc2tkYicsICAgICAgICAgICAgIyDnlKjmiLflkI0KICAgICdwYXNzd29yZCc6ICdmbGFza2RiQDEyMycsICAgICMg5a+G56CBCiAgICAnZGF0YWJhc2UnOiAnZmxhc2tkYicsICAgICAgICAjIOaVsOaNruW6k+WQjQogICAgJ2NoYXJzZXQnOiAndXRmOG1iNCcgICAgICAgICAgIyDlrZfnrKbpm4YKfQoKIyDmtYvor5VNeVNRTOi/nuaOpeeahOWHveaVsApkZWYgdGVzdF9teXNxbF9jb25uZWN0aW9uKCk6CiAgICB0cnk6CiAgICAgICAgIyDlu7rnq4vov57mjqUKICAgICAgICBjb25uID0gcHlteXNxbC5jb25uZWN0KCoqTVlTUUxfQ09ORklHKQogICAgICAgICMg5Yib5bu65ri45qCHCiAgICAgICAgY3Vyc29yID0gY29ubi5jdXJzb3IoKQogICAgICAgICMg5omn6KGM5rWL6K+V5p+l6K+iCiAgICAgICAgY3Vyc29yLmV4ZWN1dGUoIlNFTEVDVCBWRVJTSU9OKCk7IikKICAgICAgICB2ZXJzaW9uID0gY3Vyc29yLmZldGNob25lKClbMF0KICAgICAgICAjIOWFs+mXrei/nuaOpQogICAgICAgIGN1cnNvci5jbG9zZSgpCiAgICAgICAgY29ubi5jbG9zZSgpCiAgICAgICAgcmV0dXJuIGYiTXlTUUzov57mjqXmiJDlip/vvIFNeVNRTOeJiOacrO+8mnt2ZXJzaW9ufSIKICAgIGV4Y2VwdCBPcGVyYXRpb25hbEVycm9yIGFzIGU6CiAgICAgICAgcmV0dXJuIGYiTXlTUUzov57mjqXlpLHotKXvvIHplJnor6/kv6Hmga/vvJp7c3RyKGUpfSIKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICByZXR1cm4gZiLmnKrnn6XplJnor6/vvJp7c3RyKGUpfSIKCiMg5qC56Lev55Sx77ya5L+d55WZSGVsbG8gV29ybGQgKyDovpPlh7pNeVNRTOi/nuaOpeeKtuaAgQpAYXBwLnJvdXRlKCcvJykKZGVmIGhlbGxvX3dvcmxkKCk6CiAgICBteXNxbF9zdGF0dXMgPSB0ZXN0X215c3FsX2Nvbm5lY3Rpb24oKQogICAgbG9jYWxfaXAgPSBnZXRfbG9jYWxfaXAoKSAgICAgIyDmlrDlop7vvJrmnKzlnLBpcOiOt+WPlumAu+i+kQogICAgcmV0dXJuIGYiIiIKICAgIDxoMT5IZWxsbywgV29ybGQhPC9oMT4KICAgIDxoMz7mnKzlnLBpcDoge2xvY2FsX2lwfTwvaDM+CiAgICA8aDM+e215c3FsX3N0YXR1c308L2gzPgogICAgPHA+UkRT6YWN572u77ya5Li75py6PXtNWVNRTF9DT05GSUdbJ2hvc3QnXX3vvIzmlbDmja7lupM9e01ZU1FMX0NPTkZJR1snZGF0YWJhc2UnXX08L3A+CiAgICAiIiIKCiMg5ZCv5Yqo5bqU55So77yI55uR5ZCsODDnq6/lj6PvvIzlhYHorrjmiYDmnIlJUOiuv+mXru+8iQppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgYXBwLnJ1bihob3N0PScwLjAuMC4wJywgcG9ydD04MCwgZGVidWc9VHJ1ZSkK" | base64 -d > /tmp/app.py
python3 -m venv /opt/flask_venv
/opt/flask_venv/bin/pip install flask pymysql --upgrade
pkill -f 'python3 /tmp/app.py' || true
nohup /opt/flask_venv/bin/python3 /tmp/app.py > /tmp/flask.log 2>&1 &
eof

  # 存储配置 (20GB 云盘)
  system_disk_category = "cloud_essd_entry"
  data_disks {
    category = "cloud_essd_entry"
    size     = 20
  }

  # 标签 (便于资源管理, 差异化标识)
  tags = {
    Environment = "Practice"
    Region      = "Wulanchabu"
    ManagedBy   = "Terraform"
    InstanceID  = "ECS-1"
  }
}

# 第二个 ECS 实例
resource "alicloud_instance" "ecs_2" {
  # 自定义 ECS 实例名称、主机名、静态 IP (差异化)
  instance_name = "my-custom-ecs-2"
  host_name = "ecs-static-ip-host-2"
  private_ip = "172.16.1.200"

  # 基础标识 (与第一个 ECS 完全一致)
  instance_type = "ecs.e-c1m1.large"
  image_id      = data.alicloud_images.default.images.0.id
  vswitch_id    = alicloud_vswitch.vsw.id
  security_groups = [alicloud_security_group.sg.id]

  # 主机密码 (复用变量, 保持一致)
  password      = var.ecs_password
  # user_data自动启用密码登录
  user_data = <<-eof
#!/bin/bash
# 启用 SSH 密码登录
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
systemctl restart sshd

# 安装 MySQL Python 依赖
apt update -y
apt install -y python3-pip python3-venv python3-flask net-tools
pip3 install pymysql cryptography
# ========== 解码生成 app.py ==========
echo "ZnJvbSBmbGFzayBpbXBvcnQgRmxhc2sKaW1wb3J0IHB5bXlzcWwKZnJvbSBweW15c3FsLmVyciBpbXBvcnQgT3BlcmF0aW9uYWxFcnJvcgoKIyDmlrDlop7vvJrlpoLkuIvmqKHlnZcKaW1wb3J0IHNvY2tldAppbXBvcnQgZmNudGwKaW1wb3J0IHN0cnVjdAoKIyDmlrDlop7vvJrojrflj5bmnKzlnLDkuLvmnLppcOWcsOWdgApkZWYgZ2V0X2xvY2FsX2lwKCk6CiAgICB0YXJnZXRfbmljcyA9IFsnZXRoMCcsICdlbnMzMyddCiAgICBmb3IgbmljIGluIHRhcmdldF9uaWNzOgogICAgICAgIHRyeToKICAgICAgICAgICAgcyA9IHNvY2tldC5zb2NrZXQoc29ja2V0LkFGX0lORVQsIHNvY2tldC5TT0NLX0RHUkFNKQogICAgICAgICAgICBuaWNfYnl0ZXMgPSBuaWMuZW5jb2RlKCd1dGYtOCcpWzoxNV0KICAgICAgICAgICAgaWZyZXEgPSBzdHJ1Y3QucGFjaygnMTZzSDE0cycsIG5pY19ieXRlcywgc29ja2V0LkFGX0lORVQsIGInXHgwMCcqMTQpCiAgICAgICAgICAgIHJlcyA9IGZjbnRsLmlvY3RsKHMuZmlsZW5vKCksIDB4ODkxNSwgaWZyZXEpCiAgICAgICAgICAgIGlwID0gc29ja2V0LmluZXRfbnRvYShyZXNbMjA6MjRdKQogICAgICAgICAgICBzLmNsb3NlKCkKICAgICAgICAgICAgaWYgbm90IGlwLnN0YXJ0c3dpdGgoJzEyNy4nKToKICAgICAgICAgICAgICAgIHJldHVybiBpcAogICAgICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICAgICAgY29udGludWUKCgojIOWIneWni+WMlkZsYXNr5bqU55SoCmFwcCA9IEZsYXNrKF9fbmFtZV9fKQoKIyBSRFMgTXlTUUzov57mjqXphY3nva7vvIjlkoxUZXJyYWZvcm3kuK3nmoRSRFPphY3nva7kuIDoh7TvvIkKTVlTUUxfQ09ORklHID0gewogICAgJ2hvc3QnOiAnMTcyLjE2LjEuMjAyJywgICAgICAgIyBSRFPnmoTnp4HmnIlJUAogICAgJ3BvcnQnOiAzMzA2LCAgICAgICAgICAgICAgICAgIyBNeVNRTOm7mOiupOerr+WPowogICAgJ3VzZXInOiAnZmxhc2tkYicsICAgICAgICAgICAgIyDnlKjmiLflkI0KICAgICdwYXNzd29yZCc6ICdmbGFza2RiQDEyMycsICAgICMg5a+G56CBCiAgICAnZGF0YWJhc2UnOiAnZmxhc2tkYicsICAgICAgICAjIOaVsOaNruW6k+WQjQogICAgJ2NoYXJzZXQnOiAndXRmOG1iNCcgICAgICAgICAgIyDlrZfnrKbpm4YKfQoKIyDmtYvor5VNeVNRTOi/nuaOpeeahOWHveaVsApkZWYgdGVzdF9teXNxbF9jb25uZWN0aW9uKCk6CiAgICB0cnk6CiAgICAgICAgIyDlu7rnq4vov57mjqUKICAgICAgICBjb25uID0gcHlteXNxbC5jb25uZWN0KCoqTVlTUUxfQ09ORklHKQogICAgICAgICMg5Yib5bu65ri45qCHCiAgICAgICAgY3Vyc29yID0gY29ubi5jdXJzb3IoKQogICAgICAgICMg5omn6KGM5rWL6K+V5p+l6K+iCiAgICAgICAgY3Vyc29yLmV4ZWN1dGUoIlNFTEVDVCBWRVJTSU9OKCk7IikKICAgICAgICB2ZXJzaW9uID0gY3Vyc29yLmZldGNob25lKClbMF0KICAgICAgICAjIOWFs+mXrei/nuaOpQogICAgICAgIGN1cnNvci5jbG9zZSgpCiAgICAgICAgY29ubi5jbG9zZSgpCiAgICAgICAgcmV0dXJuIGYiTXlTUUzov57mjqXmiJDlip/vvIFNeVNRTOeJiOacrO+8mnt2ZXJzaW9ufSIKICAgIGV4Y2VwdCBPcGVyYXRpb25hbEVycm9yIGFzIGU6CiAgICAgICAgcmV0dXJuIGYiTXlTUUzov57mjqXlpLHotKXvvIHplJnor6/kv6Hmga/vvJp7c3RyKGUpfSIKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICByZXR1cm4gZiLmnKrnn6XplJnor6/vvJp7c3RyKGUpfSIKCiMg5qC56Lev55Sx77ya5L+d55WZSGVsbG8gV29ybGQgKyDovpPlh7pNeVNRTOi/nuaOpeeKtuaAgQpAYXBwLnJvdXRlKCcvJykKZGVmIGhlbGxvX3dvcmxkKCk6CiAgICBteXNxbF9zdGF0dXMgPSB0ZXN0X215c3FsX2Nvbm5lY3Rpb24oKQogICAgbG9jYWxfaXAgPSBnZXRfbG9jYWxfaXAoKSAgICAgIyDmlrDlop7vvJrmnKzlnLBpcOiOt+WPlumAu+i+kQogICAgcmV0dXJuIGYiIiIKICAgIDxoMT5IZWxsbywgV29ybGQhPC9oMT4KICAgIDxoMz7mnKzlnLBpcDoge2xvY2FsX2lwfTwvaDM+CiAgICA8aDM+e215c3FsX3N0YXR1c308L2gzPgogICAgPHA+UkRT6YWN572u77ya5Li75py6PXtNWVNRTF9DT05GSUdbJ2hvc3QnXX3vvIzmlbDmja7lupM9e01ZU1FMX0NPTkZJR1snZGF0YWJhc2UnXX08L3A+CiAgICAiIiIKCiMg5ZCv5Yqo5bqU55So77yI55uR5ZCsODDnq6/lj6PvvIzlhYHorrjmiYDmnIlJUOiuv+mXru+8iQppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgYXBwLnJ1bihob3N0PScwLjAuMC4wJywgcG9ydD04MCwgZGVidWc9VHJ1ZSkK" | base64 -d > /tmp/app.py
python3 -m venv /opt/flask_venv
/opt/flask_venv/bin/pip install flask pymysql --upgrade
pkill -f 'python3 /tmp/app.py' || true
nohup /opt/flask_venv/bin/python3 /tmp/app.py > /tmp/flask.log 2>&1 &
eof

  # 存储配置
  system_disk_category = "cloud_essd_entry"
  data_disks {
    category = "cloud_essd_entry"
    size     = 20
  }

  # 标签
  tags = {
    Environment = "Practice"
    Region      = "Wulanchabu"
    ManagedBy   = "Terraform"
    InstanceID  = "ECS-2"
  }
}
EOF
powershell 复制代码
# 因为将 flask 应用部署逻辑内嵌到了 ECS 自动化执行任务中, 所以 deploy_app.tf 文件不再需要
rm deploy_app.tf
创建 CLB
powershell 复制代码
cat > clb.tf << 'EOF'
# 1. 创建内网 CLB 实例 (适配官方 alicloud_slb_load_balancer 资源)
resource "alicloud_slb_load_balancer" "private_clb" {
  load_balancer_name   = "flask-app-private-clb"  # 官方标准参数
  load_balancer_spec   = "slb.s1.small"           # 官方标准参数
  address_type         = "intranet"               # 私网 CLB (公网为 internet)
  address_ip_version   = "ipv4"                   # 官方示例必选
  vswitch_id           = alicloud_vswitch.vsw.id  # 关联现有 VSwitch (自动归属 VPC/可用区)
  instance_charge_type = "PayBySpec"              # 官方示例计费类型 (按需)

  # 标签保持和现有资源一致
  tags = {
    Environment = "Practice"
    Region      = "Wulanchabu"
    ManagedBy   = "Terraform"
  }
}

# 2. 创建 CLB 后端服务器组 (官方标准资源)
resource "alicloud_slb_server_group" "flask_server_group" {
  load_balancer_id = alicloud_slb_load_balancer.private_clb.id
  name             = "flask-app-server-group"  # 服务器组名称
}

# 3. 延迟初始化 (避免服务器组创建未完成就添加 ECS, 官方示例必加)
resource "time_sleep" "clb_sleep" {
  depends_on      = [alicloud_slb_server_group.flask_server_group]
  create_duration = "30s"  # 等待30秒确保服务器组初始化完成
}

# 4. 将第一个 ECS 添加到服务器组 (官方标准关联方式)
resource "alicloud_slb_server_group_server_attachment" "ecs_1_attach" {
  depends_on      = [time_sleep.clb_sleep]
  server_group_id = alicloud_slb_server_group.flask_server_group.id
  server_id       = alicloud_instance.ecs_1.id
  port            = 80       # 关联 ECS 的 80 端口
  weight          = 100      # 权重 100
  type            = "ecs"    # 服务器类型为 ECS
  description     = "ecs-1"  # 描述便于识别
}

# 5. 将第二个 ECS 添加到服务器组
resource "alicloud_slb_server_group_server_attachment" "ecs_2_attach" {
  depends_on      = [time_sleep.clb_sleep]
  server_group_id = alicloud_slb_server_group.flask_server_group.id
  server_id       = alicloud_instance.ecs_2.id
  port            = 80
  weight          = 100
  type            = "ecs"
  description     = "ecs-2"
}

# 6. 配置 CLB 80 端口 HTTP 监听 (含健康检查, 官方标准参数)
resource "alicloud_slb_listener" "clb_http_80" {
  load_balancer_id = alicloud_slb_load_balancer.private_clb.id
  server_group_id  = alicloud_slb_server_group.flask_server_group.id
  frontend_port    = 80       # CLB 对外端口
  backend_port     = 80       # 转发到 ECS 的端口
  protocol         = "http"   # HTTP 协议
  bandwidth        = 10       # 带宽限制 (官方示例默认)
  
  # 健康检查配置 (官方标准参数)
  health_check              = "on"
  health_check_uri          = "/"                 # 检查 Flask 根路由
  health_check_connect_port = 80                  # 检查端口
  healthy_threshold         = 3                   # 健康阈值
  unhealthy_threshold       = 3                   # 不健康阈值
  health_check_timeout      = 5                   # 超时时间
  health_check_interval     = 2                   # 检查间隔
  health_check_http_code    = "http_2xx"          # 健康状态码
  
  # 会话保持 (测试场景关闭)
  sticky_session            = "off"
}
EOF
EIP 改造
powershell 复制代码
cat > eip.tf << 'EOF'
# 创建静态公网 EIP (保留原有配置)
resource "alicloud_eip_address" "ecs_eip" {
  address_name = "ecs-static-eip"
}

# 将 EIP 绑定到新的私网 CLB (适配官方 CLB 资源名)
resource "alicloud_eip_association" "eip_bind" {
  allocation_id  = alicloud_eip_address.ecs_eip.id
  instance_id    = alicloud_slb_load_balancer.private_clb.id  # 关联新的 CLB 资源
  instance_type  = "SlbInstance"  # 必须指定 CLB 类型
}
EOF
定制输出
powershell 复制代码
cat > outputs.tf << 'EOF'
# 原有 ECS 输出调整为适配双 ECS
output "ecs_1_private_ip" {
  value = alicloud_instance.ecs_1.private_ip
  description = "第一个 ECS 的静态私有 IP"
}

output "ecs_2_private_ip" {
  value = alicloud_instance.ecs_2.private_ip
  description = "第二个 ECS 的静态私有 IP"
}

# 新增 CLB 相关输出
output "clb_private_ip" {
  value = alicloud_slb_load_balancer.private_clb.address
  description = "内网 CLB 的私有 IP"
}

output "clb_public_eip" {
  value = alicloud_eip_address.ecs_eip.ip_address
  description = "绑定到 CLB 的公网 EIP"
}

output "clb_app_url" {
  value = format("http://%s", alicloud_eip_address.ecs_eip.ip_address)
  description = "通过 CLB 访问 Flask 应用的地址 (80 端口)"
}

# 输出 RDS MySQL 连接信息
output "rds_mysql_info" {
  value = {
    host     = alicloud_db_instance.flask_rds.private_ip_address
    port     = 3306
    username = "flaskdb"
    password = "flaskdb@123"
    database = "flaskdb"
  }
  description = "RDS MySQL 连接信息 (VPC 内访问)"
}

EOF
执行计划
powershell 复制代码
terraform init -reconfigure

terraform plan

terraform apply --auto-approve
测试效果
powershell 复制代码
terraform state list

[root@ubuntu-240 ecs-4 ]#terraform output
clb_app_url = "http://8.130.169.240"
clb_private_ip = "172.16.1.235"
clb_public_eip = "8.130.169.240"
ecs_1_private_ip = "172.16.1.100"
ecs_2_private_ip = "172.16.1.200"
rds_mysql_info = {
  "database" = "flaskdb"
  "host" = "172.16.1.202"
  "password" = "flaskdb@123"
  "port" = 3306
  "username" = "flaskdb"
}

# 访问公网 IP
[root@ubuntu-240 ecs-4 ]#curl http://8.130.169.240

    <h1>Hello, World!</h1>
    <h3>本地ip: 172.16.1.200</h3>
    <h3>MySQL连接成功!MySQL版本:8.0.36</h3>
    <p>RDS配置:主机=172.16.1.202,数据库=flaskdb</p>

[root@ubuntu-240 ecs-4 ]#curl http://8.130.169.240

    <h1>Hello, World!</h1>
    <h3>本地ip: 172.16.1.100</h3>
    <h3>MySQL连接成功!MySQL版本:8.0.36</h3>
    <p>RDS配置:主机=172.16.1.202,数据库=flaskdb</p>
清理环境
powershell 复制代码
terraform destroy --auto-approve

8.1.5 模块化实践

8.1.5.1 根模块
环境准备
powershell 复制代码
cd /data/case/ && mkdir -p terraform-flask-app/modules && cd /data/case/terraform-flask-app
根模块文件
powershell 复制代码
# 定制供应商信息
cat > providers.tf << 'EOF'
# Terraform 版本约束
terraform {
  required_providers {
    # 阿里云Provider (指定版本, 避免兼容问题)
    alicloud = {
      source  = "aliyun/alicloud"
      version = "~> 1.266.0"
    }
    # time模块 (CLB 延迟初始化用, 提前引入)
    time = {
      source  = "hashicorp/time"
      version = "~> 0.12.0"
    }
  }
  # 版本约束 (避免过低版本 Terraform 不兼容)
  required_version = ">= 1.5.0"
}

# 阿里云 Provider 配置 (地域通过变量传入)
provider "alicloud" {
  region = var.region
}
EOF
powershell 复制代码
# 定义全局变量文件
cat > variables.tf << 'EOF'
# ========== 全局基础配置 ==========
variable "region" {
  type        = string
  default     = "cn-wulanchabu"
  description = "阿里云地域"
}

# ========== 网络模块变量 ==========
variable "vpc_name" {
  type        = string
  default     = "ecs-practice-vpc"
  description = "VPC名称"
}

variable "vpc_cidr" {
  type        = string
  default     = "172.16.0.0/16"
  description = "VPC 网段"
}

variable "vswitch_cidr" {
  type        = string
  default     = "172.16.1.0/24"
  description = "交换机网段"
}

variable "security_group_name" {
  type        = string
  default     = "ecs-practice-sg"
  description = "安全组名称"
}

# ========== ECS 模块变量 ==========
variable "ecs_instance_type" {
  type        = string
  default     = "ecs.e-c1m1.large"
  description = "ECS 实例规格 (需确保地域有该规格)"
}

variable "ecs_password" {
  type        = string
  default     = "Admin@123"
  sensitive   = true  # 敏感参数不显示明文
  description = "ECS root 用户密码 (需符合阿里云密码规则)"
}

variable "ecs_1_private_ip" {
  type        = string
  default     = "172.16.1.100"
  description = "ECS 1 静态私有 IP"
}

variable "ecs_2_private_ip" {
  type        = string
  default     = "172.16.1.200"
  description = "ECS 2 静态私有 IP"
}

# ========== RDS 模块变量 ==========
variable "rds_instance_name" {
  type        = string
  default     = "flask-mysql-db"
  description = "RDS 实例名称"
}

variable "rds_instance_type" {
  type        = string
  default     = "rds.mysql.t1.small"
  description = "RDS 实例规格"
}

variable "rds_storage" {
  type        = number
  default     = 20
  description = "RDS 存储大小 (GB)"
}

variable "rds_private_ip" {
  type        = string
  default     = "172.16.1.202"
  description = "RDS 静态私有 IP"
}

variable "rds_db_name" {
  type        = string
  default     = "flaskdb"
  description = "RDS 数据库名称"
}

variable "rds_db_user" {
  type        = string
  default     = "flaskdb"
  description = "RDS 数据库账号"
}

variable "rds_db_password" {
  type        = string
  default     = "flaskdb@123"
  sensitive   = true
  description = "RDS 数据库密码"
}

# ========== CLB 模块变量 ==========
variable "clb_instance_name" {
  type        = string
  default     = "flask-app-private-clb"
  description = "CLB 实例名称"
}

variable "clb_instance_spec" {
  type        = string
  default     = "slb.s1.small"
  description = "CLB 实例规格"
}
EOF
powershell 复制代码
# 定义变量赋值文件
cat > terraform.tfvars << 'EOF'
# 基础配置 (可根据实际需求修改)
region = "cn-wulanchabu"

# ECS 配置 (密码建议修改为符合阿里云规则的)
ecs_password = "Admin@123"
ecs_1_private_ip = "172.16.1.100"
ecs_2_private_ip = "172.16.1.200"

# RDS 配置
rds_db_password = "flaskdb@123"
rds_private_ip = "172.16.1.202"
EOF
powershell 复制代码
# 定义根模块核心文件
cat > main.tf << 'EOF'
# 根模块: 暂未调用任何子模块 (先验证初始化)
# 后续步骤会逐步添加
module "network" { 
  source               = "./modules/network"
  region               = var.region
  vpc_name             = var.vpc_name
  vpc_cidr             = var.vpc_cidr
  vswitch_cidr         = var.vswitch_cidr
  security_group_name  = var.security_group_name
}
module "rds" { 
  source               = "./modules/rds"
  region               = var.region
  vpc_id               = module.network.vpc_id
  vswitch_id           = module.network.vswitch_id
  security_group_id    = module.network.security_group_id

  rds_instance_name    = var.rds_instance_name
  rds_instance_type    = var.rds_instance_type
  rds_storage          = var.rds_storage
  rds_private_ip       = var.rds_private_ip
  rds_db_user          = var.rds_db_user
  rds_db_password      = var.rds_db_password
  rds_db_name          = var.rds_db_name
}
module "ecs_1" { 
  source            = "./modules/ecs"

  instance_name     = "my-custom-ecs-1"
  host_name         = "ecs-static-ip-host-1"
  private_ip        = var.ecs_1_private_ip
  instance_type     = var.ecs_instance_type
  ecs_password      = var.ecs_password
  vswitch_id        = module.network.vswitch_id
  security_group_id = module.network.security_group_id

  rds_ip    = module.rds.rds_private_ip
  rds_user  = module.rds.rds_db_user
  rds_pass  = module.rds.rds_db_password
  rds_db    = module.rds.rds_db_name
}
module "ecs_2" { 
  source            = "./modules/ecs"

  instance_name     = "my-custom-ecs-2"
  host_name         = "ecs-static-ip-host-2"
  private_ip        = var.ecs_2_private_ip
  instance_type     = var.ecs_instance_type
  ecs_password      = var.ecs_password
  vswitch_id        = module.network.vswitch_id
  security_group_id = module.network.security_group_id

  rds_ip    = module.rds.rds_private_ip
  rds_user  = module.rds.rds_db_user
  rds_pass  = module.rds.rds_db_password
  rds_db    = module.rds.rds_db_name
}
module "clb" { 
  source      = "./modules/clb"
  region      = var.region
  clb_name    = var.clb_instance_name
  clb_spec    = var.clb_instance_spec
  vswitch_id  = module.network.vswitch_id
}
# 挂载 ECS 1 → CLB
resource "alicloud_slb_server_group_server_attachment" "ecs1" {
  depends_on      = [module.clb.wait_ready]
  server_group_id = module.clb.server_group_id
  server_id       = module.ecs_1.instance_id
  port            = 80
  weight          = 100
  type            = "ecs"
}
# 挂载 ECS 2 → CLB
resource "alicloud_slb_server_group_server_attachment" "ecs2" {
  depends_on      = [module.clb.wait_ready]
  server_group_id = module.clb.server_group_id
  server_id       = module.ecs_2.instance_id
  port            = 80
  weight          = 100
  type            = "ecs"
}
EOF
powershell 复制代码
# 定义输出信息文件
cat > outputs.tf << 'EOF'
# ========== 测试用输出 (验证变量) ==========
output "test_region" {
  value       = var.region
  description = "测试: 输出地域变量"
}

output "test_ecs_password_masked" {
  value       = var.ecs_password != "" ? "******" : "未配置"
  description = "测试: 验证 ECS 密码变量 (掩码显示)"
  sensitive   = true  # 标记为敏感输出
}

# ========== 子模块输出骨架 (后续填充) ==========
# 根模块输出: 后续会汇总所有子模块的关键输出
# 网络模块输出
output "vpc_id" {
  value       = module.network.vpc_id
  description = "VPC ID"
}

output "vswitch_id" {
  value       = module.network.vswitch_id
  description = "交换机 ID"
}

# ECS 模块输出
output "ecs_1_private_ip" {
  value       = module.ecs_1.private_ip
  description = "ECS 1 私有 IP"
}

output "ecs_2_private_ip" {
  value       = module.ecs_2.private_ip
  description = "ECS 2 私有 IP"
}

# RDS 模块输出
output "rds_private_ip" {
  value       = module.rds.rds_private_ip
  description = "RDS 私有 IP"
}

# CLB 模块输出
output "clb_public_eip" {
  value       = module.clb.clb_public_ip
  description = "CLB 公网 EIP"
}

# CLB 的对外地址输出
output "clb_app_url" {
  value = "http://${module.clb.clb_public_ip}"
}
EOF
8.1.5.2 网络模块
powershell 复制代码
mkdir -p modules/network && cd modules/network
powershell 复制代码
# 创建主配置文件
cat > main.tf << 'EOF'
# 自动获取可用区
data "alicloud_zones" "default" {}

# VPC (专有网络)
resource "alicloud_vpc" "vpc" {
  vpc_name   = var.vpc_name
  cidr_block = var.vpc_cidr
}

# 交换机 (VSwitch)
resource "alicloud_vswitch" "vsw" {
  vpc_id     = alicloud_vpc.vpc.id
  cidr_block = var.vswitch_cidr
  zone_id    = data.alicloud_zones.default.zones.0.id
}

# 安全组
resource "alicloud_security_group" "sg" {
  security_group_name = var.security_group_name
  vpc_id              = alicloud_vpc.vpc.id
}

# 入站规则: SSH 22
resource "alicloud_security_group_rule" "sg_ingress_22" {
  type              = "ingress"
  ip_protocol       = "tcp"
  port_range        = "22/22"
  cidr_ip           = "0.0.0.0/0"
  security_group_id = alicloud_security_group.sg.id
}

# 入站规则: HTTP 80
resource "alicloud_security_group_rule" "sg_ingress_80" {
  type              = "ingress"
  ip_protocol       = "tcp"
  port_range        = "80/80"
  cidr_ip           = "0.0.0.0/0"
  security_group_id = alicloud_security_group.sg.id
}

# 入站规则: MySQL 3306 (仅 VPC 内)
resource "alicloud_security_group_rule" "sg_ingress_3306" {
  type              = "ingress"
  ip_protocol       = "tcp"
  port_range        = "3306/3306"
  cidr_ip           = var.vpc_cidr
  security_group_id = alicloud_security_group.sg.id
}
EOF
powershell 复制代码
# 创建环境变量文件
cat > variables.tf << 'EOF'
variable "region" {
  type = string
}

variable "vpc_name" {
  type = string
}

variable "vpc_cidr" {
  type = string
}

variable "vswitch_cidr" {
  type = string
}

variable "security_group_name" {
  type = string
}
EOF
powershell 复制代码
# 创建输出信息文件
cat > outputs.tf << 'EOF'
output "vpc_id" {
  value = alicloud_vpc.vpc.id
}

output "vswitch_id" {
  value = alicloud_vswitch.vsw.id
}

output "security_group_id" {
  value = alicloud_security_group.sg.id
}

output "zone_id" {
  value = data.alicloud_zones.default.zones.0.id
}
EOF
8.1.5.3 RDS 模块
powershell 复制代码
cd /data/case/terraform-flask-app && mkdir -p modules/rds && cd modules/rds
powershell 复制代码
# 创建主配置文件
cat > main.tf << 'EOF'
# 获取可用区
data "alicloud_zones" "default" {}

# RDS MySQL 实例
resource "alicloud_db_instance" "flask_rds" {
  engine               = "MySQL"
  engine_version       = "8.0"
  instance_type        = var.rds_instance_type
  instance_name        = var.rds_instance_name
  zone_id              = data.alicloud_zones.default.zones.0.id
  vswitch_id           = var.vswitch_id
  security_group_ids   = [var.security_group_id]
  instance_storage     = var.rds_storage
  vpc_id               = var.vpc_id
  private_ip_address   = var.rds_private_ip

  tags = {
    Environment = "Practice"
    ManagedBy   = "Terraform"
  }
}

# 创建数据库账号
resource "alicloud_db_account" "flask_db_account" {
  db_instance_id   = alicloud_db_instance.flask_rds.id
  account_name     = var.rds_db_user
  account_type     = "Normal"
  account_password = var.rds_db_password
}

# 创建数据库 (新版本的 terrform 不支持 name 属性,使用 data_base_name)
resource "alicloud_db_database" "flask_db" {
  instance_id   = alicloud_db_instance.flask_rds.id
  data_base_name  = var.rds_db_name
  character_set = "utf8mb4"
}

# 授权账号访问数据库
resource "alicloud_db_account_privilege" "flask_privilege" {
  instance_id  = alicloud_db_instance.flask_rds.id
  account_name = alicloud_db_account.flask_db_account.account_name
  db_names     = [alicloud_db_database.flask_db.data_base_name]
  privilege    = "ReadWrite"
}
EOF
powershell 复制代码
# 创建环境变量文件
cat > variables.tf << 'EOF'
variable "region" {
  type = string
}

variable "vpc_id" {
  type = string
}

variable "vswitch_id" {
  type = string
}

variable "security_group_id" {
  type = string
}

variable "rds_instance_name" {
  type = string
}

variable "rds_instance_type" {
  type = string
}

variable "rds_storage" {
  type = number
}

variable "rds_private_ip" {
  type = string
}

variable "rds_db_user" {
  type = string
}

variable "rds_db_password" {
  type = string
}

variable "rds_db_name" {
  type = string
}
EOF
powershell 复制代码
# 创建输出信息文件
cat > outputs.tf << 'EOF'
output "rds_id" {
  value = alicloud_db_instance.flask_rds.id
}

output "rds_private_ip" {
  value = alicloud_db_instance.flask_rds.private_ip_address
}

output "rds_db_user" {
  value = var.rds_db_user
}

output "rds_db_password" {
  value = var.rds_db_password
  sensitive = true
}

output "rds_db_name" {
  value = var.rds_db_name
}
EOF
8.1.5.4 ECS 模块
powershell 复制代码
cd /data/case/terraform-flask-app && mkdir -p modules/ecs && cd modules/ecs
powershell 复制代码
cp /data/case/ecs-4/app.py ./
powershell 复制代码
# 创建主配置文件
cat > main.tf << 'EOF'
# 获取 Ubuntu 24.04 镜像
data "alicloud_images" "default" {
  name_regex  = "^ubuntu_24_04.*"
  most_recent = true
  owners      = "system"
}

locals {
  image_id = data.alicloud_images.default.images != [] ? data.alicloud_images.default.images.0.id : "ubuntu_24_04_x64_20G_alibase_20261016.vhd"
}

# 创建 ECS 实例
resource "alicloud_instance" "single" {
  instance_name   = var.instance_name
  host_name       = var.host_name
  private_ip      = var.private_ip
  instance_type   = var.instance_type
  image_id        = local.image_id
  vswitch_id      = var.vswitch_id
  security_groups = [var.security_group_id]
  password        = var.ecs_password

  # 初始化脚本: 启用 SSH + 安装 Flask + 自动连接 RDS
  user_data = <<-eof
#!/bin/bash
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
systemctl restart ssh

apt update -y
apt install -y python3-pip python3-venv python3-flask net-tools
pip3 install pymysql cryptography
# ========== 解码生成 app.py ==========
cat > /tmp/app.py << 'PYEOF'
from flask import Flask
import pymysql
from pymysql.err import OperationalError

# 新增: 如下模块
import socket
import fcntl
import struct

# 新增: 获取本地主机 ip 地址
def get_local_ip():
    target_nics = ['eth0', 'ens33']
    for nic in target_nics:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            nic_bytes = nic.encode('utf-8')[:15]
            ifreq = struct.pack('16sH14s', nic_bytes, socket.AF_INET, b'\x00'*14)
            res = fcntl.ioctl(s.fileno(), 0x8915, ifreq)
            ip = socket.inet_ntoa(res[20:24])
            s.close()
            if not ip.startswith('127.'):
                return ip
        except Exception as e:
            continue


# 初始化 Flask 应用
app = Flask(__name__)

# RDS MySQL 连接配置 (和 Terraform 中的 RDS 配置一致)
MYSQL_CONFIG = {
    'host': '172.16.1.202',       # RDS的私有 IP
    'port': 3306,                 # MySQL 默认端口
    'user': 'flaskdb',            # 用户名
    'password': 'flaskdb@123',    # 密码
    'database': 'flaskdb',        # 数据库名
    'charset': 'utf8mb4'          # 字符集
}

# 测试 MySQL 连接的函数
def test_mysql_connection():
    try:
        # 建立连接
        conn = pymysql.connect(**MYSQL_CONFIG)
        # 创建游标
        cursor = conn.cursor()
        # 执行测试查询
        cursor.execute("SELECT VERSION();")
        version = cursor.fetchone()[0]
        # 关闭连接
        cursor.close()
        conn.close()
        return f"MySQL 连接成功!MySQL 版本: {version}"
    except OperationalError as e:
        return f"MySQL 连接失败!错误信息: {str(e)}"
    except Exception as e:
        return f"未知错误: {str(e)}"

# 根路由: 保留 Hello World + 输出 MySQL 连接状态
@app.route('/')
def hello_world():
    mysql_status = test_mysql_connection()
    local_ip = get_local_ip()     # 新增: 本地 ip 获取逻辑
    return f"""
    <h1>Hello, World!</h1>
    <h3>本地ip: {local_ip}</h3>
    <h3>{mysql_status}</h3>
    <p>RDS配置: 主机={MYSQL_CONFIG['host']}, 数据库={MYSQL_CONFIG['database']}</p>
    """

# 启动应用 (监听 80 端口, 允许所有 IP 访问)
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80, debug=True)
PYEOF

python3 -m venv /opt/flask_venv
/opt/flask_venv/bin/pip install flask pymysql --upgrade
pkill -f 'python3 /tmp/app.py' || true
nohup /opt/flask_venv/bin/python3 /tmp/app.py > /tmp/flask.log 2>&1 &
eof

  system_disk_category = "cloud_essd_entry"
  data_disks {
    category = "cloud_essd_entry"
    size     = 20
  }

  tags = {
    Environment = "Practice"
    ManagedBy   = "Terraform"
  }
}
EOF
powershell 复制代码
# 创建环境变量文件
cat > variables.tf << 'EOF'
variable "instance_name"     { type = string }
variable "host_name"         { type = string }
variable "private_ip"        { type = string }
variable "instance_type"     { type = string }
variable "ecs_password"      { type = string }
variable "vswitch_id"        { type = string }
variable "security_group_id"  { type = string }
variable "rds_ip"            { type = string }
variable "rds_user"          { type = string }
variable "rds_pass"          { type = string }
variable "rds_db"            { type = string }
EOF
powershell 复制代码
# 创建输出信息文件
cat > outputs.tf << 'EOF'
output "instance_id" {
  value = alicloud_instance.single.id
}

output "private_ip" {
  value = alicloud_instance.single.private_ip
}
EOF
8.1.5.5 CLB 模块
powershell 复制代码
cd /data/case/terraform-flask-app && mkdir -p modules/clb && cd modules/clb
powershell 复制代码
# 创建主配置文件
cat > main.tf << 'EOF'
# 私网 CLB
resource "alicloud_slb_load_balancer" "private_clb" {
  load_balancer_name   = var.clb_name
  load_balancer_spec   = var.clb_spec
  address_type         = "intranet"
  address_ip_version   = "ipv4"
  vswitch_id           = var.vswitch_id
  instance_charge_type = "PayBySpec"

  tags = {
    Environment = "Practice"
    ManagedBy   = "Terraform"
  }
}

# EIP (公网 IP)
resource "alicloud_eip_address" "ecs_eip" {
  address_name = "${var.clb_name}-eip"
}

# 绑定 EIP → CLB
resource "alicloud_eip_association" "eip_bind" {
  allocation_id = alicloud_eip_address.ecs_eip.id
  instance_id   = alicloud_slb_load_balancer.private_clb.id
  instance_type = "SlbInstance"
}

# 后端服务器组
resource "alicloud_slb_server_group" "app_group" {
  load_balancer_id = alicloud_slb_load_balancer.private_clb.id
  name             = "${var.clb_name}-server-group"
}

# 等待 30 秒 (必须)
resource "time_sleep" "wait" {
  depends_on      = [alicloud_slb_server_group.app_group]
  create_duration = "30s"
}

# 监听 80 端口
resource "alicloud_slb_listener" "http_80" {
  load_balancer_id = alicloud_slb_load_balancer.private_clb.id
  server_group_id  = alicloud_slb_server_group.app_group.id
  frontend_port    = 80
  backend_port     = 80
  protocol         = "http"
  bandwidth        = 10

  health_check              = "on"
  health_check_uri          = "/"
  health_check_connect_port = 80
  health_check_http_code    = "http_2xx"
  sticky_session            = "off"
}
EOF
powershell 复制代码
# 创建环境变量文件
cat > variables.tf << 'EOF'
variable "region"        { type = string }
variable "clb_name"      { type = string }
variable "clb_spec"      { type = string }
variable "vswitch_id"    { type = string }
EOF
powershell 复制代码
# 创建输出信息文件
cat > outputs.tf << 'EOF'
output "clb_id" {
  value = alicloud_slb_load_balancer.private_clb.id
}

output "clb_private_ip" {
  value = alicloud_slb_load_balancer.private_clb.address
}

output "clb_public_ip" {
  value = alicloud_eip_address.ecs_eip.ip_address
}

output "server_group_id" {
  value = alicloud_slb_server_group.app_group.id
}

output "wait_ready" {
  value = time_sleep.wait.id
}
EOF
8.1.5.6 执行测试
powershell 复制代码
cd /data/case/terraform-flask-app

# 目录结构
[root@ubuntu-240 terraform-flask-app ]#tree
.
├── main.tf
├── modules
│   ├── clb
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── ecs
│   │   ├── app.py
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── network
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   └── rds
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── outputs.tf
├── providers.tf
├── terraform.tfvars
└── variables.tf
powershell 复制代码
# 执行计划
terraform init

terraform plan

terraform apply -auto-approve
powershell 复制代码
# 测试效果
[root@ubuntu-240 terraform-flask-app ]#terraform output
clb_app_url = "http://8.146.227.102"
clb_public_eip = "8.146.227.102"
ecs_1_private_ip = "172.16.1.100"
ecs_2_private_ip = "172.16.1.200"
rds_private_ip = "172.16.1.202"
test_ecs_password_masked = <sensitive>
test_region = "cn-wulanchabu"
vpc_id = "vpc-0jljb8kl7mmekzt50bn28"
vswitch_id = "vsw-0jl8sffebun6pslusu6a1"

[root@ubuntu-240 terraform-flask-app ]#curl http://8.146.227.102

    <h1>Hello, World!</h1>
    <h3>本地ip: 172.16.1.100</h3>
    <h3>MySQL 连接成功!MySQL 版本: 8.0.36</h3>
    <p>RDS配置: 主机=172.16.1.202, 数据库=flaskdb</p>

[root@ubuntu-240 terraform-flask-app ]#curl http://8.146.227.102

    <h1>Hello, World!</h1>
    <h3>本地ip: 172.16.1.200</h3>
    <h3>MySQL 连接成功!MySQL 版本: 8.0.36</h3>
    <p>RDS配置: 主机=172.16.1.202, 数据库=flaskdb</p>
8.1.5.6 环境清理
powershell 复制代码
terraform destroy -auto-approve

总结SRE可靠性治理和指标体系建设

  • SRE 起源
    • SRE 起源于 Google
    • 2003 年左右由 Google 的工程师 Ben Treynor Sloss 提出了一种全新的思路:用软件工程的方法来解决运维问题
    • 他组建了一支由软件工程师组成的团队来负责系统运维,这支团队就是最早的 SRE 团队
    • 后来,Google 将 SRE 的理念和实践总结成书(《Site Reliability Engineering》),向业界推广,SRE 由此成为现代云原生运维的重要标准。
  • 核心使命
    • SRE 的核心使命是在保障系统高可靠性的同时,维持快速的迭代交付速度
    • 保护与推进(Protect and Progress):在系统的稳定性(可靠性)与功能迭代速度之间找到最佳平衡点,避免为了稳定而停滞不前,也避免为了速度而牺牲稳定性
    • 工程化解决运维问题:通过编写代码、开发自动化工具来替代重复的手工操作,消除"运维工作"(Toil),让系统具备自我修复和自动化扩展的能力
    • 风险量化管理:通过服务等级目标(SLO)和错误预算(Error Budget)来量化系统的可靠性,用数据驱动的方式决定何时发布新功能、何时停止发布去修复稳定性问题
  • DevOps 与 SRE 的关系
    • DevOps 是一场文化运动:强调打破开发与运维之间的墙,让两者协作、共享责任,核心理念是自动化、度量、共享(CAMS),目标是更快交付更稳定
    • SRE是具体实践:由 Google 提出,是 DevOps 文化的一种具体实现方法论------通过工程化手段(代码化、自动化、SLO、错误预算)落地DevOps理念
    • 关系:两者互补而非替代------DevOps 回答"为什么"(文化、协作),SRE 回答"怎么做"(具体工程实践);团队可同时采用DevOps 文化+SRE 实践; SRE 提供了可操作的度量(SLO/错误预算)让"可靠性"可量化
  • 可靠性指标体系
    • SLI(服务等级指标):衡量服务质量的量化指标,如登录接口 P95 延迟、请求成功率、可用性------是 "测量什么"
    • SLO(服务等级目标):为SLI设定的目标值,如 "登录接口 P99 延迟 < 500ms" "API 可用性 > 99.9%"------是 "期望达到什么"
    • SLA(服务等级协议):对用户的正式承诺及违约补偿,如 "月度可用性 < 99.9% 赔偿 10% 月费"------是 "对外承诺什么"
    • 关系:SLI 是基础指标,SLO 基于 SLI 设定内部目标,SLA 基于 SLO 对外承诺且通常更宽松(内部目标高于外部承诺),三者构成服务质量度量体系
    • 示例:SLI = 请求成功率,SLO = 99.9%,SLA = 99.95% 月度可用性(对外承诺,含赔偿条款)

使用 opencode 结合 Ruoyi skill 完成课程实践

RuoYi-Vue 案例

环境准备
powershell 复制代码
# 解压 SKILL 压缩包
[root@ubuntu-240 ~ ]#tar xf ruoyi-deploy.tar.gz

# 为脚本文件赋予权限
[root@ubuntu-240 ~ ]#chmod +x ruoyi-deploy/scripts/*.sh

# 创建项目目录
[root@ubuntu-240 ~ ]#mkdir -p /data/ops/.opencode/skills

# 将 SKILL 文件拷贝到项目目录
[root@ubuntu-240 ~ ]#cp -r ruoyi-deploy /data/ops/.opencode/skills/

# 目录结构
[root@ubuntu-240 ~ ]#tree /data/ops/.opencode/skills/ruoyi-deploy/
/data/ops/.opencode/skills/ruoyi-deploy/
├── assets
│   ├── ruoyi-admin.service.tpl
│   └── ruoyi.conf.tpl
├── references
│   ├── parameters.md
│   ├── rollback.md
│   ├── troubleshoot.md
│   └── verify.md
├── scripts
│   ├── onekey_install_ruoyi_ubuntu24.sh
│   ├── preflight_check.sh
│   ├── run_with_log.sh
│   └── ruoyi_collect_status_check.sh
└── SKILL.md
powershell 复制代码
# 准备自定义命令
mkdir -p /data/ops/.opencode/commands
cat > /data/ops/.opencode/commands/deploy.md << 'EOF'
---
description: 部署若依(调用 ruoyi-deploy skill)
agent: build
---
使用 ruoyi-deploy skill 完成单机部署

要求:
1. 先执行 scripts/preflight_check.sh, 把结果逐项输出
2. 出现「严重」项就停下, 不要继续
3. 我确认后再执行 scripts/run_with_log.sh
4. 结束后按 SKILL.md 的输出格式汇报
补充说明: $ARGUMENTS
EOF
powershell 复制代码
# 项目执行前确认
cd /data/ops && opencode run "读一下 .opencode/skills/ruoyi-deploy/SKILL.md,然后执行 scripts/preflight_check.sh"
使用 SKILL
powershell 复制代码
# 开启会话窗口
opencode

查看 SKILL

查看 SKILL 目录结构

powershell 复制代码
# 使用自定义命令执行部署
/deploy
# 执行完基础检查需要确认继续部署
继续

部署完成浏览器访问验证

故障演练
powershell 复制代码
# 备份相关数据
mysqldump -uroot -p'Root@2026' --single-transaction --all-databases > /root/bak-$(date +%F).sql
tar czf /root/upload-$(date +%F).tar.gz /data/ruoyi/uploadPath
ls -lh /root/bak-*.sql /root/upload-*.tar.gz
powershell 复制代码
# 模拟后端端口被占用
systemctl stop ruoyi-admin
python3 -m http.server 8080 >/dev/null 2>&1 &
powershell 复制代码
# OpenCode 故障分析, 只诊断, 不处理
opencode serve --hostname 0.0.0.0 --port 10020

# 浏览器打开 OpenCode 页面, 发送语句
现象: ruoyi-admin服务没有启动成功, 请按 references/troubleshoot.md 的排查顺序定位, 先只读诊断, 不要修改任何文件; 给出结论和 2 个候选解决方案"
相关推荐
可乐_不渴1 小时前
# C语言文件操作全解析:从 fopen 到 fclose,一文吃透文件 IO
linux·服务器·c语言
草莓熊Lotso1 小时前
【C++ 基于微服务的即时通讯系统】网关基建:cpp-httplib 与 WebSocketpp 从入门到实战
linux·开发语言·数据库·c++·redis·微服务·云原生
李纲明1 小时前
WordPress 媒体库上传失败或一直转圈:先核 PHP 上传限制与目录权限,再查安全插件与对象存储
运维·开发语言·安全·php·wordpress·媒体库·devdiy
志栋智能9 小时前
运维超自动化的版本控制与回滚机制
运维·自动化
中云DDoS CC防护蔡蔡10 小时前
DDOS和CC攻击谁更可怕
运维·服务器·经验分享·网络安全·ddos
Ruiery10 小时前
Linux 6.6内核内存管理深度解析(十六):mmap — 用户态“申请内存“的真相
linux·运维·服务器
ClickHouseDB10 小时前
ClickHouse Cloud 与 Snowflake 实时性价比对比:CostBench 测试中的 412 倍差距来
运维·数据库·系统架构
欧米欧10 小时前
Linux系统篇(七),环境变量的底层溯源,核心获取机制与安全应用
linux·运维·服务器
Ruiery10 小时前
Linux 6.6内核内存管理深度解析(十八):KASLR 内核地址空间随机化
linux·运维·服务器·安全