참고
terraform module을 만들었다면 README.md를 잘 작성해줘야 함. 그런데 module이 좀 복잡해지면 잘못된 내용을 담을 수 있거나 매 변경 때마다 문서 내용을 업데이트하는 것은 쉬운게 아님. 그래서 .tf
파일 경로만 지정해주면 다 읽어서 문서를 만들어주는 terraform-docs를 적용해보자. 그리고 이 적용 또한 commit할 때마다 자동으로 수행되도록 pre-commit hook도 사용해보자.
terraform module로부터 다양한 포맷으로 도큐먼트 생성해주는 유틸리티.
$ brew install terraform-docs
### 확인
$ terraform-docs
A utility to generate documentation from Terraform modules in various output formats
Usage:
terraform-docs [PATH] [flags]
terraform-docs [command]
Available Commands:
asciidoc Generate AsciiDoc of inputs and outputs
completion Generate shell completion code for the specified shell (bash or zsh)
help Help about any command
json Generate JSON of inputs and outputs
markdown Generate Markdown of inputs and outputs
pretty Generate colorized pretty of inputs and outputs
tfvars Generate terraform.tfvars of inputs
toml Generate TOML of inputs and outputs
version Print the version number of terraform-docs
xml Generate XML of inputs and outputs
yaml Generate YAML of inputs and outputs
Flags:
-c, --config string config file name (default ".terraform-docs.yml")
--footer-from string relative path of a file to read footer from (default "")
--header-from string relative path of a file to read header from (default "main.tf")
-h, --help help for terraform-docs
--hide strings hide section [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources]
--lockfile read .terraform.lock.hcl if exist (default true)
--output-check check if content of output file is up to date (default false)
--output-file string file path to insert output into (default "")
--output-mode string output to file method [inject, replace] (default "inject")
--output-template string output template (default "<!-- BEGIN_TF_DOCS -->\n{{ .Content }}\n<!-- END_TF_DOCS -->")
--output-values inject output values into outputs (default false)
--output-values-from string inject output values from file into outputs (default "")
--read-comments use comments as description when description is empty (default true)
--recursive update submodules recursively (default false)
--recursive-path string submodules path to recursively update (default "modules")
--show strings show section [all, data-sources, footer, header, inputs, modules, outputs, providers, requirements, resources]
--sort sort items (default true)
--sort-by string sort items by criteria [name, required, type] (default "name")
-v, --version version for terraform-docs
Use "terraform-docs [command] --help" for more information about a command.
$ terraform-docs markdown table \
--output-file README.md \
--output-mode inject \
.
<!-- BEGIN_TF_DOCS -->
와 <!-- END_TF_DOCS -->
사이로 추가되므로 사용자가 추가하고 싶은 내용이 있다면 그 위나 아래에 작성하자.샘플 README.md
## 용도
- docker image build하는 CI나 k8s에 워크로드를 띄우는 CD 작업을 CodeSeries로 할 때 활용.
## 효과
- 최소 권한 법칙에 따라 IAM을 CI/CD 단위로 생성하고 권한을 최소화 함.
- 매번 CodeBuild, CodePipeline, IAM, S3를 만들 필요 없이 이 모듈을 사용하면 한 번에 만들어주며 추적 관리가 가능함.
## 범위
가능
- CI나 CD를 뺄 수 있음.
- 기본적으로 CD에는 approval을 넣으려 하는데 뺼 수 있음.
- buildspec path 수정.
- CodeCommit 소스 엔드포인트/브랜치 수정.
- 접근할 ECR ARN 수정.
- attach할 IAM policy ARN 수정.
- tags 추가.
불가능
- k8s에 apply하는 RBAC는 직접 적용해줘야 함(권고 사항)
- Source는 반드시 CodeCommit 이어야 함
- Source (CodeCommit) -> Build (CodeBuild) -> Deploy on EKS (CodeBuild) 구조가 아니라면 사용 불가.
## 사용 방법
기본 main.tf 작성 방법 (`env/prod/cicd/test`)
``` bash
## 용도
- docker image build하는 CI나 k8s에 워크로드를 띄우는 CD 작업을 CodeSeries로 할 때 활용.
## 효과
- 최소 권한 법칙에 따라 IAM을 CI/CD 단위로 생성하고 권한을 최소화 함.
- 매번 CodeBuild, CodePipeline, IAM, S3를 만들 필요 없이 이 모듈을 사용하면 한 번에 만들어주며 추적 관리가 가능함.
## 범위
가능
- CI나 CD를 뺄 수 있음.
- 기본적으로 CD에는 approval을 넣으려 하는데 뺼 수 있음.
- buildspec path 수정.
- CodeCommit 소스 엔드포인트/브랜치 수정.
- 접근할 ECR ARN 수정.
- attach할 IAM policy ARN 수정.
- tags 추가.
불가능
- k8s에 apply하는 RBAC는 직접 적용해줘야 함(권고 사항)
- Source는 반드시 CodeCommit 이어야 함
- Source (CodeCommit) -> Build (CodeBuild) -> Deploy on EKS (CodeBuild) 구조가 아니라면 사용 불가.
## 사용 방법
기본 main.tf 작성 방법 (`env/prod/cicd/test`)
``` bash
terraform { ### optional
backend "s3" {
bucket = "<your value>"
key = "<your value>/terraform.tfstate"
region = "<your value>"
encrypt = true
}
}
module "cicd-with-eks" {
source = "../../../../modules/cicd-with-eks/" ### relative
name_custom_suffix = "test-set-your-name"
tags_additional = {
Purpose = "test-set-your-name"
}
this_iam_managed_policy_arns_additional = []
this_ecr_arns = [
"arn:aws:ecr:ap-northeast-2:set-your-aws-account-id:repository/set-your-repo",
"arn:aws:ecr:ap-northeast-2:set-your-aws-account-id:repository/set-your-repo",
]
codecommit_repo_name = "set-your-codcommit-repo-name"
codecommit_branch_name = "set-your-codcommit-branch-name"
ci_buildspec_path = "buildspec.yml"
ci_environment = {
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/standard:6.0"
type = "LINUX_CONTAINER"
image_pull_credentials_type = "CODEBUILD"
privileged_mode = true
}
cd_buildspec_path = "kubernetes/buildspec.yml"
cd_environment = {
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/standard:6.0"
type = "LINUX_CONTAINER"
image_pull_credentials_type = "CODEBUILD"
privileged_mode = true
}
codepipeline_stages = [
{
name = "Source"
actions = [
{
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeCommit"
version = "1"
input_artifacts = [""]
output_artifacts = ["source_output"]
run_order = 1
### will be added automatically from local block
# configuration = {
# RepositoryName = "set-your-codcommit-repo-name"
# BranchName = "set-your-codcommit-branch-name"
# }
}
]
},
{
name = "Build"
actions = [{
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["source_output"]
output_artifacts = ["build_output"]
run_order = 1
### will be added automatically from local block
# configuration = {
# ProjectName = "aws_codebuild_project.cicd_ci.name"
# }
}]
},
{
name = "Delivery"
actions = [
{
name = "Approval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = 1
run_order = 1
input_artifacts = [""]
output_artifacts = [""]
### will be added automatically from local block
# configuration {
# NotificationArn = "$var.approve_sns_arn}"
# CustomData = "${var.approve_comment}"
# ExternalEntityLink = "${var.approve_url}"
#
# }
},
{
name = "Delivery"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["source_output"]
output_artifacts = [""]
run_order = 2
### will be added automatically from local block
# configuration = {
# ProjectName = aws_codebuild_project.cicd_cd.name
# }
}
]
}
]
}
<!-- BEGIN_TF_DOCS -->
## Requirements
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.7 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 4.47 |
| <a name="requirement_time"></a> [time](#requirement\_time) | ~> 0.9.1 |
## Providers
| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 4.60.0 |
| <a name="provider_null"></a> [null](#provider\_null) | 3.2.1 |
| <a name="provider_terraform"></a> [terraform](#provider\_terraform) | n/a |
| <a name="provider_time"></a> [time](#provider\_time) | 0.9.1 |
## Modules
No modules.
## Resources
| Name | Type |
|------|------|
| [aws_codebuild_project.this_cd](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |
| [aws_codebuild_project.this_ci](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codebuild_project) | resource |
| [aws_codepipeline.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codepipeline) | resource |
| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket_acl.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_acl) | resource |
| [null_resource.wait](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
| [time_static.this](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/static) | resource |
| [aws_codecommit_repository.this_codecommit](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/codecommit_repository) | data source |
| [aws_iam_policy_document.this_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.this_inline_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [terraform_remote_state.eks](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/data-sources/remote_state) | data source |
## Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_cd_buildspec_path"></a> [cd\_buildspec\_path](#input\_cd\_buildspec\_path) | Path to the buildspec.yml for the CD stage | `string` | `"kubernetes/buildspec.yml"` | no |
| <a name="input_cd_environment"></a> [cd\_environment](#input\_cd\_environment) | CodeBuild environment for the CD stage | <pre>object({<br> compute_type = string<br> image = string<br> type = string<br> image_pull_credentials_type = string<br> privileged_mode = bool<br> })</pre> | <pre>{<br> "compute_type": "BUILD_GENERAL1_SMALL",<br> "image": "aws/codebuild/standard:6.0",<br> "image_pull_credentials_type": "CODEBUILD",<br> "privileged_mode": true,<br> "type": "LINUX_CONTAINER"<br>}</pre> | no |
| <a name="input_ci_buildspec_path"></a> [ci\_buildspec\_path](#input\_ci\_buildspec\_path) | Path to the buildspec.yml for the CI stage | `string` | `"buildspec.yml"` | no |
| <a name="input_ci_environment"></a> [ci\_environment](#input\_ci\_environment) | CodeBuild environment for the CI stage | <pre>object({<br> compute_type = string<br> image = string<br> type = string<br> image_pull_credentials_type = string<br> privileged_mode = bool<br> })</pre> | <pre>{<br> "compute_type": "BUILD_GENERAL1_SMALL",<br> "image": "aws/codebuild/standard:6.0",<br> "image_pull_credentials_type": "CODEBUILD",<br> "privileged_mode": true,<br> "type": "LINUX_CONTAINER"<br>}</pre> | no |
| <a name="input_codecommit_branch_name"></a> [codecommit\_branch\_name](#input\_codecommit\_branch\_name) | Branch name watched from the CodePipeline's source stage | `string` | `"set-your-codcommit-branch-name"` | no |
| <a name="input_codecommit_repo_name"></a> [codecommit\_repo\_name](#input\_codecommit\_repo\_name) | CodeCommit repository name used as a CodePipeline's source | `string` | `"set-your-codcommit-repo-name"` | no |
| <a name="input_codepipeline_stages"></a> [codepipeline\_stages](#input\_codepipeline\_stages) | CodePipeline definition for all stages | `any` | `[]` | no |
| <a name="input_create_cd"></a> [create\_cd](#input\_create\_cd) | Indicates whether or not to create a CodeBuild project for CD | `bool` | `true` | no |
| <a name="input_create_ci"></a> [create\_ci](#input\_create\_ci) | Indicates whether or not to create a CodeBuild project for CI | `bool` | `true` | no |
| <a name="input_name_custom_suffix"></a> [name\_custom\_suffix](#input\_name\_custom\_suffix) | suffix attached to name of all resources | `string` | `"set-your-name"` | no |
| <a name="input_tags_additional"></a> [tags\_additional](#input\_tags\_additional) | Additional tags that will be attached additionally to resources in this module | `map(string)` | `{}` | no |
| <a name="input_tags_default"></a> [tags\_default](#input\_tags\_default) | Default tags that will be attached to resources in this module | `map(string)` | <pre>{<br> "Email": "set-your-email",<br> "LocalTagTest": "true",<br> "Owner": "set-your-id",<br> "Purpose": "mlops",<br> "Team": "datatech"<br>}</pre> | no |
| <a name="input_this_ecr_arns"></a> [this\_ecr\_arns](#input\_this\_ecr\_arns) | ECR ARNs to be allowed permissions | `list(string)` | <pre>[<br> "arn:aws:ecr:ap-northeast-2:set-your-aws-account-id:repository/set-your-repo",<br> "arn:aws:ecr:ap-northeast-2:set-your-aws-account-id:repository/set-your-repo"<br>]</pre> | no |
| <a name="input_this_iam_managed_policy_arns_additional"></a> [this\_iam\_managed\_policy\_arns\_additional](#input\_this\_iam\_managed\_policy\_arns\_additional) | Managed policies additionally attached | `list(string)` | `[]` | no |
| <a name="input_this_iam_managed_policy_arns_default"></a> [this\_iam\_managed\_policy\_arns\_default](#input\_this\_iam\_managed\_policy\_arns\_default) | Managed policies attached by default. | `list(string)` | <pre>[<br> "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy",<br> "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy",<br> "arn:aws:iam::aws:policy/AmazonEKSServicePolicy",<br> "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"<br>]</pre> | no |
## Outputs
| Name | Description |
|------|-------------|
| <a name="output_codebuild_cd_arn"></a> [codebuild\_cd\_arn](#output\_codebuild\_cd\_arn) | CodeBuild Cd project ARN |
| <a name="output_codebuild_ci_arn"></a> [codebuild\_ci\_arn](#output\_codebuild\_ci\_arn) | CodeBuild CI project ARN |
| <a name="output_codepipeline_arn"></a> [codepipeline\_arn](#output\_codepipeline\_arn) | CodePipeline ARN |
| <a name="output_role_arn"></a> [role\_arn](#output\_role\_arn) | Role ARN to be used by CodePipeline, CodeBuild |
| <a name="output_s3_bucket_arn"></a> [s3\_bucket\_arn](#output\_s3\_bucket\_arn) | S3 Bucket ARN used by CodeSeries CICD |
<!-- END_TF_DOCS -->
위 예제에서 <!-- BEGIN_TF_DOCS -→ 이전에는 직접 작성한 내용이며 여기는 terraform-docs가 건드리지 않는 부분이므로 별도로 사용자가 추가하면 됨.
매번 변경사항이 생길 때 마다 terraform-docs를 수동으로 실행하는 것은 귀찮고 휴먼 에러가 생길 여지가 있으므로 tf 소스 변경 후 커밋할 때 terraform-docs를 자동으로 수행하게 설정해보자.
소스코드 작업 후 push 전에 hook을 이용하여 사전 작업할 내용을 정의할 수 있는데 이를 활용해 변경된 terraform 코드에 대한 README.md를 terraform-docs로 자동 업데이트 해주자.
먼저, pre-commit 설치하기
### mac
$ brew install pre-commit
### python
$ pip install pre-commit
설치 확인
$ pre-commit --version
root 경로에 .pre-commit-config.yaml
생성
repos:
- repo: https://github.com/terraform-docs/terraform-docs
rev: "v0.16.0"
hooks:
- id: terraform-docs-go
args: ["markdown", "table", "--output-file", "README.md", "--output-mode", "inject", "<path-to-tf>"]
활성화
테스트
$ git commit -am "[update modules/cicd-wth-eks] pre-commit 테스트"
terraform-docs...........................................................Failed
- hook id: terraform-docs-go
- files were modified by this hook
modules/cicd-with-eks/README.md updated successfully
$ git commit -am "[update modules/cicd-wth-eks] pre-commit 테스트"
terraform-docs...........................................................Passed
[master a250c03] [update modules/cicd-wth-eks] pre-commit 테스트
2 files changed, 4 insertions(+), 5 deletions(-)
주의 사항