自动化运维工具Terraform和Ansible的区别

描述

引言

在现代云原生时代,基础设施即代码(Infrastructure as Code,IaC)已成为运维工程师的核心技能。面对复杂的多云环境和日益增长的基础设施需求,传统的手动配置方式已无法满足快速、可靠、可重复的部署要求。本文将深入探讨 Terraform 和 Ansible 这两大运维利器的核心差异,明确它们在配置管理和资源编排领域的分工边界,为运维工程师提供清晰的技术选型指导。

Terraform 基础介绍

Terraform 是 HashiCorp 公司开发的一款开源基础设施即代码工具,采用声明式语法,通过 HCL(HashiCorp Configuration Language)语言描述基础设施资源。它的核心优势在于跨云平台的资源编排能力,支持 AWS、Azure、Google Cloud、阿里云等主流云服务商。

Terraform 的核心特性

1. 声明式语法
Terraform 使用声明式语法,用户只需描述最终状态,而非实现过程。这种方式使得基础设施配置更加直观和易于维护。

2. 状态管理
Terraform 通过状态文件(terraform.tfstate)追踪基础设施资源的当前状态,确保实际环境与配置文件的一致性。

3. 计划与应用
在实际部署前,Terraform 会生成执行计划,展示将要进行的变更,提供了安全的变更预览机制。

Ansible 与 Terraform 的分工边界

技术定位差异

Terraform:资源编排专家

• 专注于基础设施资源的创建、修改和删除

• 管理云服务商的各种资源:虚拟机、网络、存储、数据库等

• 维护资源间的依赖关系和生命周期

Ansible:配置管理专家

• 专注于服务器内部的配置管理

• 软件安装、配置文件管理、服务启动等

• 应用程序部署和运行时配置

工作流程对比

典型的云基础设施部署流程中,两者的协作模式如下:

1. Terraform 阶段:创建云资源(VPC、子网、安全组、EC2实例等)

2. Ansible 阶段:配置服务器(安装软件、部署应用、配置服务等)

配置管理 vs 资源编排

资源编排(Infrastructure Orchestration)

资源编排关注的是基础设施资源的生命周期管理,包括:

• 资源创建的顺序和依赖关系

• 资源属性的定义和修改

• 资源的销毁和回收

• 跨云平台的资源统一管理

配置管理(Configuration Management)

配置管理专注于系统内部的状态管理,包括:

• 操作系统级别的配置

• 应用程序的安装和配置

• 服务的启动和运行状态管理

• 配置文件的模板化和动态生成

实际应用案例

案例一:使用 Terraform 创建 AWS 基础设施

 

# main.tf - AWS 基础设施资源编排
# 定义 Terraform 提供商和版本要求
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

# 配置 AWS 提供商
provider "aws" {
  region = var.aws_region
}

# 定义变量
variable "aws_region" {
  description = "AWS 部署区域"
  type        = string
  default     = "us-west-2"
}

variable "environment" {
  description = "环境标识"
  type        = string
  default     = "production"
}

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

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

# 创建公共子网
resource "aws_subnet" "public" {
  count             = 2
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.${count.index + 1}.0/24"
  availability_zone = data.aws_availability_zones.available.names[count.index]
  
  # 公共子网自动分配公网IP
  map_public_ip_on_launch = true

  tags = {
    Name = "${var.environment}-public-subnet-${count.index + 1}"
    Type = "public"
  }
}

# 创建私有子网
resource "aws_subnet" "private" {
  count             = 2
  vpc_id            = aws_vpc.main.id
  cidr_block        = "10.0.${count.index + 10}.0/24"
  availability_zone = data.aws_availability_zones.available.names[count.index]

  tags = {
    Name = "${var.environment}-private-subnet-${count.index + 1}"
    Type = "private"
  }
}

# 获取可用区信息
data "aws_availability_zones" "available" {
  state = "available"
}

# 创建互联网网关
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

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

# 创建路由表
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

  tags = {
    Name = "${var.environment}-public-rt"
  }
}

# 关联公共子网到路由表
resource "aws_route_table_association" "public" {
  count          = length(aws_subnet.public)
  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}

# 创建安全组
resource "aws_security_group" "web" {
  name        = "${var.environment}-web-sg"
  description = "Web 服务器安全组"
  vpc_id      = aws_vpc.main.id

  # 允许 HTTP 入站流量
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 允许 HTTPS 入站流量
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # 允许 SSH 入站流量
  ingress {
    from_port   = 22
    to_port     = 22
    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"]
  }

  tags = {
    Name = "${var.environment}-web-sg"
  }
}

# 创建密钥对
resource "aws_key_pair" "main" {
  key_name   = "${var.environment}-key"
  public_key = file("~/.ssh/id_rsa.pub")
}

