认识IaC的第一步

在文章底部的"AWS Console to Code"是一段AWS 控制台(Console)生成的”Console to Code“(C2C)输出。
部分服务会在配置完成之后,提供预览代码这个功能,点击并选择熟悉的语言工具即可下载,本文使用的是python。

C2C文件是通过AWS转换后一个示意代码片段,通常因为其转换后格式和语法的问题不能直接运行。

那么这个C2C文件或者说AWS提供这个功能是为有何作用?

当厌倦了等待界面响应和繁琐的跳转之后,希望通过代码和api来管理控制资源的时候,这个c2c文件才开始具备使用价值。

它帮助解决在刚开始接触就碰上的最头疼的几个问题:

  • 我要操作的API接口是哪个?输入什么参数控制什么属性?
  • 他们的资源依赖关系是如何的?是相对独立,还是存在前提条件?
  • 如何找到一个比较合理,符合直觉的方式,将console操作经验迁移或重现至AWS SDK工作场景中?
  • 最终,一个比较完善的资源集合的代码应该是什么样的?

对此类似上述问题,这种刚刚接触的IaC或者是这种工作模式的新人或者是团队,都能在AWS提供的C2C示例中找到方向或线索。

操作的API对象,关于如何使用SDK的问题

Boto3 SDK → HTTPS请求 → AWS API Gateway → ELB服务 → 资源创建引擎

c2c是没有注释,在第一次没有任何人提示的情况下,很难立刻理解整个示例的逻辑结构,所以在第一次阅读的时候建议结合对应SDK的用户手册,查询对应函数或者是方法名。

例如,在C2C示例中被调用的函数方法ec2_client.create_vpc(),因为重命名的缘故,实际他是 boto3.client('ec2').create_vpc(**kwarys)

boto3是AWS提供的Python SDK模块,上述代码的可以理解成:
调用 boto3 模块,创建一个 EC2 服务的客户端,然后使用该客户端的 create_vpc 方法。

以下是一个简化的代码样例,比较详细的解析以代码注释的方式呈现,协助理解。

# 导入模块
import boto3
# 建立连接器(实例化客户端)
ec2_client = boto3.client('ec2')
# 使用ec2_client实例,通过方法create_vpc创建一个vpc资源
response = ec2_client.create_vpc(**kwarys)    # **kwargs 代表一个解包的参数字典,用于传入多个参数。不理解可以看C2C示例

即便是通过高级语言的python封装,在使用SDK操作AWS云资源的时候,实际上和用户交互的依旧是AWS 的API,只不过AWS的boto3提供了更加方便的模式,让用户利用编程语言更加接近自然的观点去理解和编写IaC。

既然是最终基于API的操作,那么他的工作流定然是遵顼API的基本逻辑:发送请求→平台响应并处理→返回结果
在C2C的例子也有这个逻辑存在:# **kwargs 代表一个解包的参数字典,用于传入多个参数。。

所以,在一个最基本、能够工作的代码块中就有了这三个比较关键部分:

  • Session/Client:,一个会话或连接器,用于和AWS API进行身份验证和通讯
  • Function/Method,具体的操作方法,用于告知AWS需要进行的操作和相关参数。
  • Response, AWS的响应结果,通常是json或者是xml,包含了一些关键信息。

包含了这三项关键内容,就能够达到“通过SDK操作AWS云资源”,这个最基本的目的,即便是现在看来还是不够的。

资源的依赖,迁移控制台经验,构建VPC集合

当已经初步理解,能够编写简单的程序使用SDK调用api的时候,接下来遇到的问题的其中一个就是AWS 资源依赖
这是一个先后问题,我将其归类到资源前提,资源依赖问题。

按照控制台的操作逻辑:VPC→子网→路由表→互联网出口→安全组→……
上述是符合直觉的逻辑,是能够转换到SDK的使用中,只不过在代码中需要显式(主动)管理vpc和内部的组件之间依赖关系
比如:

  • 创建VPC之后响应信息包含了vpc_id。
  • 创建subnet需要传入vpc_id。
  • 创建igw之后,需要vpc_id和igw_id才能完成关联。

一条线性的依赖,从创建vpc开始,到最终完成整体VPC资源的生命周期结束。这条线性依赖在C2C已经逐条列出来了,能够直接被进行参考和使用。

  1. create_vpc()
  2. modify_vpc_attribute()
  3. create_subnets()
  4. create_internet_gateway()
  5. attach_internet_gateway()
  6. create_route_tables()
  7. create_route()
  8. associate_route_table()
  9. create_security_groups()

a VPC's Console to code

