将 terraform 上的 jenkins 与 bitbucket 集成

ani*_*ita 3 bitbucket amazon-web-services jenkins terraform terraform-provider-aws

我已经为 aws 架构创建了 terraform 脚本,其中包括 ec2 实例和 ec2 上的 jenkins。我是 jenkins 的新手,并试图弄清楚如何使用现有的 terraform 脚本将它与 bitbucket 集成。任何帮助将不胜感激。

小智 5

使用 terraform 将更改应用于基础设施的 CI/CD 管道工作流:

  1. 开发人员或运维工程师更改其本地机器中的 terraform 配置文件并将代码提交到 BitBucket。
  2. Gitbucket webhook 向 jenkins 触发持续集成作业。
  3. Jenkins 将从包含 terraform 文件的配置存储库中提取最新代码到其工作区。
  4. 它读取 terraform 配置,然后初始化远程 consul 后端。
  5. Terraform 生成有关必须应用于基础架构的更改的计划
  6. Jenkins 将有关更改的通知发送到松弛通道以供手动批准。
  7. 在这里,用户可以批准或不批准地形计划。
  8. 用户输入被发送到 jenkins 服务器以进行进一步的操作。
  9. 一旦操作员批准更改,jenkins 将执行 terraform apply 命令以反映对基础架构的更改。
  10. Terraform 将创建关于执行计划时创建的资源及其依赖项的报告。
  11. Terraform 将在提供者环境中供应资源。
  12. 在应用更改后,Jenkins 将再次向 slack 通道发送有关基础设施状态的通知。作业执行后,Jenkins 管道作业被配置为清理作业创建的工作区。

如何设置部署环境?

  1. 在 gitlab 或 bitbucket 等 scm 工具中创建一个 repo,并将 terraform 配置及其依赖模块提交到 repo。如果您使用任何第三方远程模块作为依赖项,它将在执行时自动下载。
  2. 如果你没有 Jenkins 服务器,那么只需拉一个 jenkins docker 镜像并在你的本地机器上运行它。如果您是在云环境中进行设置,请检查市场中的 jenkins 虚拟机映像以设置环境并配置所需的插件。
  3. 在您的 bitbucket 存储库设置中创建一个 webhook,以调用对 jenkins 回调 url 的 http 调用以触发持续集成作业。
  4. 如果您有现有的 jenkins 服务器,请确保在 jenkins 服务器中安装了管道插件。否则转到“管理插件”并安装管道插件。
  5. 在这个项目中,我们使用 consul 作为状态存储和状态锁定的远程后端。对于多人参与项目和生产部署的情况,不建议使用本地状态。最好使用远程后端,它提供具有状态锁定功能的高可用存储,以避免多个用户一次写入状态。
  6. 如果您的环境中没有 consul 键值存储,只需拉取 consul docker 镜像并设置一个单节点集群。如果是生产部署,请设置分布式键值存储。
  7. 在 slack 中创建一个应用程序并记下用于在 Jenkinsfile 中配置它的 slack 集成详细信息。
  8. 在主 terraform 配置文件中配置您的提供者详细信息和后端详细信息,可以通过环境变量或持久保存在存储库中。就我而言,我将在 AWS 中预置一个资源,而我的 CI 服务器托管在 AWS 中。因此,我将 IAM 角色分配给具有足够权限的服务器。
  9. 使用管道插件在 Jenkins 中创建一个新项目。
  10. 添加定义管道阶段的 Jenkinsfile。保存作业并手动触发以进行测试。然后将更改应用到配置并将更改提交到 bitbucket 并确保自动触发作业。检查 Jenkins 日志以获取有关该作业的更多详细信息。

在此处输入图片说明

###Jenkinsfile###
import groovy.json.JsonOutput

//git env vars
env.git_url = 'https://user@bitbucket.org/user/terraform-ci.git'
env.git_branch = 'master'
env.credentials_id = '1'

//slack env vars
env.slack_url = 'https://hooks.slack.com/services/SDKJSDKS/SDSDJSDK/SDKJSDKDS23434SDSDLCMLC'
env.notification_channel = 'my-slack-channel'

//jenkins env vars
env.jenkins_server_url = 'https://52.79.46.98'
env.jenkins_node_custom_workspace_path = "/opt/bitnami/apps/jenkins/jenkins_home/${JOB_NAME}/workspace"
env.jenkins_node_label = 'master'
env.terraform_version = '0.11.10'

def notifySlack(text, channel, attachments) {
    def payload = JsonOutput.toJson([text: text,
        channel: channel,
        username: "Jenkins",
        attachments: attachments
    ])
    sh "export PATH=/opt/bitnami/common/bin:$PATH && curl -X POST --data-urlencode \'payload=${payload}\' ${slack_url}"
}

pipeline {
	agent {
		node {
			customWorkspace "$jenkins_node_custom_workspace_path"
			label "$jenkins_node_label"
		} 
	}
	
	stages {
		stage('fetch_latest_code') {
			steps {
				git branch: "$git_branch" ,
				credentialsId: "$credentials_id" ,
				url: "$git_url"
			}
		}

		stage('install_deps') {
			steps {
				sh "sudo apt install wget zip python-pip -y"
				sh "cd /tmp"
				sh "curl -o terraform.zip https://releases.hashicorp.com/terraform/'$terraform_version'/terraform_'$terraform_version'_linux_amd64.zip"
				sh "unzip terraform.zip"
				sh "sudo mv terraform /usr/bin"
				sh "rm -rf terraform.zip"
			}
		}

		stage('init_and_plan') {
			steps {
				sh "sudo terraform init $jenkins_node_custom_workspace_path/workspace"
				sh "sudo terraform plan $jenkins_node_custom_workspace_path/workspace"
				notifySlack("Build completed! Build logs from jenkins server $jenkins_server_url/jenkins/job/$JOB_NAME/$BUILD_NUMBER/console", notification_channel, [])
			}
		}

		stage('approve') {
			steps {
			  notifySlack("Do you approve deployment? $jenkins_server_url/jenkins/job/$JOB_NAME", notification_channel, [])
				input 'Do you approve deployment?'
			}
		}

		stage('apply_changes') {
			steps {
				sh "echo 'yes' | sudo terraform apply $jenkins_node_custom_workspace_path/workspace"
				notifySlack("Deployment logs from jenkins server $jenkins_server_url/jenkins/job/$JOB_NAME/$BUILD_NUMBER/console", notification_channel, [])
			}
		}
	}
	
	post { 
  	always { 
    	cleanWs()
   }
  }
}
###Code Completed###
Run Code Online (Sandbox Code Playgroud)