수업 69일차 테라폼 상태관리하기 , 파일 레이아웃

유동우·2022년 12월 31일
1

■ 테라폼 상태관리하기

mkdir terraform-state

cd terraform-state

vim main.tf

1 terraform {
2 required_version = ">= 1.0.0, < 2.0.0"
3
4 required_providers {
5 aws = {
6 source = "hashicorp/aws"
7 version = "~> 4.0"
8 }
9 }
10 }
11 provider "aws" {
12 region = "ap-northeast-2"
13 }
14
15 resource "aws_s3_bucket" "terraform_state" {
16 bucket = "aws08-terraform-state"
17
18 # 실수로 S3 버킷을 삭제하는 것을 방지한다.
19 lifecycle {
20 prevent_destroy = true
21 }
22
23 # 코드 이력을 관리하기 위해 상태 파일의 버전 관리를 활성화한다.
24
25 versioning {
26 enabled = true
27 }
28
29 # 서버측 암호화를 활성화한다.
30
31 server_side_encryption_configuration {
32 rule {
33 apply_server_side_encryption_by_default {
34 sse_algorithm = "AES256"
35 }
36 }
37 }
38 }

============================

※ 삭제방지하고싶지않을때

18 # 실수로 S3 버킷을 삭제하는 것을 방지한다.
19 # lifecycle {
20 # prevent_destroy = true
21 # }
22
23 lifecycle {
24 prevent_destroy = false
25 }
26 force_destroy = true

=============================

※ dynamodb 리소스추가

46 resource "aws_dynamodb_table" "terraform_locks" {
47 name = "aws-08-terraform-locks"
48 billing_mode = "PAY_PER_REQUEST"
49 hash_key = "LockID"
50
51 attribute {
52 name = "LockID"
53 type = "S"
54 }
55 }

================

※ 파일위치정리

mkdir global

mkdir global/s3

mv . global/s3

mv .* global/s3/

=> global의 s3에 main.tf에는 S3 버킷이랑 dynamodb 구성

==================

mkdir stage

mkdir stage/services

mkdir stage/services/webserver-cluster

cd stage/services/webserver-cluster

vim main.tf

1 terraform {
2 required_version = ">= 1.0.0, < 2.0.0"
3
4 required_providers {
5 aws = {
6 source = "hashicorp/aws"
7 version = "~> 4.0"
8 }
9 }
10 backend "s3" {
11
12 # 이전에 생성한 버킷 이름으로 변경
13 bucket = "aws08-terraform-state"
14 key = "global/s3/terraform.tfstate"
15 region = "ap-northeast-2"
16
17 # 이전에 생성한 다이나모DB 테이블 이름으로 변경
18 dynamodb_table = "terraform-locks"
19 encrypt = true
20 }
21 }
22
23 provider "aws" {
24 region = "ap-northeast-2"
25 }

=> webserver-cluster에 main.tf에는 S3버킷에 대한 backend 구성

============================================

~/01-terraform/terraform-state/global/s3

vim output.tf

1 output "s3_bucket_arn" {
2 value = aws_s3_bucket.terraform_state.arn
3 description = "The ARN of the S3 bucket"
4 }
5 output "dynamodb_table_name" {
6 value = aws_dynamodb_table.terraform_locks.name
7 description = "The name of the DynamoDB table"
8 }

:e variables.tf

1 variable "bucket_name" {
2 description = "The name of the S3 bucket. Must be globally unique."
3 type = string
4 default = "aws08-terraform-state"
5 }
6
7 variable "table_name" {
8 description = "The name of the DynamoDB table. Must be unique in this AWS acc ount."
9 type = string
10 default = "aws08-terraform-locks"
11 }

=============================

vim main.tf // DynamoDB 생성

