mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
626 字
2 分钟
Infrastructure as Code 基础设施即代码
2023-09-01

凌晨两点,生产环境的数据库服务器配置被手动修改导致宕机,而没有人能说清楚到底改了什么。如果基础设施的每一项变更都像代码一样有版本记录、可审查、可回滚,这类事故就不会发生。Infrastructure as Code(IaC,基础设施即代码) 正是解决这个问题的方法论。

一、IaC 概述#

1. IaC 核心概念#

graph TB subgraph "IaC 优势" A["版本控制"] --> D["可重复"] B["自动化"] --> D C["一致性"] --> D E["审计追踪"] --> D end
特性说明
声明式定义期望状态
版本控制Git 管理基础设施
自动化减少人工操作
可测试验证基础设施变更

2. 工具对比#

工具类型语言适用场景
Terraform声明式HCL多云资源管理
Pulumi声明式Python/TS开发者友好
Ansible过程式YAML配置管理
CloudFormation声明式JSON/YAMLAWS 专用

二、Terraform 实践#

1. 基础配置#

Terraform 是 HashiCorp 开源的基础设施编排工具,使用 HCL(HashiCorp Configuration Language) 作为配置语言,支持多云资源管理。

main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "tf-state-bucket"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tf-locks"
}
}
provider "aws" {
region = "us-east-1"
}
# 变量定义
variable "environment" {
type = string
default = "production"
}
# 资源定义
resource "aws_instance" "app" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
tags = {
Name = "app-${var.environment}"
Environment = var.environment
}
}

2. 模块化设计#

modules/vpc/main.tf
module "vpc" {
source = "./modules/vpc"
environment = var.environment
cidr_block = var.vpc_cidr
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
single_nat_gateway = false
}
# modules/vpc/variables.tf
variable "environment" {
type = string
}
variable "vpc_cidr" {
type = string
}
variable "private_subnets" {
type = list(string)
}
variable "public_subnets" {
type = list(string)
}

3. 状态管理#

State(状态文件) 是 Terraform 追踪真实基础设施与配置映射关系的核心机制,必须妥善存储和保护。

# 状态锁定
terraform {
backend "s3" {
# DynamoDB 表用于状态锁定
lock_table = "terraform-locks"
}
}
# 导入现有资源
terraform import aws_instance.existing i-1234567890abcdef0
# 查看状态
terraform show
terraform state list
terraform state mv aws_instance.old aws_instance.new

三、Ansible 实践#

Ansible 是 Red Hat 维护的开源自动化工具,采用 Agentless(无代理) 架构,通过 SSH 连接目标主机执行任务。

1. 主机清单#

inventory.ini
[webservers]
web1.example.com ansible_host=10.0.1.1
web2.example.com ansible_host=10.0.1.2
[databases]
db1.example.com ansible_host=10.0.2.1
[production:children]
webservers
databases
[production:vars]
ansible_user=ubuntu
ansible_python_interpreter=/usr/bin/python3

2. Playbook#

Playbook 是 Ansible 的任务编排文件,使用 YAML 格式定义配置、部署和编排的自动化流程。

playbook.yml
- name: Deploy Application
hosts: webservers
become: yes
vars:
app_version: "1.0.0"
app_port: 8080
tasks:
- name: Install dependencies
apt:
name:
- nginx
- python3-pip
state: present
update_cache: yes
- name: Deploy application
git:
repo: "https://github.com/org/app.git"
dest: /opt/app
version: "{{ app_version }}"
force: yes
- name: Configure nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/conf.d/app.conf
notify: Restart nginx
- name: Start application
systemd:
name: app
state: started
enabled: yes
daemon_reload: yes
- name: Wait for application
wait_for:
port: "{{ app_port }}"
delay: 5
timeout: 60
handlers:
- name: Restart nginx
systemd:
name: nginx
state: restarted

3. Roles 结构#

Roles(角色) 是 Ansible 组织 Playbook 的标准方式,将任务、变量、模板和处理器按目录结构分离。

