답변:
또한 기존 AWS 인프라를 Terraform으로 마이그레이션하는 중이므로 개발할 때 답변을 업데이트하는 것을 목표로합니다.
나는 내가 불확실한 영역을 구체화하기 위해 공식 Terraform 예제 와 여러 번의 시행 착오 에 크게 의존해 왔습니다.
.tfstate
파일
Terraform 구성을 사용하여 각기 다른 상태를 가질 수있는 서로 다른 인프라에 많은 상자를 프로비저닝 할 수 있습니다. 여러 사람이 실행할 수도 있으므로이 상태는 중앙 위치 (예 : S3)에 있어야하지만 git이 아니 어야합니다 .
이것은 Terraform을 보면 확인할 수 있습니다 .gitignore
.
개발자 제어
우리의 목표는 전체 감사 (git 로그) 및 온 전성 검사 변경 (pull 요청) 기능을 유지하면서 개발자에게 인프라에 대한 더 많은 제어를 제공하는 것입니다. 이를 염두에두고 내가 목표로하는 새로운 인프라 워크 플로는 다음과 같습니다.
편집 1-현재 상태 업데이트
이 답변을 시작한 이후로 많은 TF 코드를 작성했으며 우리의 상황이 더 편안해졌습니다. 우리는 그 과정에서 버그와 제한에 부딪 혔지만 이것이 새롭고 빠르게 변화하는 소프트웨어를 사용하는 특징이라는 점을 인정합니다.
나열한 것
각각 여러 서브넷이있는 여러 VPC가있는 복잡한 AWS 인프라가 있습니다. 이를 쉽게 관리하기위한 핵심은 인프라 코드 (테라 폼 및 퍼펫 모두)를 구성하는 데 사용할 수있는 지역, 환경, 서비스 및 소유자를 포함하는 유연한 분류를 정의하는 것이 었습니다.
모듈
다음 단계는 terraform 모듈을 저장할 단일 git 저장소를 만드는 것이 었습니다. 모듈의 최상위 디렉토리 구조는 다음과 같습니다.
tree -L 1 .
결과:
├── README.md
├── aws-asg
├── aws-ec2
├── aws-elb
├── aws-rds
├── aws-sg
├── aws-vpc
└── templates
각각은 정상적인 기본값을 설정하지만 "glue"로 덮어 쓸 수있는 변수로 노출합니다.
접착제
glue
위에서 언급 한 모듈을 사용 하는 두 번째 저장소 가 있습니다. 분류 문서에 따라 배치됩니다.
.
├── README.md
├── clientA
│ ├── eu-west-1
│ │ └── dev
│ └── us-east-1
│ └── dev
├── clientB
│ ├── eu-west-1
│ │ ├── dev
│ │ ├── ec2-keys.tf
│ │ ├── prod
│ │ └── terraform.tfstate
│ ├── iam.tf
│ ├── terraform.tfstate
│ └── terraform.tfstate.backup
└── clientC
├── eu-west-1
│ ├── aws.tf
│ ├── dev
│ ├── iam-roles.tf
│ ├── ec2-keys.tf
│ ├── prod
│ ├── stg
│ └── terraform.tfstate
└── iam.tf
클라이언트 수준에는 .tf
글로벌 리소스 (예 : IAM 역할)를 프로비저닝하는 AWS 계정 별 파일이 있습니다. 다음은 EC2 SSH 퍼블릭 키가있는 지역 수준입니다. 마지막 환경 (년 dev
, stg
, prod
등) 우리 VPC 셋업, 인스턴스의 생성 등에 연결 저장된 피어링된다.
참고 사항 : 보시다시피 나는 terraform.tfstate
git에 보관하는 것보다 위의 내 조언 에 어긋납니다. 이것은 내가 S3로 이동할 때까지 일시적인 조치이지만 현재 유일한 개발자이므로 나에게 적합합니다.
다음 단계
이것은 여전히 수동 프로세스이며 Jenkins에는 없지만 우리는 다소 크고 복잡한 인프라를 포팅하고 있습니다. 내가 말했듯이 버그는 거의 없지만 잘되고 있습니다!
편집 2-변경
이 초기 답변을 작성한 지 거의 1 년이 지났고 Terraform과 저의 상태가 크게 변경되었습니다. 저는 이제 Terraform을 사용하여 Azure 클러스터를 관리하는 새로운 위치에 있으며 Terraform은 이제 v0.10.7
.
상태
사람들은 계속 저 상태가되어야 말한 하지 힘내 갈 - 그리고 그들은 정확합니다. 우리는 이것을 개발자 커뮤니케이션과 규율에 의존하는 2 인 팀의 임시 조치로 사용했습니다. 더 큰 규모의 분산 된 팀과 함께 이제 DynamoDB에서 제공하는 잠금 을 통해 S3의 원격 상태를 완전히 활용 하고 있습니다. 이상적으로 이것은 consul로 마이그레이션 될 것입니다. 이제는 크로스 클라우드 공급자를 잘라 내기위한 v1.0입니다.
모듈
이전에는 내부 모듈을 만들고 사용했습니다. 이것은 여전히 사례이지만 Terraform 레지스트리 의 출현과 성장으로 우리는 이것을 적어도 기반으로 사용하려고합니다.
파일 구조
새로운 위치는 infx 환경 dev
과 prod
. 각각은 자신의 변수와 출력을 가지고 있으며 위에서 만든 모듈을 재사용합니다. remote_state
제공자는 또한 환경 사이에 작성된 자원의 출력을 공유하는 데 도움이됩니다. 시나리오는 전역 적으로 관리되는 TLD에 대한 서로 다른 Azure 리소스 그룹의 하위 도메인입니다.
├── main.tf
├── dev
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
└── prod
├── main.tf
├── output.tf
└── variables.tf
계획
다시 분산 된 팀의 추가 과제로 인해 이제 우리는 항상 terraform plan
명령 출력을 저장합니다 . 우리는 검사와 사이에 변화의 위험없이 실행됩니다 알 수 plan
및 apply
(잠금이 함께 할 수 있지만) 단계. 이 계획 파일은 잠재적으로 일반 텍스트 "비밀"변수를 포함 할 수 있으므로 삭제해야합니다.
전반적으로 우리는 Terraform에 매우 만족하며 추가 된 새로운 기능으로 계속 배우고 개선합니다.
Terraform을 많이 사용하며 권장 설정은 다음과 같습니다.
각 환경 (예 : stage, prod, qa)에 대한 Terraform 코드를 별도의 템플릿 집합 (따라서 별도의 .tfstate
파일)에 저장하는 것이 좋습니다 . 변경하는 동안 별도의 환경이 실제로 서로 격리되도록하는 것이 중요합니다. 그렇지 않으면 스테이징에서 일부 코드를 엉망으로 만드는 동안 prod에서도 무언가를 날려 버리는 것이 너무 쉽습니다. 이유 에 대한 다채로운 토론은 Terraform, VPC 및 env 당 tfstate 파일이 필요한 이유를 참조하십시오 .
따라서 일반적인 파일 레이아웃은 다음과 같습니다.
stage
└ main.tf
└ vars.tf
└ outputs.tf
prod
└ main.tf
└ vars.tf
└ outputs.tf
global
└ main.tf
└ vars.tf
└ outputs.tf
단계 VPC의 모든 Terraform 코드는 stage
폴더 로 이동하고, prod VPC의 모든 코드는 prod
폴더 로 이동하고, VPC 외부에있는 모든 코드 (예 : IAM 사용자, SNS 주제, S3 버킷)는 global
폴더 로 이동 합니다. .
규칙에 따라 일반적으로 Terraform 코드를 3 개의 파일로 나눕니다.
vars.tf
: 입력 변수.outputs.tf
: 출력 변수.main.tf
: 실제 자원.일반적으로 인프라를 두 개의 폴더에 정의합니다.
infrastructure-modules
:이 폴더에는 재사용 가능한 작은 버전의 모듈이 포함되어 있습니다. 각 모듈을 VPC 또는 데이터베이스와 같은 단일 인프라를 생성하는 방법에 대한 청사진으로 생각하십시오.infrastructure-live
:이 폴더에는 .NET의 모듈을 결합하여 생성하는 실제 라이브 실행 인프라가 포함되어 있습니다 infrastructure-modules
. 이 폴더의 코드를 청사진에서 지은 실제 주택이라고 생각하십시오.Terraform 모듈은 폴더에 Terraform 템플릿 다만 어떤 집합입니다. 예를 들어 단일 VPC에 대한 모든 라우팅 테이블, 서브넷, 게이트웨이, ACL 등을 정의하는 vpc
in 이라는 폴더가있을 수 있습니다 infrastructure-modules
.
infrastructure-modules
└ vpc
└ main.tf
└ vars.tf
└ outputs.tf
우리는 다음에 해당 모듈을 사용할 수 있습니다 infrastructure-live/stage
및 infrastructure-live/prod
무대와 자극 VPC의를 만들 수 있습니다. 예를 들어 다음은 infrastructure-live/stage/main.tf
다음과 같습니다.
module "stage_vpc" {
source = "git::git@github.com:gruntwork-io/module-vpc.git//modules/vpc-app?ref=v0.0.4"
vpc_name = "stage"
aws_region = "us-east-1"
num_nat_gateways = 3
cidr_block = "10.2.0.0/18"
}
모듈을 사용하려면 module
리소스 를 사용하고 해당 source
필드를 하드 드라이브의 로컬 경로 (예 :) source = "../infrastructure-modules/vpc"
또는 위의 예에서와 같이 Git URL ( 모듈 소스 참조) 을 가리 킵니다 . Git URL의 장점은 특정 git sha1 또는 태그 ( ref=v0.0.4
)를 지정할 수 있다는 것 입니다. 이제 인프라를 작은 모듈 묶음으로 정의 할뿐만 아니라 해당 모듈의 버전을 지정하고 필요에 따라 신중하게 업데이트하거나 롤백 할 수 있습니다.
우리는 VPC, Docker 클러스터, 데이터베이스 등을 만들기 위해 재사용 가능하고 테스트되고 문서화 된 여러 인프라 패키지 를 만들었으며 내부적으로는 대부분 버전이 지정된 Terraform 모듈입니다.
Terraform을 사용하여 리소스 (예 : EC2 인스턴스, 데이터베이스, VPC)를 생성하면 생성 된 내용에 대한 정보가 .tfstate
파일 에 기록 됩니다. 이러한 리소스를 변경하려면 팀의 모든 구성원이 동일한 .tfstate
파일에 액세스 해야하지만 Git에 체크인해서는 안됩니다 ( 이유에 대한 설명 은 여기 참조 ).
대신 Terraform 을 실행할 때마다 최신 파일을 자동으로 푸시 / 풀하는 Terraform Remote State.tfstate
를 활성화하여 S3에 파일을 저장하는 것이 좋습니다 . 최신 버전이 손상 될 경우 이전 파일로 롤백 할 수 있도록 S3 버킷에서 버전 관리 를 활성화 해야합니다 . 그러나 중요한 참고 사항 : Terraform은 잠금을 제공하지 않습니다 . 따라서 두 팀 구성원 이 같은 파일 에서 동시에 실행되면 서로의 변경 사항을 덮어 쓸 수 있습니다..tfstate
terraform apply
.tfstate
이 문제를 해결하기 위해 Amazon DynamoDB를 사용하여 잠금을 제공하는 Terraform 용 씬 래퍼 인 Terragrunt 라는 오픈 소스 도구를 만들었습니다 (대부분의 팀에서 완전히 무료 여야 함). 자세한 내용 은 Terragrunt 를 사용 하여 Terraform에 자동 원격 상태 잠금 및 구성 추가를 확인하십시오 .
우리는 현실 세계에서 Terraform을 사용하기 위해 배운 모든 모범 사례를 자세히 설명 하는 A Comprehensive Guide to Terraform 이라는 일련의 블로그 게시물을 막 시작했습니다 .
업데이트 : Terraform 블로그 게시물 시리즈에 대한 포괄적 인 가이드가 인기를 얻어 Terraform : Up & Running 이라는 책으로 확장했습니다 !
remote config
Terraform 구성을 방금 확인했거나 이전 원격 구성을 변경하려는 경우 실행해야 합니다. Terraform 0.9는 개념을 도입하여 backends
많은 것을 단순화합니다. 자세한 내용은 이 PR 을 참조하십시오.
remote config
prod 상태를 가리 키 도록 명령 을 다시 실행 해야합니다 . 환경마다 다른 상태를 가정합니다. 맞습니까? v0.9가 기대됩니다.
.tf
두 개의 서로 다른 환경에 정확히 동일한 파일 세트를 배포 remote config
하려면 전환 할 때마다 실행해야합니다 . 이것은 분명히 오류가 발생하기 쉬우므로 실제로이 기술을 사용하지 않는 것이 좋습니다. 대신 이 블로그 게시물 에서 Terraform 모듈을 사용하는 방법 과 함께이 블로그 게시물에서 권장되는 Terraform 파일 레이아웃을 확인하십시오 .
이전에는이를 remote config
허용했지만 지금은 " 백엔드 " 로 대체 되었으므로 terraform 원격은 더 이상 사용할 수 없습니다.
terraform remote config -backend-config="bucket=<s3_bucket_to_store_tfstate>" -backend-config="key=terraform.tfstate" -backend=s3
terraform remote pull
terraform apply
terraform remote push
자세한 내용은 문서 를 참조하십시오.
여기에 많은 답변이 있다는 것을 알고 있지만 제 접근 방식은 상당히 다릅니다.
⁃ Modules
⁃ Environment management
⁃ Separation of duties
모듈
환경 관리
IaC는 인프라 관리와 관련된 SDLC 프로세스를 만들었으며 개발 인프라 및 개발 애플리케이션 환경을 기대하는 것은 정상이 아닙니다.
업무 분리
소규모 조직에 있거나 개인 인프라를 운영하는 경우 이는 실제로 적용되지는 않지만 운영 관리에 도움이됩니다.
일부 리소스는 거의 변경되지 않고 다른 리소스는 항상 변경되므로 릴리스 문제에도 도움이됩니다. 분리는 위험과 복잡성을 제거합니다.
이 전략은 AWS의 다중 계정 전략과 유사합니다. 더 많은 정보를 읽으십시오.
CI / CD
이것은 자체 주제이지만 Terraform은 좋은 파이프 라인 내에서 매우 잘 작동합니다. 여기서 가장 일반적인 오류는 CI를 은색 총알로 취급하는 것입니다. 기술적으로 Terraform은 어셈블리 파이프 라인 단계 중에 만 인프라를 프로비저닝해야합니다. 이는 일반적으로 템플릿을 검증하고 테스트하는 CI 단계에서 발생하는 것과는 별개입니다.
NB 모바일로 작성되었으므로 오류가 있으시면 양해 바랍니다.
답변이 매우 견고하고 유익하기 전에 여기에 2 센트를 추가하려고합니다.
적은 수의 리소스로 작업하는 것이 더 쉽고 빠릅니다.
terraform plan
및 terraform
apply 둘 다 클라우드 API 호출을 통해 리소스 상태를 확인합니다.적은 자원으로 폭발 반경이 더 작습니다.
원격 상태를 사용하여 프로젝트를 시작합니다.
tfstate
git 에서 파일을 관리하는 것은 악몽입니다.일관된 구조와 명명 규칙을 연습하십시오.
리소스 모듈을 가능한 한 단순하게 유지하십시오.
변수로 전달되거나 데이터 소스를 사용하여 검색 될 수있는 값을 하드 코딩 하지 마십시오 .
data
소스를 사용 하고 terraform_remote_state
특히 컴포지션 내에서 인프라 모듈 간의 접착제로 사용 합니다 .
( 참조 기사 : https://www.terraform-best-practices.com/code-structure )
예:
적은 수의 리소스로 작업하는 것이 더 쉽고 빠르므로 아래에 권장 코드 레이아웃이 나와 있습니다.
참고 : 각 프로젝트에는 고유 한 특성이 있으므로 엄격하게 따르지 않는 참고 자료입니다.
.
├── 1_tf-backend #remote AWS S3 + Dynamo Lock tfstate
│ ├── main.tf
│ ├── ...
├── 2_secrets
│ ├── main.tf
│ ├── ...
├── 3_identities
│ ├── account.tf
│ ├── roles.tf
│ ├── group.tf
│ ├── users.tf
│ ├── ...
├── 4_security
│ ├── awscloudtrail.tf
│ ├── awsconfig.tf
│ ├── awsinspector.tf
│ ├── awsguarduty.tf
│ ├── awswaf.tf
│ └── ...
├── 5_network
│ ├── account.tf
│ ├── dns_remote_zone_auth.tf
│ ├── dns.tf
│ ├── network.tf
│ ├── network_vpc_peering_dev.tf
│ ├── ...
├── 6_notifications
│ ├── ...
├── 7_containers
│ ├── account.tf
│ ├── container_registry.tf
│ ├── ...
├── config
│ ├── backend.config
│ └── main.config
└── readme.md
인프라를 오케스트레이션하기 위해 terraform을 사용하는 동안 따라야 할 모범 사례가 거의 없다고 생각합니다.
- 동일한 코드를 다시 작성하지 마십시오 (재사용 성).
- 쉽게 유지할 수 있도록 환경 구성을 별도로 유지하십시오.
- 원격 백엔드 s3 (암호화) 및 dynamo DB를 사용하여 동시성 잠금 처리
- 다른 매개 변수를 전달하여 여러 번 호출 할 수있는 재사용 가능한 함수처럼 모듈을 생성하고 기본 인프라에서 해당 모듈을 여러 번 사용합니다.
여러 환경 처리
대부분의 권장 방법은 terraform '작업 공간'을 사용하여 여러 환경을 처리하는 것이지만 작업 공간의 사용은 조직의 작업 방식에 따라 다를 수 있다고 생각합니다. 다른 하나는 각 환경 (예 : 스테이지, 제품, QA)에 대한 Terraform 코드를 저장하여 환경 상태를 분리하는 것입니다. 그러나이 경우에는 여러 위치에서 동일한 코드를 복사하고 있습니다.
├── main.tf
├── dev
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
└── prod
├── main.tf
├── output.tf
└── variables.tf
대부분의 경우 모든 환경이 90 % 동일 할 것이라고 믿기 때문에 각 환경 폴더에 보관하여 동일한 테라 폼 코드의 중복을 처리하고 방지하기 위해 몇 가지 다른 접근 방식을 따랐습니다.
├── deployment
│ ├── 01-network.tf
│ ├── 02-ecs_cluster.tf
│ ├── 03-ecs_service.tf
│ ├── 04-eks_infra.tf
│ ├── 05-db_infra.tf
│ ├── 06-codebuild-k8s.tf
│ ├── 07-aws-secret.tf
│ ├── backend.tf
│ ├── provider.tf
│ └── variables.tf
├── env
│ ├── dev
│ │ ├── dev.backend.tfvar
│ │ └── dev.variables.tfvar
│ └── prod
│ ├── prod.backend.tfvar
│ └── prod.variables.tfvar
├── modules
│ └── aws
│ ├── compute
│ │ ├── alb_loadbalancer
│ │ ├── alb_target_grp
│ │ ├── ecs_cluster
│ │ ├── ecs_service
│ │ └── launch_configuration
│ ├── database
│ │ ├── db_main
│ │ ├── db_option_group
│ │ ├── db_parameter_group
│ │ └── db_subnet_group
│ ├── developertools
│ ├── network
│ │ ├── internet_gateway
│ │ ├── nat_gateway
│ │ ├── route_table
│ │ ├── security_group
│ │ ├── subnet
│ │ ├── vpc
│ └── security
│ ├── iam_role
│ └── secret-manager
└── templates
환경과 관련된 구성
환경 관련 구성 및 매개 변수를 변수 파일에 별도로 보관하고 해당 값을 전달하여 인프라를 구성하십시오. 예 : 아래와 같이
dev.backend.tfvar
region = "ap-southeast-2"
bucket = "dev-samplebackendterraform"
key = "dev/state.tfstate"
dynamo_db_lock = "dev-terraform-state-lock"
dev.variable.tfvar
environment = "dev"
vpc_name = "demo"
vpc_cidr_block = "10.20.0.0/19"
private_subnet_1a_cidr_block = "10.20.0.0/21"
private_subnet_1b_cidr_block = "10.20.8.0/21"
public_subnet_1a_cidr_block = "10.20.16.0/21"
public_subnet_1b_cidr_block = "10.20.24.0/21"
인프라 부분의 조건부 건너 뛰기
환경 특정 변수 파일에 구성을 만들고 해당 변수를 기반으로 해당 부분을 만들거나 건너 뛰기로 결정합니다. 이러한 방식으로 필요에 따라 인프라의 특정 부분을 건너 뛸 수 있습니다.
variable vpc_create {
default = "true"
}
module "vpc" {
source = "../modules/aws/network/vpc"
enable = "${var.vpc_create}"
vpc_cidr_block = "${var.vpc_cidr_block}"
name = "${var.vpc_name}"
}
resource "aws_vpc" "vpc" {
count = "${var.enable == "true" ? 1 : 0}"
cidr_block = "${var.vpc_cidr_block}"
enable_dns_support = "true"
enable_dns_hostnames = "true"
}
각 환경에 대한 인프라 변경을 초기화하고 실행하려면 아래 명령이 필요합니다. 필요한 환경 폴더로 cd합니다.
terraform init -var-file=dev.variables.tfvar -backend-config=dev.backend.tfvar ../../deployment/
terraform apply -var-file=dev.variables.tfvar ../../deployment
하위 폴더의 아이디어가 마음에 들지 않습니다. 환경마다 소스가 달라지고 표류하는 경향이 있기 때문입니다.
더 나은 접근 방식은 모든 환경 (dev, preprod 및 prod)에 대해 단일 스택을 사용하는 것입니다. 단일 환경에서 작업하려면 terraform workspace
.
terraform workspace new dev
그러면 새 작업 공간이 생성됩니다. 여기에는 전용 상태 파일과 terraform.workspace
코드에서 사용할 수 있는 변수가 포함 됩니다.
resource "aws_s3_bucket" "bucket" {
bucket = "my-tf-test-bucket-${terraform.workspace}"
}
이렇게하면 버킷이 호출됩니다.
위의 작업 공간에 적용한 후 ( terraform workspace select <WORKSPACE>
환경 변경에 사용 ). 코드를 다중 지역에서 증명하려면 다음과 같이하십시오.
data "aws_region" "current" {}
resource "aws_s3_bucket" "bucket" {
bucket = "my-tf-test-bucket-${data.aws_region.current.name}-${terraform.workspace}"
}
얻기 위해 (us-east-1 지역의 경우)
따라야 할 몇 가지 Terraform 모범 사례 :
하드 코딩 방지 : 때때로 개발자가 직접 리소스를 수동으로 생성했습니다. 이러한 리소스를 표시하고 terraform 가져 오기를 사용하여 코드에 포함해야합니다. 샘플:
account_number =“123456789012 "account_alias ="mycompany "
Docker 컨테이너에서 Terraform 실행 : Terraform은 실행할 수있는 버전을 쉽게 제어 할 수있는 공식 Docker 컨테이너를 출시합니다.
CI / CD 파이프 라인에서 빌드 작업을 설정할 때 Terraform Docker 컨테이너를 실행하는 것이 좋습니다.
TERRAFORM_IMAGE=hashicorp/terraform:0.11.7
TERRAFORM_CMD="docker run -ti --rm -w /app -v ${HOME}/.aws:/root/.aws -v ${HOME}/.ssh:/root/.ssh -v `pwd`:/app $TERRAFORM_IMAGE"
자세한 내용은 내 블로그를 참조하십시오 : https://medium.com/tech-darwinbox/how-darwinbox-manages-infrastructure-at-scale-with-terraform-371e2c5f04d3
이 스레드에 기여하고 싶습니다.
일부 특별한 경우에는 Terraform 상태 파일에 대한 수동 액세스가 필요합니다. 리팩토링, 변경 중단 또는 결함 수정과 같은 작업을 수행하려면 운영 담당자가 Terraform 상태 작업을 실행해야합니다. 이러한 경우 배스 천 호스트, VPN 등을 사용하여 Terraform 상태에 대한 특별 제어 액세스를 계획하십시오.
CI / CD 파이프 라인에 대한 지침을 포함하여 자세한 내용을 다루는 더 긴 모범 사례 블로그 를 확인하십시오 .
여전히 더 나은 솔루션을 찾고 있다면, 다른 환경 폴더 구조를 유지하는 대신 작업 공간 별 변수를 가질 수있는 작업 공간을 살펴보십시오.
로 예브게니 Brikman가 언급 그것은 모듈 구조를 가지고하는 것이 좋습니다.