首先要知道正确的python的关键字并不使用C2C提供的这种样子,这种是"cidr_blcok": "10.0.0.0/16"是Json的格式。
并且在提供的SDK手册中,熟悉关键字通常都是驼峰命名的既是AWS输出cidr_blcok对应参数名要改写成CidrBlock,boto3是大小写敏感。
正确的书写:

import boto3
ec2_client = boto3.client(‘ec2’)
# 1. 创建 VPC
response_vpc = ec2_client.create_vpc(
    CidrBlock="10.0.0.0/16",
    AmazonProvidedIpv6CidrBlock=False,  # Python 中布尔值为 True/False
    InstanceTenancy="default",
    TagSpecifications=[{
        "ResourceType": "vpc",
        "Tags": [{"Key": "Name", "Value": "webObjcent-vpc"}]
    }]
)

NEW_VPC_ID = response_vpc[‘Vpc’][‘VpcId’]  # 获取新建 VPC 的 ID
# 2. 修改 VPC 属性,启用 DNS 主机名
ec2_client.modify_vpc_attribute(
    VpcId=NEW_VPC_ID,
    EnableDnsHostnames={‘Value’: True}
)

目前来看,这段代码相对来说比较晚上的创建了一个Vpc,足够应付最简单的iac工作要求。
但目前来看这段代码还是会有相当多的不足:

  • 多次的调用了boto3.cliet()
  • 响应的关键属性都需要解析、定义、然后才能够被使用
  • 面向过程,每次构建或者是调整都需要重构部分的参数。
  • 没有日志和错误处理
  • ……

这些不足同样也是优化方向,比如缓存连接器来重复调用boto3.client(),简单的函数化方法的调用,方便后续重复利用等……

不过这些优化将不再这个面向入门级别的文章,兼顾总结性的文章中考虑。
优化代码首先需要熟悉代码和其工作流程,优化代码是一个长期工作。

AWS C2C原输出内容

import boto3
import botocore.exceptions
ec2_client = boto3.client('ec2')
ec2_client.create_vpc(
    "cidr_block": "10.0.0.0/16",
    "amazon_provided_ipv6cidr_block": false,
    "instance_tenancy": "default",
    "tag_specifications": [{"resource_type": "vpc", "tags": [{"key": "Name", "value": "webObjcent-vpc"}]}]
)
NEW_VPC_ID = response['Vpc']['VpcId']

ec2_client.modify_vpc_attribute(
    "vpc_id": "NEW_VPC_ID",
    "enable_dns_hostnames": {"value": true}
)
ec2_client.describe_vpcs(
    "vpc_ids": ["NEW_VPC_ID"]
)
# 创建子网
ec2_client.create_subnet(
    "vpc_id": "NEW_VPC_ID",
    "cidr_block": "10.0.144.0/20",
    "availability_zone": "ap-southeast-1b",
    "ipv6cidr_block": undefined,
    "tag_specifications": [{"resource_type": "subnet", "tags": [{"key": "Name", "value": "webObjcent-subnet-private2-ap-southeast-1b"}]}]
)

ec2_client.create_internet_gateway(
    "tag_specifications": [{"resource_type": "internet-gateway", "tags": [{"key": "Name", "value": "webObjcent-igw"}]}]
)



ec2_client.attach_internet_gateway(
    "internet_gateway_id": "preview-igw-1234",
    "vpc_id": "NEW_VPC_ID"
)
ec2_client.create_route_table(
    "vpc_id": "NEW_VPC_ID",
    "tag_specifications": [{"resource_type": "route-table", "tags": [{"key": "Name", "value": "webObjcent-rtb-private2-ap-southeast-1b"}]}]
)
ec2_client.create_route(
    "route_table_id": "preview-rtb-public-0",
    "destination_cidr_block": "0.0.0.0/0",
    "gateway_id": "preview-igw-1234"
)
ec2_client.associate_route_table(
    "route_table_id": "preview-rtb-private-2",
    "subnet_id": "preview-subnet-private-3"
)
ec2_client.describe_route_tables(
    "route_table_ids": [undefined, undefined, "preview-rtb-private-1", "preview-rtb-private-2"]
)

建设告知

现在网站仍在建设和优化中,正在等待公安信息备案,尚未开始正式使用。
预计于今年年底彻底完成对应建设。


TODO

  • [ ] 挂载ICP备案信息,此处对ICP备案号做简单展示(粤ICP备2025497347号-1
  • [ ] 测试站点MD兼容性
  • [ ] 检查站点数字符号兼容性,目前仍有字号不规则不匹配情况
  • [ ] 文件备份
  • [ ] 优化一下目前的站点外观

COMPLETED

  • 给Nginx加载SSL证书,优化nginx配置项 - 11.27.25