# roles 应用结构
roles/
├── common/
├── tasks/
└── main.yml
├── handlers/
└── main.yml
└── templates/
└── motd.j2
├── nginx/
├── tasks/
└── main.yml
├── handlers/
└── main.yml
└── templates/
└── nginx.conf.j2
└── app/
├── tasks/
└── main.yml
├── templates/
└── app.conf.j2
└── vars/
└── main.yml

四、Pulumi 实践#

Pulumi 是新一代 IaC 工具,允许使用通用编程语言(如 TypeScriptPythonGo)定义基础设施,相比 HCL 更适合开发者。

1. TypeScript 示例#

index.ts
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// 创建 VPC
const vpc = new aws.ec2.Vpc("app-vpc", {
cidrBlock: "10.0.0.0/16",
enableDnsHostnames: true,
enableDnsSupport: true,
tags: {
Name: "app-vpc",
Environment: pulumi.getStack(),
},
});
// 创建子网
const subnet = new aws.ec2.Subnet("app-subnet", {
vpcId: vpc.id,
cidrBlock: "10.0.1.0/24",
availabilityZone: "us-east-1a",
tags: {
Name: "app-subnet",
},
});
// 创建 ECS 集群
const cluster = new aws.ecs.Cluster("app-cluster", {
name: "app-cluster",
settings: [
{
name: "containerInsights",
value: "enabled",
},
],
});
// 导出
export const vpcId = vpc.id;
export const clusterName = cluster.name;
export const subnetId = subnet.id;

2. 跨云部署#

multi-cloud.ts
import * as aws from "@pulumi/aws";
import * as azure from "@pulumi/azure-native";
import * as gcp from "@pulumi/gcp";
// 统一的网络接口
interface NetworkConfig {
vpcCidr: string;
tags: Record<string, string>;
}
// AWS VPC
export function createAwsNetwork(config: NetworkConfig) {
return new aws.ec2.Vpc("vpc", {
cidrBlock: config.vpcCidr,
tags: config.tags,
});
}
// Azure Virtual Network
export function createAzureNetwork(config: NetworkConfig) {
return new azure.network.VirtualNetwork("vnet", {
resourceGroupName: "my-rg",
addressSpace: [config.vpcCidr],
tags: config.tags,
});
}
// GCP Network
export function createGcpNetwork(config: NetworkConfig) {
return new gcp.compute.Network("network", {
autoCreateSubnetworks: false,
routingConfig: {
routingMode: "REGIONAL",
},
});
}

五、CI/CD 集成#

1. Terraform CI/CD#

.github/workflows/terraform.yml
name: Terraform CI/CD
on:
push:
branches: [main]
pull_request:
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.0
- name: Terraform Init
run: terraform init
env:
TF_VAR aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
TF_VAR aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Terraform Format Check
run: terraform fmt -check
- name: Terraform Validate
run: terraform validate
- name: Terraform Plan
run: terraform plan -no-color
env:
TF_VAR aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
TF_VAR aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve
env:
TF_VAR aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
TF_VAR aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

2. Ansible CI/CD#

.github/workflows/ansible.yml
name: Ansible CI/CD
on:
push:
paths:
- "ansible/**"
- "inventory/**"
jobs:
ansible-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ansible-lint
run: pip install ansible-lint
- name: Run ansible-lint
run: ansible-lint
molecule-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Molecule Test
run: |
pip install molecule ansible
molecule test

六、总结#

graph TB A["IaC 工具"] --> B["Terraform"] A --> C["Ansible"] A --> D["Pulumi"] B --> E["声明式 HCL"] C --> F["过程式 YAML"] D --> G["声明式代码"]
工具优势劣势
Terraform多云支持、状态管理HCL 学习曲线
Ansible简单易用、Agentless过程式、难以测试
Pulumi开发者友好、类型安全相对较新

最佳实践:

  • 使用版本控制管理所有配置文件
  • 模块化设计提高复用性
  • 状态文件存储在远程后端
  • 变更前先 plan 后 apply
  • 自动化测试验证配置

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

Infrastructure as Code 基础设施即代码
https://blog.souloss.com/posts/deploy/deploy-infrastructure-as-code/
作者
Souloss
发布于
2023-09-01
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时