跳到主要内容

基础设施即代码

基础设施即代码(Infrastructure as Code,IaC)是一种用代码来管理和配置基础设施的实践。通过代码定义基础设施,可以实现自动化部署、版本控制、可重复性和一致性。IaC是云原生和DevOps实践的核心支柱之一。

什么是基础设施即代码?

传统基础设施管理的困境

在传统模式下,基础设施的管理依赖手动操作。运维人员通过控制台点击、命令行输入来创建和配置资源。这种方式存在诸多问题:

不可重复:手动操作难以保证每次都完全相同。今天创建的服务器配置可能和明天的不一样,导致环境差异。

缺乏版本控制:配置变更没有记录,出问题时难以追溯。谁在什么时候做了什么修改?很难说清楚。

协作困难:多人同时管理基础设施时,容易产生冲突和覆盖。缺少协同机制。

文档滞后:文档描述的配置往往与实际不符。文档更新不及时,失去参考价值。

扩展困难:手动创建十台服务器可能还行,创建一千台就力不从心了。

IaC的核心价值

IaC将基础设施的配置用代码来描述,用软件工程的方法来管理基础设施:

可重复性:同样的代码产生同样的基础设施。创建开发、测试、生产环境只需运行相同的代码,确保环境一致性。

版本控制:基础设施代码纳入Git仓库,每一次变更都有记录。可以回滚到任意历史版本,可以创建分支进行实验。

自动化:代码可以自动执行,实现一键部署。与CI/CD流水线集成,实现基础设施的持续交付。

文档即代码:代码本身就是最准确的文档。阅读代码就能了解基础设施的完整状态。

协作友好:使用Git的工作流程,团队成员可以提交变更、进行代码审查、解决冲突。

快速扩展:修改一个数字就能增加十倍资源。代码的复制成本几乎为零。

IaC的两种方法

声明式(Declarative):描述期望的状态,而不是达成状态的步骤。例如,"我需要三个Web服务器",系统会自动创建或删除服务器以达到这个状态。Terraform、Kubernetes采用这种方式。

命令式(Imperative):描述达到目标的步骤。例如,"创建服务器A,然后创建服务器B,然后创建服务器C"。Ansible、传统脚本采用这种方式。

声明式方法通常更适合基础设施管理,因为它更容易理解和维护,也更适合处理状态变化。

Terraform详解

Terraform是HashiCorp公司开源的基础设施即代码工具,是目前最流行的IaC解决方案。它支持几乎所有主流云服务商,采用声明式配置语言HCL(HashiCorp Configuration Language)。

Terraform的核心概念

Provider:云服务提供商的插件,如AWS、Azure、GCP、阿里云等。Terraform通过Provider与云平台API交互。

Resource:基础设施资源,如虚拟机、存储、网络等。每个Resource描述一个具体的基础设施组件。

Data Source:查询已存在的外部资源,用于引用不是由当前Terraform配置管理的资源。

Module:可重用的配置单元,将相关资源组织在一起,便于复用和分享。

State:Terraform维护的状态文件,记录资源与配置的映射关系。状态文件是Terraform的核心,用于追踪实际基础设施。

Plan:执行计划,显示即将进行的变更。在应用变更前,Terraform会生成执行计划供确认。

Apply:应用变更,执行计划中描述的操作。

Terraform工作流程

Terraform的工作流程包含四个主要阶段:

编写(Write):编写HCL配置文件,定义期望的基础设施状态。

计划(Plan):运行terraform plan,Terraform会比较配置文件和实际状态,生成执行计划。这个阶段可以预览即将发生的变更。

应用(Apply):运行terraform apply,执行计划中的操作。Terraform会并行创建独立的资源,按依赖顺序创建有依赖关系的资源。

销毁(Destroy):运行terraform destroy,销毁所有由Terraform管理的资源。这在清理测试环境时很有用。

基础配置示例

# 声明Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}

# 配置远程状态存储
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}

# 配置AWS Provider
provider "aws" {
region = "us-east-1"
}

# 创建VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true

tags = {
Name = "main-vpc"
Environment = "production"
}
}

# 创建子网
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"
}
}

# 创建EC2实例
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]

tags = {
Name = "web-server"
}
}