1 terraform {
2 required_version = ">= 1.0.0, < 2.0.0"
3
4 required_providers {
5 aws = {
6 source = "hashicorp/aws"
7 version = "~> 4.0"
8 }
9 }
10 }
11
12 provider "aws" {
13 region = "ap-northeast-2"
14 }
15
16 resource "aws_s3_bucket" "terraform_state" {
17
18 bucket = var.bucket_name
19
20 // 버킷을 삭제할 수 있게 한다.
21 force_destroy = true
22
23 }
24
25 # 상태 파일의 전체 리비전 기록을 볼 수 있도록 버전 지정
26 resource "aws_s3_bucket_versioning" "enabled" {
27 bucket = aws_s3_bucket.terraform_state.id
28 versioning_configuration {
29 status = "Enabled"
30 }
31 }
32
33 # 기본적으로 서버측 암호화 사용
34 resource "aws_s3_bucket_server_side_encryption_configuration" "default" {
35 bucket = aws_s3_bucket.terraform_state.id
36
37 rule {
38 apply_server_side_encryption_by_default {
39 sse_algorithm = "AES256"
40 }
41 }
42 }
43
44 # S3 버킷에 대한 모든 공용 액세스를 명시적으로 차단
45 resource "aws_s3_bucket_public_access_block" "public_access" {
46 bucket = aws_s3_bucket.terraform_state.id
47 block_public_acls = true
48 block_public_policy = true
49 ignore_public_acls = true
50 restrict_public_buckets = true
51 }
52
53 resource "aws_dynamodb_table" "terraform_locks" {
54 name = var.table_name
55 billing_mode = "PAY_PER_REQUEST"
56 hash_key = "LockID"
57
58 attribute {
59 name = "LockID"
60 type = "S"
61 }
62 }

============================================

~/01-terraform/terraform-state/stage/services/webserver-cluster

rm -rf main.tf