# 创建 EC2 实例
resource "aws_instance" "web" {
  count                  = 2
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = "t3.micro"
  key_name              = aws_key_pair.main.key_name
  vpc_security_group_ids = [aws_security_group.web.id]
  subnet_id             = aws_subnet.public[count.index].id

  # 实例启动时执行的脚本
  user_data = <<-EOF
    #!/bin/bash
    apt-get update
    apt-get install -y python3 python3-pip
    pip3 install ansible
  EOF

  tags = {
    Name = "${var.environment}-web-${count.index + 1}"
    Role = "web-server"
  }
}

# 获取 Ubuntu AMI 信息
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"] # Canonical

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

# 输出关键信息
output "vpc_id" {
  description = "VPC ID"
  value       = aws_vpc.main.id
}

output "public_subnet_ids" {
  description = "公共子网 ID 列表"
  value       = aws_subnet.public[*].id
}

output "web_server_ips" {
  description = "Web 服务器公网 IP"
  value       = aws_instance.web[*].public_ip
}

 

案例二:使用 Ansible 进行服务器配置管理

 

# nginx-playbook.yml - Nginx 配置管理
---
- name: 配置 Nginx Web 服务器
  hosts: web_servers
  become: yes
  gather_facts: yes

  vars:
    nginx_user: "www-data"
    nginx_worker_processes: "auto"
    nginx_worker_connections: 1024
    nginx_keepalive_timeout: 65
    nginx_server_name: "{{ ansible_default_ipv4.address }}"
    
  tasks:
    # 更新软件包缓存
    - name: 更新 apt 软件包缓存
      apt:
        update_cache: yes
        cache_valid_time: 3600
      tags: [packages]

    # 安装 Nginx
    - name: 安装 Nginx
      apt:
        name: nginx
        state: present
      notify: restart nginx
      tags: [packages]

    # 创建网站目录
    - name: 创建网站根目录
      file:
        path: /var/www/html
        state: directory
        owner: "{{ nginx_user }}"
        group: "{{ nginx_user }}"
        mode: '0755'
      tags: [directories]

    # 配置 Nginx 主配置文件
    - name: 配置 Nginx 主配置文件
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: '0644'
        backup: yes
      notify: reload nginx
      tags: [config]

    # 配置虚拟主机
    - name: 配置默认虚拟主机
      template:
        src: default.conf.j2
        dest: /etc/nginx/sites-available/default
        owner: root
        group: root
        mode: '0644'
        backup: yes
      notify: reload nginx
      tags: [config]

    # 创建自定义网页
    - name: 创建自定义首页
      template:
        src: index.html.j2
        dest: /var/www/html/index.html
        owner: "{{ nginx_user }}"
        group: "{{ nginx_user }}"
        mode: '0644'
      tags: [content]

    # 启动并启用 Nginx 服务
    - name: 启动并启用 Nginx 服务
      systemd:
        name: nginx
        state: started
        enabled: yes
      tags: [service]

    # 配置防火墙规则
    - name: 配置 UFW 防火墙规则
      ufw:
        rule: allow
        port: "{{ item }}"
        proto: tcp
      loop:
        - '80'
        - '443'
      tags: [firewall]

    # 安装 SSL 证书工具
    - name: 安装 Certbot
      apt:
        name: 
          - certbot
          - python3-certbot-nginx
        state: present
      tags: [ssl]

  handlers:
    # 重启 Nginx 服务
    - name: restart nginx
      systemd:
        name: nginx
        state: restarted

    # 重新加载 Nginx 配置
    - name: reload nginx
      systemd:
        name: nginx
        state: reloaded
{# templates/nginx.conf.j2 - Nginx 主配置模板 #}
# Nginx 主配置文件
# 由 Ansible 自动生成,请勿手动修改

user {{ nginx_user }};
worker_processes {{ nginx_worker_processes }};
pid /run/nginx.pid;

events {
    worker_connections {{ nginx_worker_connections }};
    use epoll;
    multi_accept on;
}

http {
    # 基础设置
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout {{ nginx_keepalive_timeout }};
    types_hash_max_size 2048;
    server_tokens off;

    # MIME 类型
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    # 访问日志
    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;

    # 包含虚拟主机配置
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

 

案例三:集成 Terraform 和 Ansible 的自动化部署

 

# inventory/hosts.yml - 动态主机清单
---
all:
  children:
    web_servers:
      hosts:
        # 这些IP将从 Terraform 输出中动态获取
        web-1:
          ansible_host: "{{ terraform_outputs.web_server_ips[0] }}"
        web-2:
          ansible_host: "{{ terraform_outputs.web_server_ips[1] }}"
      vars:
        ansible_user: ubuntu
        ansible_ssh_private_key_file: ~/.ssh/id_rsa
        ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
#!/bin/bash
# deploy.sh - 完整部署脚本
# 集成 Terraform 和 Ansible 的自动化部署流程

set -e

# 颜色定义
RED='�33[0;31m'
GREEN='�33[0;32m'
YELLOW='�33[1;33m'
NC='�33[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 检查依赖工具
check_dependencies() {
    log_info "检查依赖工具..."
    
    if ! command -v terraform &> /dev/null; then
        log_error "Terraform 未安装"
        exit 1
    fi
    
    if ! command -v ansible &> /dev/null; then
        log_error "Ansible 未安装"
        exit 1
    fi
    
    log_info "依赖工具检查完成"
}

# Terraform 部署
terraform_deploy() {
    log_info "开始 Terraform 基础设施部署..."
    
    # 初始化 Terraform
    terraform init
    
    # 生成执行计划
    terraform plan -out=tfplan
    
    # 应用配置
    terraform apply tfplan
    
    # 获取输出信息
    terraform output -json > terraform_outputs.json
    
    log_info "Terraform 部署完成"
}

# 等待实例就绪
wait_for_instances() {
    log_info "等待 EC2 实例就绪..."
    
    # 从 Terraform 输出获取 IP 地址
    IPS=$(terraform output -json | jq -r '.web_server_ips.value[]')
    
    for ip in $IPS; do
        log_info "等待 $ip 就绪..."
        while ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no ubuntu@$ip 'echo "ready"' &>/dev/null; do
            log_warn "等待 $ip 响应..."
            sleep 10
        done
        log_info "$ip 已就绪"
    done
}

# Ansible 配置
ansible_configure() {
    log_info "开始 Ansible 配置管理..."
    
    # 生成动态主机清单
    python3 generate_inventory.py
    
    # 测试连接
    ansible all -i inventory/hosts.yml -m ping
    
    # 执行配置
    ansible-playbook -i inventory/hosts.yml nginx-playbook.yml
    
    log_info "Ansible 配置完成"
}

# 验证部署
verify_deployment() {
    log_info "验证部署结果..."
    
    IPS=$(terraform output -json | jq -r '.web_server_ips.value[]')
    
    for ip in $IPS; do
        log_info "测试 $ip 的 Web 服务..."
        if curl -s -o /dev/null -w "%{http_code}" http://$ip | grep -q "200"; then
            log_info "$ip Web 服务正常"
        else
            log_error "$ip Web 服务异常"
        fi
    done
}

# 主函数
main() {
    log_info "开始自动化部署流程..."
    
    check_dependencies
    terraform_deploy
    wait_for_instances
    ansible_configure
    verify_deployment
    
    log_info "部署完成!"
    log_info "访问地址:"
    terraform output web_server_ips
}

# 清理资源
cleanup() {
    log_warn "清理 Terraform 资源..."
    terraform destroy -auto-approve
    rm -f terraform_outputs.json
    rm -f tfplan
    log_info "资源清理完成"
}

# 参数处理
case "${1:-deploy}" in
    "deploy")
        main
        ;;
    "cleanup")
        cleanup
        ;;
    *)
        echo "使用方法: $0 [deploy|cleanup]"
        exit 1
        ;;
