我尝试将Terraform计划结果的说明功能集成到CI/CD中,请ChatGPT帮我解释!
背景:
基础设施工程师:“请帮我审查一下这段Terraform代码的PR。”
基础设施工程师:“请查看变更点的plan结果↓。”
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
~ update in-place
- destroy
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_instance.example1 will be created
+ resource "aws_instance" "example1" {
+ ami = "ami-abc123"
+ instance_type = "t2.micro"
+ key_name = "example_key"
+ vpc_security_group_ids = (known after apply)
+ subnet_id = "subnet-123456"
+ associate_public_ip_address = true
+ tags = {
+ "Name" = "example1"
}
}
# aws_instance.example2 will be updated in-place
~ resource "aws_instance" "example2" {
~ instance_type = "t2.micro" -> "t2.small"
ami = "ami-abc123"
key_name = "example_key"
vpc_security_group_ids = "sg-abc123"
subnet_id = "subnet-123456"
associate_public_ip_address = true
tags = {
"Name" = "example2"
}
}
# aws_instance.example3 will be destroyed
- resource "aws_instance" "example3" {
- ami = "ami-abc123" -> null
- instance_type = "t2.micro" -> null
- key_name = "example_key" -> null
- vpc_security_group_ids = "sg-abc123" -> null
- subnet_id = "subnet-123456" -> null
- associate_public_ip_address = true -> null
- tags = {
"Name" = "example3"
} -> null
}
# aws_instance.example4 must be replaced
-/+ resource "aws_instance" "example4" {
~ ami = "ami-abc123" -> "ami-def456" # forces replacement
~ instance_type = "t2.micro" -> "t2.small"
key_name = "example_key"
vpc_security_group_ids = "sg-abc123"
subnet_id = "subnet-123456"
associate_public_ip_address = true
tags = {
"Name" = "example4"
}
}
Plan: 2 to add, 1 to change, 2 to destroy.
应该看哪里呢…
当团队成员要求对Terraform代码进行审核时,我认为会发生类似上述对话的情况,但这种审核对于初学者来说却更难一些。
具体而言,我觉得很难在查看像上面的计划结果时,快速理解以下几个方面。
-
- この変更によってどのような影響があるのか
- この変更で気を付けるべき点はどこか
因此,我尝试创建一个功能,让ChatGPT(gpt-3.5或gpt-4)解释并展示计划的结果。
示例
在特定的分支上,我们对Terraform文件进行了如下修改。
将这个差异提交并推送到远程仓库中。
resource "aws_codecommit_repository" "sample_1" {
repository_name = "sample-1"
}
- resource "aws_codecommit_repository" "sample_2" {
- repository_name = "sample_2"
- }
+ resource "aws_codecommit_repository" "sample_qiita_article" {
+ repository_name = "sample-qiita-article"
+ description = "This repository is for the article of Qiita."
+ default_branch = "mastar"
+ }
然后,CodePipeline会像图片一样启动。
按下「詳細」按钮后,您可以在下方确认GPT为您提供的日志说明。
> Entering new chain...
Prompt after formatting:
System:
あなたはterraformのplan結果を解釈し、噛み砕いて初心者にもわかりやすく説明することができます。
下記のplan結果を読み解いて、どのような変更が加わるか、どのような点に注意すべきかを500文字程度で説明してください。
Human:
```:plan結果
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
- destroy
Terraform will perform the following actions:
# aws_codecommit_repository.sample_2 will be destroyed
- resource "aws_codecommit_repository" "sample_2" {
- arn = "arn:aws:codecommit:ap-northeast-1:any_account_id:sample-2" -> null
- clone_url_http = "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/sample-2" -> null
- clone_url_ssh = "ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/sample-2" -> null
- id = "sample-2" -> null
- repository_id = "sample_repository_id" -> null
- repository_name = "sample-2" -> null
- tags = {} -> null
- tags_all = {} -> null
}
# aws_codecommit_repository.sample_qiita_article will be created
+ resource "aws_codecommit_repository" "sample_qiita_article" {
+ arn = (known after apply)
+ clone_url_http = (known after apply)
+ clone_url_ssh = (known after apply)
+ default_branch = "master"
+ description = "This repository is for the article of Qiita."
+ id = (known after apply)
+ repository_id = (known after apply)
+ repository_name = "sample-qiita-article"
+ tags_all = (known after apply)
}
Plan: 1 to add, 0 to change, 1 to destroy.
```
> Finished chain.
ChatGPTからひとこと:
このplan結果では、Terraformが以下の変更を加えることを示しています。
1. `aws_codecommit_repository.sample_2`というリポジトリが削除されます。
- 削除されるリポジトリの詳細情報(ARN、clone URLなど)が表示されています。
- このリポジトリに関連するリソースはすべて削除されます。
2. `aws_codecommit_repository.sample_qiita_article`というリポジトリが作成されます。
- このリポジトリにはまだ詳細情報がわからないため、apply後にARNやclone URLなどが表示されます。
- リポジトリのデフォルトブランチは"master"に設定され、Qiitaの記事用のリポジトリであることが説明されています。
プランの結果は、1つのリポジトリが削除され、もう1つのリポジトリが作成されることを示しています。変更を適用する前に、これらの変更が意図したものであることを確認してください。また、削除されるリポジトリに関連するリソースがある場合は注意が必要です。
机制具体细节
在GitHub或CodeCommit等平台上推送Terraform文件的更改时,AWS CodeBuild将被触发,执行terraform plan指令并将结果输入给ChatGPT,然后展示响应信息。
这样一来,例如在公关的证据中,您可以直接复制粘贴计划结果而无需自己撰写解释,只需将CodeBuild的日志粘贴进去就可以了。
实施示例
层级图
.
└── main.tf/
└── gpt_plan/
├── buildspec_plan.yml
├── explain_plan_result.py
└── install_terraform.sh
CodeBuild实现部分
resource "aws_codebuild_project" "terraform_plan" {
name = "gpt_plan_build_sample"
service_role = your_codebuild_role
build_timeout = "5" # minutes
artifacts {
type = "NO_ARTIFACTS"
}
environment {
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/standard:5.0"
type = "LINUX_CONTAINER"
image_pull_credentials_type = "CODEBUILD"
}
# CodePipelineから実行する場合にはCodePipelineのconfigurationが優先される
source {
type = "CODECOMMIT" # or GITGUB, S3, etc.
location = "https://git-codecommit.ap-northeast-1.amazonaws.com/your_repository_location"
git_clone_depth = 1
buildspec = "gpt_plan/buildspec_plan.yml"
}
}
version: 0.2
env:
parameter-store:
OPENAI_API_KEY: "openai_api_key"
phases:
install:
runtime-versions:
python: 3.8
commands:
- chmod +x gpt_plan/install_terraform.sh
- ./gpt_plan/install_terraform.sh
build:
commands:
- terraform init
- terraform plan -out=plan_result.txt
post_build:
on-failure: CONTINUE
commands:
# ANSIエスケープコードと呼ばれる、SHELL上で文字色等を装飾するためのコードをsedで削除してからplan_result_fmt.txtに出力
- terraform show plan_result.txt | sed 's/\x1b\[[0-9;]*m//g' > plan_result_fmt.txt
- pip install langchain
- pip install openai
- python -m gpt_plan.explain_plan_result plan_result_fmt.txt
#!/bin/bash
apt-get update
apt-get install -y unzip
curl -o /tmp/terraform.zip -LO https://releases.hashicorp.com/terraform/0.14.5/terraform_0.14.5_linux_amd64.zip # versionはお好みで指定
unzip /tmp/terraform.zip -d /usr/local/bin/
terraform --version
代码管道的实现部分
resource "aws_codepipeline" "gpt_plan_pipeline_sample" {
name = "gpt_plan_pipeline_sample"
role_arn = your_codepipeline_role
artifact_store {
location = aws_s3_bucket.artifact_store.bucket
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeCommit"
version = "1"
output_artifacts = ["source_output"]
# codebuildのsourceよりもこちらが優先される
configuration = {
RepositoryName = your_repository_name # tf差分ファイルのpush先リポジトリを指定する
BranchName = "develop" # or master or main
}
}
}
stage {
name = "BuildAndPlan"
action {
name = "Plan"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
input_artifacts = ["source_output"]
version = "1"
configuration = {
ProjectName = aws_codebuild_project.gpt_plan_build_sample.name
}
}
}
}
Python ChatGPT输入部分
import sys
from langchain.chat_models import ChatOpenAI
from langchain.chains import LLMChain
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
if len(sys.argv) < 2:
print("Usage: python explain_plan_result.py <plan_file>")
sys.exit(1)
plan_file = sys.argv[1]
class Prompt:
def pmt_tmpl(self) -> ChatPromptTemplate:
sys_template = """
あなたはterraformのplan結果を解釈し、噛み砕いて初心者にもわかりやすく説明することができます。
下記のplan結果を読み解いて、どのような変更が加わるか、どのような点に注意すべきかを{summary_words}文字程度で説明してください。
"""
sys_pmt = SystemMessagePromptTemplate.from_template(sys_template)
human_template = """
```:plan結果
{plan_result}
```
"""
human_pmt = HumanMessagePromptTemplate.from_template(human_template)
chat_pmt = ChatPromptTemplate.from_messages([sys_pmt, human_pmt])
return chat_pmt
def vairables(self, summary_words: int, plan_result: str) -> dict:
return {
"summary_words": summary_words,
"plan_result": plan_result,
}
def get_plan_result() -> str:
with open(plan_file, "r") as f:
plan_result: str = f.read()
return plan_result
def explain_plan_result() -> None:
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.5)
pmt_cls = Prompt()
prompt = pmt_cls.pmt_tmpl()
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)
chain_input = pmt_cls.vairables(summary_words=500, plan_result=get_plan_result())
llm_resp = chain.run(chain_input)
print(f"ChatGPTからひとこと:\n{llm_resp}")
if __name__ == "__main__":
explain_plan_result()
系统案例的深入挖掘
在提交Terraform代码的PR时,也尝试附上以下的说明文。在以下情况下可能会有用。
-
- Terraformに明るくないレビュアーがいる場合
レビュアーがTerraformに精通していなくても、この機能により変更点を理解する手助けができます。
他部署の人もレビューに参加していて、変更の要点を簡潔に説明したい場合
変更点を要約することで、プロジェクト全体を円滑に進めることができます。
通过改进输入作为LangChain系统模板(sys_template = ~)的文章,我们可以让ChatGPT提供更加针对特定用途的解释。
例如,我想到可以通过指定sys_template = “您可以从terraform的plan结果中准确地检测到拼写错误。~”来将其命名为”拼写检测小助手”。
想法
我在我所参与的项目中尝试了一下。
虽然对于简单的计划结果来说,并没有太高的实用性,但对于复杂的计划结果,它可能会有助于理解。
此外,在进行审核时,我也对ChatGPT会说些什么感到有些期待,这也是一个好处。(个人差异存在)
在继续进行细微改进的同时,我们期待着未来它将如何为我们提供帮助。