cp ~/01-terraform/web-cluster/*.tf .

ls 하면 main.tf outputs.tf variables.tf 복사한 tf파일 나옴

~/01-terraform/terraform-state/stage

mkdir data-stores

mkdir data-stores/mysql

cd data-stores/mysql

vim main.tf // RDS에 데이터베이스 생성

1 terraform {
2 required_version = ">= 1.0.0, < 2.0.0"
3 required_providers {
4 aws = {
5 source = "hashicorp/aws"
6 version = "~> 4.0"
7 }
8 }
9 backend "s3" {
10 # 이전에 생성한 버킷 이름으로 변경
11 bucket = "aws08-terraform-state"
12 key = "workspace-example/terraform.tfstate"
13 region = "ap-northeast-2"
14 # 이전에 생성한 다이나모DB 테이블 이름으로 변경
15 dynamodb_table = "aws08-terraform-locks"
16 encrypt = true
17 }
18 }
19 provider "aws" {
20 region = "ap-northeast-2"
21 }
22
23 # RDS에 데이터베이스를 생성한다.
24 resource "aws_db_instance" "example" {
25 identifier_prefix = "aws08-terraform-example"
26 engine = "mysql"
27 allocated_storage = 10 # 스토리지는 10GB
28 instance_class = "db.t2.micro" # vCPU 1개, 1GB 메모리
29 skip_final_snapshot = true
30
31 name = var.db_name
32 username = var.db_username
33 password = var.db_password
34 }

:e variabels.tf

1 variable "db_username" {
2 description = "The username for the database"
3 type = string
4 sensitive = true
5 default = "admin"
6 }
7 variable "db_password" {
8 description = "The password for the database"
9 type = string
10 sensitive = true
11 default = "password"
12 }
13 variable "db_name" {
14 description = "The name to use for the database"
15 type = string
16 default = "example_database_stage"
17 }

===========================

■ 파일 레이아웃을 이용한 격리

terraform-state

┌ stage - ┌ services - webserver-cluster
│ └ data-stores - mysql
└ global - s3

apply하면
terraform.tfstate // 상태파일생성됨

backend에 상태파일 생성

s3가 backend 역할수행중

S3 버킷과 다이나모DB 테이블을 삭제하려면 이 단계를 반대로 수행한다.
1. 테라폼 코드로 이동하여 backend 구성을 제거한 다음 terraform init 명령을 재실행하여 테라폼 상
태를 로컬 디스크에 다시 복사한다.
2. terraform destroy 명령을 실행하여 S3 버킷 및 다이나모DB 테이블을 삭제한다.
3. 이 때 S3 버킷이 비어있지 않고 lifecycle이 삭제 불가로 되어있어 삭제가 되지 않으면 lifecycle 블
록의 prevent_destroy를 false로 변경하고 aws_s3_bucket 리소스에 force_destroy = true 를
추가한 후 terraform init, terraform apply를 실행하고 terraform destroy 명령을 실행한다.

※ backend 블록에서는 변수나 참조를 사용할 수 없다

===================================

● stage
테스트 환경과 같은 사전 프로덕션 워크로드 환경

● prod
사용자용 맵 같은 프로덕션 워크로드 환경

● mgmt
베스천 호스트, 젠킨스와 같은 데브옵스 도구 환경테라폼 상태 관리하기 18

● global
S3, IAM과 같이 모든 환경에서 사용되는 리소스를 배치할 수 있는 장소
각 환경에는 구성 요소마다 별도의 폴더가 있다. 프로젝트마다 구성 요소가 다르지만 일반적인 구성 요
소는 다음과 같다.

● vpc
해당 환경을 위한 네트워크 토폴로지

● services
루비 온 레일즈 프런트앤드 또는 스칼라 백엔드 같이 해당 환경에서 서비스되는 애플리케이션 또는
마이크로서비스. 각각의 앱은 자체 폴더에 위치하여 다른 모든 앱과 분리할 수 있다.

● data-storage

MySQL 또는 레디스와 같은 해당 환경에서 실행할 데이터 저장소. 각 데이터 저장소는 자체 폴더에
상주하여 다른 모든 데이터 저장소와 분리할 수 있다.
각 구성 요소에는 다음과 같은 명명 규칙에 따라 구성되는 실제 테라폼 구성 파일이 있다.

● variables.tf : 입력 변수

● output.tf : 출력 변수

● main.tf : 리소스

=========================

~/01-terraform/terraform-state/stage/services/webserver-cluster

vim main.tf

1 terraform {
2 # 테라폼 버전 지정
3 required_version = ">=1.0.0, <2.0.0"
4
5 # 공급자 버전 지정
6 required_providers {
7 aws = {
8 source = "hashicorp/aws"
9 version = "~> 4.0"
10 }
11 }
12 }
13
14 provider "aws" {
15 region = "ap-northeast-2"
16 }
17
18 # 시작 템플릿 설정
19 resource "aws_launch_template" "example" {
20 image_id = "ami-0ab04b3ccbadfae1f" # Ubuntu 20.04 version
21 instance_type = "t2.micro"
22 key_name = "aws08-key"
23 vpc_security_group_ids = [aws_security_group.instance.id]
24
25 user_data = base64encode(data.template_file.web_output.rendered)
26
27 lifecycle {
28 create_before_destroy = true
29 }
30
31 }
32
33 # 오토스케일링 생성
34 resource "aws_autoscaling_group" "example" {
35 availability_zones = ["ap-northeast-2a", "ap-northeast-2c"]
36
37 name = "aws08-terraform-asg-example"
38 desired_capacity = 1
39 min_size = 1
40 max_size = 2
41
42 target_group_arns = [aws_lb_target_group.asg.arn]
43 health_check_type = "ELB"
44
45 launch_template {
46 id = aws_launch_template.example.id
47 version = "$ Latest"
48 }
49 tag {
50 key = "Name"
51 value = "aws08-terraform-asg-example"
52 propagate_at_launch = true
53 }
54 }
55
56 # 로드밸런서
57 resource "aws_lb" "example" {
58 name = "aws08-terraform-asg-example"
59 load_balancer_type = "application"
60 subnets = data.aws_subnets.default.ids
61 security_groups = [aws_security_group.alb.id]
62 }
63
64
65 # 로드밸런서 리스너
66 resource "aws_lb_listener" "http" {
67 load_balancer_arn = aws_lb.example.arn
68 port = 80
69 protocol = "HTTP"
70
71 # 기본값으로 단순한 404 페이지 오류를 반환한다.
72 default_action {
73 type = "fixed-response"
74 fixed_response {
75 content_type = "text/plain"
76 message_body = "404: page not found"
77 status_code = 404
78 }
79 }
80 }
81
82 # 로드 밸런서 리스너 룰 구성
83
84 resource "aws_lb_listener_rule" "asg" {
85 listener_arn = aws_lb_listener.http.arn
86 priority = 100
87
88 condition {
89 path_pattern {
90 values = ["*"]
91 }
92 }
93 action {
94 type = "forward"
95 target_group_arn = aws_lb_target_group.asg.arn
96 }
97 }
98
99
100
101 # 로드밸런서 대상그룹
102
103 resource "aws_lb_target_group" "asg" {
104 name = "aws08-terraform-asg-example"
105 port = var.server_port
106 protocol = "HTTP"
107 vpc_id = data.aws_vpc.default.id
108
109 health_check {
110 path = "/"
111 protocol = "HTTP"
112 matcher = "200"
113 interval = 15
114 timeout = 3
115 healthy_threshold = 2
116 unhealthy_threshold = 2
117 }
118 }
119
120
121 # 보안그룹 - instance
122 resource "aws_security_group" "instance" {
123 name = "var.security_group_name"
124
125 ingress {
126 from_port = var.server_port
127 to_port = var.server_port
128 protocol = "tcp"
129 cidr_blocks = ["0.0.0.0/0"]
130 }
131 }
132
133
134
135 # 보안 그룹 - ALB
136 resource "aws_security_group" "alb" {
137 name = "aws08-terraform-example-alb"
138
139
140 # 인바운드 HTTP 트래픽 허용
141 ingress {
142 from_port = 80 # 출발 포트
143 to_port = 80 # 도착 포트
144 protocol = "tcp" # 프로토콜
145 cidr_blocks = ["0.0.0.0/0"] # # 송신지
146 }
147
148 # 모든 아웃바운드 트래픽 허용
149 egress {
150 from_port = 0 # 출발 포트
151 to_port = 0 # 도착 포트
152 protocol = "-1" # 프로토콜
153 cidr_blocks = ["0.0.0.0/0"] # # 송신지
154 }
155 }
156
157 data "terraform_remote_state" "db" {
158
159 backend = "s3"
160
161 config = {
162 bucket = "aws08-terraform-state"
163 key = "stage/data-stores/mysql/terraform.tfstate"
164 region = "ap-northeast-2"
165 }
166 }
168 # Default VPC 정보 가지고 오기
169 data "aws_vpc" "default" {
170 default = true
171 }
172
173 # Subnet 정보 가지고 오기
174 data "aws_subnets" "default" {
175 filter {
176 name = "vpc-id"
177 values = [data.aws_vpc.default.id]
178 }
179 }
180
181 data "template_file" "web_output" { // 외부 파일을 읽을 수 있게해줌
182 template = file("${path.module}/user-data.sh")
183 vars = {
184 server_port = var.server_port
185 db_address = data.terraform_remote_state.db.outputs.address
186 db_port = data.terraform_remote_state.db.outputs.port
187 }
188 }

:e outputs.tf

1 # outputs.tf
2 output "alb_dns_name" {
3 value = aws_lb.example.dns_name
4 description = "The domain name of the load balancer"
5 }

:e variables.tf

1 variable "server_port" {
2 description = "The port will use for HTTP requests"
3 type = number
4 default = 8080
5 }
6
7 variable "sercurity_group_name" {
8 type = string
9 default = "aws08-terraform-example-instance"
10 }

profile
클라우드 엔지니어가 되고싶은 클린이

0개의 댓글