esac

 

最佳实践与建议

1. 技术选型原则

使用 Terraform 的场景:

• 需要创建和管理云资源

• 跨云平台的资源编排

• 基础设施版本控制和协作

• 资源依赖关系复杂的场景

使用 Ansible 的场景:

• 服务器配置管理

• 应用程序部署

• 运行时配置更新

• 批量运维操作

2. 协作模式

串行协作模式:先用 Terraform 创建基础设施,再用 Ansible 配置服务器。这是最常见的模式,适用于大多数场景。

并行协作模式:在某些场景下,可以同时使用两个工具管理不同层面的资源,但需要做好状态同步。

3. 状态管理

Terraform 状态管理

• 使用远程状态存储(如 S3、Azure Blob)

• 启用状态锁定机制

• 定期备份状态文件

Ansible 状态管理

• 使用幂等性任务设计

• 合理使用 handlers 和 tags

• 建立回滚机制

4. 安全考虑

凭证管理

• 使用 IAM 角色而非硬编码密钥

• 利用 HashiCorp Vault 或 AWS Secrets Manager

• 实施最小权限原则

网络安全

• 合理配置安全组规则

• 使用 VPN 或堡垒机访问内网资源

• 启用日志审计

总结

Terraform 和 Ansible 在现代运维体系中扮演着不同但互补的角色。Terraform 专注于基础设施资源的声明式编排,提供了强大的跨云平台能力和状态管理机制;Ansible 则专注于配置管理和应用部署,提供了灵活的任务执行和丰富的模块生态。

理解两者的分工边界,合理地将资源编排和配置管理分离,能够构建更加健壮、可维护的基础设施自动化体系。在实际应用中,建议采用 Terraform 负责基础设施层面的资源管理,Ansible 负责应用层面的配置管理,通过标准化的接口和流程实现两者的无缝协作。

随着云原生技术的发展,运维工程师需要不断学习和实践这些工具,构建适合自己组织需求的自动化运维体系。通过合理的技术选型和最佳实践,能够显著提升运维效率,降低运维风险,为业务发展提供坚实的基础设施保障。

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分