# 创建安全组
resource "aws_security_group" "web" {
name = "web-security-group"
description = "Allow HTTP traffic"
vpc_id = aws_vpc.main.id

ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

Terraform常用命令

# 初始化工作目录,下载Provider插件
terraform init

# 格式化配置文件
terraform fmt

# 验证配置语法
terraform validate

# 生成执行计划
terraform plan

# 应用变更
terraform apply

# 应用变更(自动确认)
terraform apply -auto-approve

# 销毁所有资源
terraform destroy

# 查看当前状态
terraform show

# 列出所有资源
terraform state list

# 导入已存在的资源到状态
terraform import aws_instance.web i-12345678

# 输出变量值
terraform output

模块化设计

将配置组织成模块是Terraform最佳实践之一。模块可以复用、共享,并使配置结构更清晰。

# 模块目录结构
# modules/
# └── vpc/
# ├── main.tf
# ├── variables.tf
# └── outputs.tf

# modules/vpc/variables.tf
variable "vpc_cidr" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}

variable "environment" {
description = "Environment name"
type = string
}

# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr

tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
}
}

# modules/vpc/outputs.tf
output "vpc_id" {
description = "The ID of the VPC"
value = aws_vpc.main.id
}

# 使用模块
module "production_vpc" {
source = "./modules/vpc"
vpc_cidr = "10.0.0.0/16"
environment = "production"
}

# 引用模块输出
resource "aws_subnet" "main" {
vpc_id = module.production_vpc.vpc_id
# ...
}

状态管理

状态文件是Terraform的核心,正确的状态管理至关重要。

远程状态存储:不要将状态文件存储在本地。使用远程后端如S3、Azure Blob Storage、Terraform Cloud等。这样团队成员可以共享状态,并支持状态锁定防止并发问题。

# 配置S3后端
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks" # 用于状态锁定
}
}

状态隔离:使用工作空间(Workspace)或分离状态文件来隔离不同环境。开发、测试、生产环境应该有独立的状态。

# 创建和切换工作空间
terraform workspace new dev
terraform workspace new prod
terraform workspace select dev

# 列出所有工作空间
terraform workspace list

变量与输出

变量使配置更灵活,输出便于获取资源信息。

# variables.tf
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}

variable "environment" {
description = "Environment name"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}

variable "tags" {
description = "Tags to apply to resources"
type = map(string)
default = {}
}

# 使用变量
resource "aws_instance" "web" {
instance_type = var.instance_type

tags = merge(var.tags, {
Environment = var.environment
})
}

# outputs.tf
output "instance_ip" {
description = "Public IP of the web server"
value = aws_instance.web.public_ip
}

output "instance_id" {
description = "ID of the web server"
value = aws_instance.web.id
}

敏感数据处理

不要在配置文件中硬编码敏感信息。使用变量和环境变量,或集成密钥管理服务。

# 使用环境变量
# export TF_VAR_db_password="secret123"

variable "db_password" {
description = "Database password"
type = string
sensitive = true # 标记为敏感,不会在日志中显示
}

# 从AWS Secrets Manager获取
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "my-db-password"
}

resource "aws_db_instance" "main" {
# ...
password = data.aws_secretsmanager_secret_version.db_password.secret_string
}

其他IaC工具

Ansible

Ansible是一款配置管理工具,采用命令式方法,使用YAML格式编写Playbook。它不需要在目标主机安装Agent,通过SSH连接执行任务。

# Ansible Playbook示例
- name: Configure web server
hosts: webservers
become: yes

tasks:
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: yes

- name: Start Nginx
service:
name: nginx
state: started
enabled: yes

- name: Copy configuration file
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart Nginx

handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted

Ansible适合配置管理和应用部署,与Terraform配合使用:Terraform创建基础设施,Ansible配置服务器。

Pulumi

