实战基于Gitlab+Jenkins+Terraform的基础设施自动化方案
一 背景
在当今快速发展的云计算时代,企业对基础设施的管理需求越来越复杂,传统的手工管理方式已经无法满足快速迭代、高效运维的需求。为了应对这一挑战,基础设施自动化应运而生,它利用自动化工具将基础设施的配置、部署和管理流程自动化,从而提高效率、降低成本、增强安全性。
1. 传统基础设施管理的痛点
- 效率低下: 手工配置和部署基础设施需要大量时间和人力,无法满足快速迭代的需求。
 - 错误率高: 手工操作容易出现错误,导致系统故障或安全漏洞。
 - 难以维护: 手工管理的配置难以追踪和维护,难以保证一致性。
 - 成本高昂: 人工成本、运维成本、故障修复成本等都比较高。
 
2. 基础设施自动化的优势
- 提高效率: 自动化工具可以快速完成基础设施的配置和部署,大大提高效率。
 - 降低错误率: 自动化工具可以确保配置的准确性和一致性,降低错误率。
 - 增强可维护性: 自动化工具可以记录配置和操作日志,方便追踪和维护。
 - 降低成本: 减少人工成本、运维成本、故障修复成本。
 
3. Jenkins和Terraform的应用场景
- 持续集成和持续交付 (CI/CD): 使用Jenkins构建自动化流程,并使用Terraform管理基础设施,实现快速、可靠的CI/CD流程。
 - 多云管理: 使用Terraform管理不同云平台上的基础设施,实现多云部署和管理。
 - 基础设施即代码 (IaC): 将基础设施配置以代码的形式进行管理,提高可重复性和可控性。
 - 云原生应用开发: 使用Terraform管理云原生应用所需的基础设施,例如容器、Kubernetes集群等。
 
二 相关概念
1. Jenkins
- 持续集成与持续交付 (CI/CD) 平台: Jenkins是一个开源的自动化服务器,提供了一个平台用于构建、测试和部署软件。它可以自动执行构建、测试和部署流程,帮助开发者更快地将代码交付到生产环境。
 - 强大的插件生态系统: Jenkins拥有丰富的插件系统,支持各种语言、工具和云平台,可以满足不同的自动化需求。
 - 灵活的配置: Jenkins提供灵活的配置选项,可以根据不同的需求定制自动化流程。
 
2. Terraform
- 基础设施即代码 (IaC) 工具: Terraform是一个开源的基础设施即代码工具,允许用户使用声明性配置语言定义和管理基础设施资源。
 - 支持多种云平台: Terraform支持多种云平台,包括AWS、Azure、GCP、阿里云等。
 - 强大的资源模型: Terraform提供丰富的资源模型,可以管理各种基础设施资源,例如虚拟机、网络、存储、数据库等
 
三 架构及详解
3.1 架构

3.2 工作流程
代码变更: 开发者将代码推送到代码仓库。
Jenkins 触发: Jenkins 自动检测到代码变更,并触发构建流程。
执行 Terraform: Jenkins 调用 Terraform,执行基础设施的创建或更新操作。
部署应用: Jenkins 部署应用程序到创建好的基础设施环境中。
四 实战
4.1 创建一个Jenkins Job
在Jenkins主页上,单击新建项目按钮。然后为管道命名并选择管道项目类型。

4.2 添加插件和安装软件
- Jenkins中安装Terraform
 
系统工具配置

如果安装失败,可以使用agent或者在jenkins服务器配置terraform命令
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
# 查看制定版本
yum --showduplicates list |grep terraform
# 查看制定版本
repoquery --show-duplicates terraform
# 安装制定版本
terraform install -y terraform-0:1.5.0-1.x86_64
- 添加pollscm插件。
 

4.3 开发代码并上传到Gitlab仓库

Jenkinsfile
pipeline {
    agent any
    parameters {
        choice(name: 'ACTION', choices: ['apply', 'plan','destroy'], description: 'What action should Terraform take?')
    }
    environment {
        TENCENTCLOUD_SECRET_ID = credentials('secret_id')
        TENCENTCLOUD_SECRET_KEY = credentials('secret_key')
    }
    stages {
        stage('apply/destory') {
            steps {
                script {
                        dir('cloud/tencent') {
                            sh 'terraform init'
                            sh 'terraform validate'
                            if (params.ACTION == 'plan') {
                                sh "terraform plan"
                            } else {
                               sh "terraform ${params.ACTION} -auto-approve"
                            }
                        }
                }
            }
        }
    }
}
tf文件核心
variable "region" {
  type    = string
  default = "ap-hongkong"
}
variable "instance_name" {
  type = string
  default = "iac"
}
variable "password" {
  type = string
  default = "Wxxxxxm"
}
variable "os_name" {
  type    = string
  default = "CentOS 7"
}
variable "username" {
  type    = string
  default = "root"
}
locals {
  cidr_block_vpc_name    = "10.0.0.0/16"
  cidr_block_subnet_name = "10.0.1.0/24"
  count                  = 1
  install_v2ray = "install.sh"
  v2ray_port  = 8080
  v2ray_id = "65xxxx076"
  # 密钥管理公钥
  # public_key_content = file("/Users/xuel/.ssh/id_rsa.pub")
  # 私钥
  # privile_key_file = "/Users/xuel/.ssh/id_rsa"
//  public_key_content = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDxxxx"
  tag = {
    name = "xuel"
  }
  username = can(regex("^(?i)ubuntu.*", lower(var.os_name))) ? "ubuntu" : var.username
}
data "template_file" "v2ray" {
  template = file(format("./scripts/%s", local.install_v2ray))
  vars = {
    V2RAY_PORT = local.v2ray_port
    V2RAY_ID = local.v2ray_id
  }
}
data "tencentcloud_images" "image" {
  image_type = ["PUBLIC_IMAGE"]
  os_name    = var.os_name
}
data "tencentcloud_instance_types" "instanceType" {
  cpu_core_count = 8
  memory_size    = 16
  filter {
    name   = "instance-charge-type"
    values = ["POSTPAID_BY_HOUR"]
  }
}
data "tencentcloud_availability_zones_by_product" "zone" {
    product = "cvm"
}
resource "tencentcloud_vpc" "vpc" {
  cidr_block = local.cidr_block_vpc_name
  name       = "xuel_tf_vpc"
  tags = local.tag
}
resource "tencentcloud_subnet" "subnet" {
  availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[0].name
  cidr_block        = local.cidr_block_subnet_name
  name              = "xuel_tf_subnet"
  vpc_id            = tencentcloud_vpc.vpc.id
  tags = local.tag
}
resource "random_string" "random" {
  length  = 4
  special = false
  numeric = true
}
 