Pulumi允许使用通用编程语言(TypeScript、Python、Go、C#)来定义基础设施。对于开发人员来说,使用熟悉的语言可能更舒适。

# Pulumi Python示例
import pulumi
import pulumi_aws as aws

# 创建VPC
vpc = aws.ec2.Vpc("main",
cidr_block="10.0.0.0/16",
tags={
"Name": "main-vpc",
})

# 创建子网
subnet = aws.ec2.Subnet("public",
vpc_id=vpc.id,
cidr_block="10.0.1.0/24",
tags={
"Name": "public-subnet",
})

# 输出
pulumi.export("vpc_id", vpc.id)
pulumi.export("subnet_id", subnet.id)

AWS CloudFormation

AWS原生的IaC服务,使用YAML或JSON定义资源。与AWS服务深度集成,但只支持AWS平台。

# CloudFormation模板示例
AWSTemplateFormatVersion: '2010-09-09'
Description: Web Server Stack

Parameters:
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small

Resources:
WebServer:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0c55b159cbfafe1f0
InstanceType: !Ref InstanceType
Tags:
- Key: Name
Value: WebServer

Outputs:
InstanceId:
Description: Instance ID
Value: !Ref WebServer

工具选择建议

工具语言适用场景特点
TerraformHCL多云基础设施社区活跃,Provider丰富
AnsibleYAML配置管理、应用部署无Agent,简单易学
Pulumi通用语言开发者友好类型安全,IDE支持好
CloudFormationYAML/JSONAWS专属AWS原生,免费使用

IaC最佳实践

代码组织

目录结构:按环境或服务组织代码,保持结构清晰。

infrastructure/
├── modules/
│ ├── vpc/
│ ├── ec2/
│ └── rds/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ └── prod/
└── shared/
└── remote-state/

命名规范:使用一致的命名规范,便于理解和管理。

# 好的命名
resource "aws_instance" "web_server" { }
resource "aws_security_group" "web_server_http" { }

# 不好的命名
resource "aws_instance" "i1" { }
resource "aws_security_group" "sg1" { }

版本控制

锁定Provider版本:避免Provider更新导致的意外变更。

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.0.0" # 锁定具体版本
}
}
}

使用Git分支策略:生产环境的变更通过Pull Request审核,确保变更经过充分审查。

测试

静态分析:使用terraform validate检查语法错误。

安全扫描:使用tfsec、Checkov等工具扫描安全问题。

# 使用tfsec扫描
tfsec .

# 使用Checkov扫描
checkov -d .

集成测试:使用Terratest等框架进行端到端测试。

// Terratest示例
func TestVPCModule(t *testing.T) {
t.Parallel()

terraformOptions := &terraform.Options{
TerraformDir: "../modules/vpc",
Vars: map[string]interface{}{
"vpc_cidr": "10.0.0.0/16",
"environment": "test",
},
}

defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)

vpcId := terraform.Output(t, terraformOptions, "vpc_id")
assert.NotEmpty(t, vpcId)
}

CI/CD集成

将IaC集成到CI/CD流水线中,实现基础设施的自动化管理。

# GitHub Actions示例
name: Terraform

on:
push:
branches: [main]
pull_request:

jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Terraform
uses: hashicorp/setup-terraform@v2

- name: Terraform Init
run: terraform init

- name: Terraform Format
run: terraform fmt -check

- name: Terraform Validate
run: terraform validate

- name: Terraform Plan
run: terraform plan
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: terraform apply -auto-approve
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

文档

使用注释和README文档解释配置的目的和使用方法。

/*
* VPC Module
*
* This module creates a VPC with public and private subnets.
*
* Usage:
* module "vpc" {
* source = "./modules/vpc"
* vpc_cidr = "10.0.0.0/16"
* environment = "production"
* }
*/

# 创建VPC
# 使用10.0.0.0/16网段,支持约65000个IP地址
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr

# 启用DNS支持,允许实例使用DNS主机名
enable_dns_support = true

tags = {
Name = "${var.environment}-vpc"
}
}

IaC的挑战与解决方案

状态漂移

状态漂移是指实际基础设施与状态文件不一致的情况。可能由于手动修改、其他工具变更等原因导致。

解决方案

  • 定期运行terraform plan检查漂移
  • 禁止手动修改IaC管理的资源
  • 使用terraform refresh更新状态

秘密管理

配置文件中可能包含密码、密钥等敏感信息,存在泄露风险。

解决方案

  • 使用变量和环境变量传递敏感信息
  • 集成密钥管理服务(AWS Secrets Manager、Vault)
  • 标记变量为sensitive防止日志泄露
  • 在Git中忽略包含敏感信息的文件

团队协作

多人同时修改基础设施可能导致冲突。

解决方案

  • 使用远程状态存储和状态锁定
  • 采用Pull Request工作流
  • 划分不同的状态文件减少冲突范围
  • 制定变更审核流程

小结

基础设施即代码是云原生实践的核心能力。通过代码管理基础设施,我们可以:

  • 实现基础设施的版本控制和审计
  • 保证环境的一致性和可重复性
  • 提高部署效率,减少人为错误
  • 促进团队协作和知识共享

Terraform是目前最流行的IaC工具,掌握其核心概念和最佳实践对于云基础设施管理至关重要。记住,IaC不仅仅是技术实践,更是一种思维方式:像管理代码一样管理基础设施。

下一章我们将探讨无服务器计算,了解如何进一步简化基础设施管理。