# resource "tencentcloud_key_pair" "xuel-tf-key" {
#    key_name   = "xuel_tf_publickey_${random_string.random.result}"
#    public_key = local.public_key_content
# }
resource "tencentcloud_instance" "xuel_tf_ansible" {
  availability_zone = data.tencentcloud_availability_zones_by_product.zone.zones[0].name
  image_id          = data.tencentcloud_images.image.images[0].image_id
  # image_id = "img-mbw2jx7s"
  instance_type     = data.tencentcloud_instance_types.instanceType.instance_types[0].instance_type
  vpc_id            = tencentcloud_vpc.vpc.id
  subnet_id         = tencentcloud_subnet.subnet.id
  //  allocate_public_ip = true
  system_disk_size = 50
  # system_disk_type = "CLOUD_PREMIUM"
  system_disk_type = "CLOUD_BSSD"
  #system_disk_type = "CLOUD_SSD"  
  # key_name         = tencentcloud_key_pair.tf-key.id
  password = var.password
  allocate_public_ip = true
  internet_max_bandwidth_out = 40
  # data_disks {
  #   data_disk_size = 50
  #   data_disk_type = "CLOUD_SSD"
  # }
  hostname             = format("xuel-tf-v2ray-%d", count.index)
  instance_charge_type = "POSTPAID_BY_HOUR"
  count                = local.count
  instance_name        = var.instance_name
  tags = {
    tagkey = "xtf_20240110"
  }
}
resource "null_resource" "shell" {
  count = local.count
  triggers = {
    instance_ids = element(tencentcloud_instance.xuel_tf_ansible.*.id, count.index)
  }
  provisioner "remote-exec" {
    connection {
      host        = element(tencentcloud_instance._tf_ansible.*.public_ip, count.index)
      type        = "ssh"
      user        = local.username
      password = var.password
      timeout = 100000
    }
    inline = [
      // 安装脚本
      data.template_file.v2ray.rendered
    ]
  }
}
output "summary" {
  sensitive = true
  value = {
    //    image = {for k,v in data.tencentcloud_images.image:k=>v}
    //    instanceType = {for k,v in data.tencentcloud_instance_types
    //    .instanceType:k=>v}
    //    zone = {for k,v in data.tencentcloud_availability_zones.zone: k=>v}
    instance = { for k, v in tencentcloud_instance.xuel_tf_ansible : k => v }
  }
}
output "public_ip" {
  value = tencentcloud_instance.xuel_tf_ansible[0].public_ip  
}
output "username" {
  value = local.username
}
# output "instance_type" {
#   value = data.tencentcloud_images.image
# }
output "image_list" {
  value = {for k, v in data.tencentcloud_images.image: k => v}
}
provider "tencentcloud" {
  region = var.region
  # secret_id = var.secret_id
  # secret_key = var.secret_key
}
terraform {
  required_providers {
    tencentcloud = {
      source = "tencentcloudstack/tencentcloud"
      version = "1.79.3"
    }
  }
}
脚本文件
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
                  
yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install docker-ce docker-ce-cli containerd.io -y
sudo systemctl start docker
sudo systemctl enable docker
目录结构

上传到git仓库

4.3 配置作业信息
现在,为这个管道作业填写一些细节。您可以添加Poll SCM来配置Jenkins定期轮询GitHub。该计划遵循cron的语法。例如,如果我们想每两分钟轮询一次,我们将在“管道”下使用:H/2****,从SCM、Git for SCM、我们的存储库URL和主分支中选择管道脚本。
- 添加gitlab凭据,用于jenkins登录gitlab
 

- 配置任务
 

注意gitlab触发的分支,以及Jenkinsfile在项目中的存放路径。
- 创建腾讯秘钥认证信息
 
针对敏感信息需要加密存储。

配置:Dashboard > ⚙ Manage Jenkins > Credentials


- 测试构建
 
由于Jenkinsfile中编写有参数化构建


部署选择apply
已成功安装软件和编排腾讯云


销毁选择destory
由于同一个流水线使用的为Jenkins本地的磁盘, /var/lib/jenkins/workspace/terraform-qcloud/cloud/tencent
同一个流水线不需要其他外部存储或者terraform的backend,存储在本地

五 注意事项
权限管理: 确保 Jenkins 用户具有足够的权限来执行 Terraform 命令。
安全配置: 使用合适的密码和密钥管理策略来保护敏感信息。
版本控制: 将 Terraform 配置文件保存在代码仓库中,并使用版本控制工具进行管理。
测试和验证: 在正式部署之前,要进行充分的测试和验证。
六 参考链接
- 点赞
 - 收藏
 - 关注作者
 
            
           
评论(0)