Post

Terraform Study #1

โ€˜ํ…Œ๋ผํผ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” IaCโ€™ ์ฑ…์œผ๋กœ ์ง„ํ–‰ํ•˜๋Š” Terraform ์Šคํ„ฐ๋””[T101] 1์ฃผ์ฐจ ์ •๋ฆฌ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

1์ฃผ์ฐจ

ํ‰์†Œ์— ํ…Œ๋ผํผ์— ๊ด€์‹ฌ์ด ๋งŽ์•„, ์ž๊ฒฉ์ฆ๋„ ์ทจ๋“ํ•˜๊ณ  ๊ณต๋ถ€๋ฅผ ํ–ˆ๋‹ค. ๊ณต๋ถ€๋ฅผ ํ–ˆ์ง€๋งŒ, ์•„์ง ์ด๊ฒƒ์ €๊ฒƒ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๊ฒŒ ๋งŽ๋‹ค. ์ด๋ฅผ ๊ตฌ์ฒดํ™”์‹œํ‚ค๊ณ , ์‹ค๋ฌด์— ๋Œ€ํ•œ ์กฐ์–ธ์„ ๋“ค์„ ๊ฒธ ์Šคํ„ฐ๋””์— ์ฐธ๊ฐ€ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์Šคํ„ฐ๋””๋Š” CloudNet์—์„œ ์ฃผ๊ด€ํ•˜๊ณ  ์œ ํ˜•์šฑ๋‹˜๊ณผ ์œค์„œ์œจ๋‹˜์ด ์ง„ํ–‰ํ•ด์ฃผ์‹ ๋‹ค.

1์ฃผ์ฐจ์—์„œ๋Š” ํ…Œ๋ผํผ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ , ์‹คํ–‰ ํ™˜๊ฒฝ์„ ์„ธํŒ…ํ•œ๋‹ค. ์ดํ›„ EC2๋ฅผ ๋ฐฐํฌํ•ด๋ณด๋ฉด์„œ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•๊ณผ ๋ช…๋ น์–ด์— ๋Œ€ํ•ด ํ•™์Šตํ•œ๋‹ค.

ํ…Œ๋ผํผ ์ œ๊ณต์œ ํ˜•

  1. On-premise : Terraform์ด๋ผ ๋ถˆ๋ฆฌ๋Š” ํ˜•ํƒœ๋กœ, ์‚ฌ์šฉ์ž์˜ ์ปดํ“จํŒ… ํ™˜๊ฒฝ์— ์˜คํ”ˆ์†Œ์Šค ๋ฐ”์ด๋„ˆ๋ฆฌํˆด์ธ ํ…Œ๋ผํผ์„ ํ†ตํ•ด ์‚ฌ์šฉ

    [๋ผ์ด์„ ์Šค๋ฅผ ๋ณ€๊ฒฝ] ์˜คํ”ˆ์†Œ์Šค โ†’ ์ปค๋ฎค๋‹ˆํ‹ฐ ์—๋””์…˜์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.

  2. Hosted SaaS : Terraform Cloud๋กœ ๋ถˆ๋ฆฌ๋Š” SaaS๋กœ ์ œ๊ณต๋˜๋Š” ๊ตฌ์„ฑ ํ™˜๊ฒฝ์œผ๋กœ ํ•˜์‹œ์ฝ”ํ”„๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์„œ๋ฒ„ ํ™˜๊ฒฝ์ด ์ œ๊ณต
  3. Private Install : Terraform Enterprise๋กœ ๋ถˆ๋ฆฌ๋Š” ์„œ๋ฒ„ ์„ค์น˜ํ˜• ๊ตฌ์„ฑ ํ™˜๊ฒฝ์œผ๋กœ, ๊ธฐ์—…์˜ ์‚ฌ๋‚ด ์ •์ฑ…์— ๋”ฐ๋ผ ํ”„๋กœ๋น„์ €๋‹ ๊ด€๋ฆฌ๊ฐ€ ์™ธ๋ถ€ ๋„คํŠธ์›Œํฌ์™€ ๊ฒฉ๋ฆฌ - ๋งํฌ

2,3 ๋ฒˆ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ GUI๊ฐ€ ์ œ๊ณต๋˜๋ฉฐ Terraform Cloud๋Š” Free ํ‹ฐ์–ด๊ฐ€ ์žˆ๋‹ค.

ํ…Œ๋ผํผ ํด๋ผ์šฐ๋“œ ๊ฐ€๊ฒฉ์ •์ฑ… ๋น„๊ต

  • Free : ๋ฆฌ์†Œ์Šค 500๊ฐœ ๊นŒ์ง€ ๋ฌด๋ฃŒ โ†’ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฒ„์ „
  • Standard : Free + ์›Œํฌํ”Œ๋กœ์šฐ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ + ๋™์‹œ์‹คํ–‰(Concurrency ๊ฐœ์ˆ˜ 3๊ฐœ)

AWS ์˜ต์…˜(์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑ)

AWS_PAGER ์˜ต์…˜ ์ œ๊ฑฐ

  • ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€์ฒ˜๋Ÿผ, ์ž‘๋™ํ•จ โ†’ ๋‚˜๊ฐˆ๋ ค๋ฉด :q ์˜ต์…˜์„ ์ž…๋ ฅํ•ด์•ผ ํ•˜๊ณ , ๊ธฐํƒ€ ์˜ต์…˜๋„ ์“ธ ์ˆ˜ ์žˆ๋Š”๋‹ค.

ํŽ˜์ด์ €๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ์ด์œ ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. Scripting and Automation: AWS CLI ๋ช…๋ น์–ด์˜ ์ถœ๋ ฅ์„ ์Šคํฌ๋ฆฝํŠธ๋‚˜ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ์—์„œ ํŒŒ์‹ฑํ•ด์•ผ ํ•  ๊ฒฝ์šฐ, ํŽ˜์ด์ €๊ฐ€ ๋ถˆํ•„์š”ํ•œ ์ค‘๊ฐ„ ๋‹จ๊ณ„๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. Non-Interactive Environments: CI/CD ํŒŒ์ดํ”„๋ผ์ธ์ด๋‚˜ ๋ฐฐ์น˜ ์ž‘์—…๊ณผ ๊ฐ™์€ ๋น„๋Œ€ํ™”ํ˜•(non-interactive) ํ™˜๊ฒฝ์—์„œ๋Š” ํŽ˜์ด์ €๊ฐ€ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export AWS_PAGER=""

์ ์šฉํ•˜๋ฉด, PAGER๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋œ๋‹ค.

AWS ๊ณ„์ • ์„ ํƒ

์—ฌ๋Ÿฌ AWS ๊ณ„์ •์„ ์“ฐ๋Š” ๊ฒฝ์šฐ, Profile์„ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.

export AWS_PROFILE="study"

Terraform์—์„œ๋„ ๋ณ„๋„์˜ provider block์—์„œ ์„ธํŒ…ํ•ด์ค˜์•ผํ•œ๋‹ค.

1
2
3
4
provider "aws" {
  profile = "eks"
  region  = "ap-northeast-2"
}

์ถ”๊ฐ€) vscode aws toolkit ์„ค์ •์œผ๋กœ, ํ˜„์žฌ์˜ profile์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๋Ÿฌ AWS ๊ณ„์ •์„ ์“ธ ๊ฒฝ์šฐ, ํŽธ๋ฆฌํ•˜๋‹ค.

HCL

HCL์€ JSON์„ ๋ณธ๋”ฐ ๋งŒ๋“  ์–ธ์–ด์ด๋ฉฐ, JSON๋ณด๋‹ค ์‚ฌ๋žŒ ์นœํ™”์ ์ธ ์–ธ์–ด์ด๋‹ค.

  • ์ธํ”„๋ผ๊ฐ€ ์ฝ”๋“œ๋กœ ํ‘œํ˜„๋˜๊ณ , ์ด ์ฝ”๋“œ๋Š” ๊ณง ์ธํ”„๋ผ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„ ์–ธ์ (declarative) ํŠน์„ฑ์„ ๊ฐ–๊ฒŒ ๋˜๊ณ  ํŠœ๋ง ์™„์ „ํ•œ Turing-complete ์–ธ์–ด์  ํŠน์„ฑ์„ ๊ฐ–๋Š”๋‹ค. [์ฐธ๊ณ : ํŠœ๋ง์™„์ „]
  • ์ฆ‰, ์ผ๋ฐ˜์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์˜ ์กฐ๊ฑด๋ฌธ ์ฒ˜๋ฆฌ ๊ฐ™์€ ๋™์ž‘์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ž๋™ํ™”์™€ ๋”๋ถˆ์–ด, ์‰ฝ๊ฒŒ ๋ฒ„์ €๋‹ํ•ด ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ํ•จ๊ป˜ ์ž‘์—… ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ฐ˜์„ ์ œ๊ณต. โ†’ ํ™•์‹คํ•œ ์ฐจ์ด์ 

Terraform Command ์˜ต์…˜

  • validate
    • -no-color : ๋Œ€๋ถ€๋ถ„์˜ ๋ช…๋ น๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ, ๋กœ์ปฌ์ด ์•„๋‹Œ ์™ธ๋ถ€ ์‹คํ–‰ ํ™˜๊ฒฝ(์  ํ‚จ์Šค, Terraform Cloud, Github Action ๋“ฑ)์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์ƒ‰์ƒ ํ‘œ๊ธฐ ๋ฌธ์ž๊ฐ€ ํ‘œ๊ธฐ ๋  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ -no-color ์˜ต์…˜์œผ๋กœ ์ƒ‰์ƒ ํ‘œ๊ธฐ ๋ฌธ์ž ์—†์ด ์ถœ๋ ฅํ•จ. [์ฐธ๊ณ ]
  • plan
    • -detailed-exitcode : plan ์ถ”๊ฐ€ ์˜ต์…˜์œผ๋กœ, ํŒŒ์ดํ”„๋ผ์ธ ์„ค๊ณ„์—์„œ ํ™œ์šฉ ๊ฐ€๋Šฅ, exitcode๊ฐ€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ๊ตฌ์„ฑ๋จ
  • apply or destroy
    • -auto-approve: ์ž๋™ ์Šน์ธ ๊ธฐ๋Šฅ ๋ถ€์—ฌ ์˜ต์…˜

EC2 ๋ฐฐํฌ

์šฐ์„ , ํ•ด๋‹น ์‹ค์Šต์—์„œ๋Š” default VPC๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉํ•˜๋Š” ๋ฆฌ์ „์˜ default VPC๊ฐ€ ์—†๋‹ค๋ฉด ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ƒ์„ฑํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
$ aws ec2 create-default-vpc
{
    "Vpc": {
        "CidrBlock": "172.31.0.0/16",
        ...
        ],
        "IsDefault": true,
        "Tags": []
    }
}

EC2๋ฅผ ํ”„๋กœ๋น„์ €๋‹ํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ์ฝ”๋“œ์ด๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, EC2๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ ‘์†ํ•  public IP๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "example" {
  ami                    = "ami-0c9c942bd7bf113a2"
  instance_type          = "t2.micro"
  **vpc_security_group_ids = [aws_security_group.instance.id]**

  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, T101 Study" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF

  tags = {
    Name = "Single-WebSrv"
  }
}

resource "aws_security_group" "instance" {
  name = var.security_group_name

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance"
}

**output** "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}
1
2
3
4
5
6
7
$ tf apply
...
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

public_ip = "54.180.106.217"

โ†’ user_data_replace_on_change = false ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•œ๋‹ค!

์ฝ”๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
resource "aws_instance" "example" {
  ami                    = "ami-0c9c942bd7bf113a2"
	...

  user_data_replace_on_change = false
  tags = {
    Name = "Single-WebSrv"
  }
}
...
resource "aws_security_group" "instance" {
  name = var.security_group_name
	...
	# lifecycle์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‹ค์šดํƒ€์ž„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
	lifecycle {
    create_before_destroy = true
  }
}

๋ณ€๊ฒฝํ•˜๊ธฐ ์ด์ „๊ณผ ์ดํ›„์— ์ƒ์„ฑ๊ณผ์ •์„ ๋ณด๋ฉด ๋‹ค๋ฅธ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ด์ „์ฒ˜๋Ÿผ ํŒŒ๊ดดํ•˜๊ณ  ์žฌ์ƒ์„ฑ์ด ์•„๋‹Œ, ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
# ์ด์ „
aws_security_group.instance: Destroying... [id=sg-03c90b3d559abb123]
aws_security_group.instance: Destruction complete after 1s
aws_security_group.instance: Creating...
aws_security_group.instance: Creation complete after 1s [id=sg-0de633908986b76ad]
# ๋ผ์ดํ”„์‚ฌ์ดํด ์ ์šฉ ํ›„
...
aws_security_group.instance: Modifying... [id=sg-0de633908986b76ad]
aws_security_group.instance: Modifications complete after 1s [id=sg-0de633908986b76ad]

์ฆ‰, โ€œuser_data_replace_on_change = falseโ€ ์˜ต์…˜์„ ํ†ตํ•ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ์„ค์ •์€ user_data๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ EC2 ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•  ๊ฒƒ์ธ์ง€, ์•„๋‹ˆ๋ฉด ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ์œ ์ง€ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค. false๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์œ ์ง€ํ•˜๋Š” ์˜ต์…˜์ด๋ฉฐ, ์ธ์Šคํ„ด์Šค๋ฅผ ์œ ์ง€ํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
# ์ ์šฉ ์ „
aws_instance.example: Destroying... [id=i-0794bd9bb343a948b]
...
aws_instance.example: Creating...

# "user_data_replace_on_change = false" ์ ์šฉ ํ›„
aws_instance.example: Modifying... [id=i-0568341d533d4ca58]
aws_instance.example: Still modifying... [id=i-0568341d533d4ca58, 10s elapsed]
aws_instance.example: Still modifying... [id=i-0568341d533d4ca58, 20s elapsed]

ํ…Œ๋ผํผ ๋ฌธ๋ฒ• ์„ค๋ช…

Terraform ๋ธ”๋ก, ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚ด์šฉ์„ ์ž˜ ์ •๋ฆฌํ•ด์ฃผ์…จ๋‹ค.

  • ์˜ค๋Š˜ ์‹คํ–‰ํ•˜๋˜, 3๋…„ ํ›„์— ์‹คํ–‰ํ•˜๋˜ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค! (Desired State + Immutable)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
terraform {
  required_version = "~> 1.3.0" # ํ…Œ๋ผํผ ๋ฒ„์ „

  required_providers { # ํ”„๋กœ๋ฐ”์ด๋” ๋ฒ„์ „์„ ๋‚˜์—ด
    random = {
      version = ">= 3.0.0, < 3.1.0"
    }
    aws = {
      version = "4.2.0"
    }
  }

  cloud { # Cloud/Enterprise ๊ฐ™์€ ์›๊ฒฉ ์‹คํ–‰์„ ์œ„ํ•œ ์ •๋ณด [์ฐธ๊ณ : Docs]
    organization = "<MY_ORG_NAME>"
    workspaces {
      name = "my-first-workspace"
    }
  }

  backend "local" { # state๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ์œ„์น˜๋ฅผ ์ง€์ • [์ฐธ๊ณ : Docs, local, remote, s3]
    path = "relative/path/to/terraform.tfstate"
  }
}
  • ํ…Œ๋ผํผ 0.13 ๋ฒ„์ „ ์ด์ „์—๋Š” provider ๋ธ”๋ก์— ํ•จ๊ป˜ ๋ฒ„์ „์„ ๋ช…์‹œํ–ˆ์ง€๋งŒ ํ•ด๋‹น ๋ฒ„์ „ ์ดํ›„ ํ”„๋กœ๋ฐ”์ด๋” ๋ฒ„์ „์€ terraform ๋ธ”๋ก์—์„œ required_providers์— ์ •์˜
1
2
3
4
5
6
7
8
9
terraform {
  cloud {
    hostname = "[app.terraform.io](http://app.terraform.io/)"
    organization = "my-org"
    workspades = {
       name = "my-app-prod"
    }
  }
}

Backend

ํ˜‘์—…์„ ์œ„ํ•ด์„œ๋Š” s3 ๋“ฑ ์›๊ฒฉ์œผ๋กœ ์ €์žฅํ•ด์„œ ๊ด€๋ฆฌํ•จ, ๊ธฐ๋ณธ์ ์œผ๋กœ lock์„ ์ง€์›ํ•œ๋‹ค. ๋กœ์ปฌ์—์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ, ๋กœ์ปฌ์—์„œ apply ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ์Šน์ธ์„ ๊ธฐ๋‹ค๋ฆด ๋•Œ ls -al ๋ช…๋ น์–ด๋กœ ์ž‘์—… ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ ํŒŒ์ผ์„ ํ™•์ธํ•˜๋ฉด .terraform.tfstate.lock.info ํŒŒ์ผ์ด ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
cat .terraform.tfstate.lock.info | jq .
{
  "ID": "b4dbfee6-a28f-04da-d235-5591414dbcbc",
  "Operation": "OperationTypeApply",
  "Info": "",
  "Who": "kane@kanes-MacBook-Pro.local",
  "Version": "1.5.6",
  "Created": "2023-08-27T14:07:14.110318Z",
  "Path": "terraform.tfstate"
}
  • ์ถ”๊ฐ€ ์˜ต์…˜1 (์ด์ „ ๊ตฌ์„ฑ ์œ ์ง€) : -migrate-state๋Š” terraform.tfstate์˜ ์ด์ „ ๊ตฌ์„ฑ์—์„œ ์ตœ์‹ ์˜ state ์Šค๋ƒ…์ƒท์„ ์ฝ๊ณ  ๊ธฐ๋ก๋œ ์ •๋ณด๋ฅผ ์ƒˆ ๊ตฌ์„ฑ์œผ๋กœ ์ „ํ™˜ํ•œ๋‹ค.
  • ์ถ”๊ฐ€ ์˜ต์…˜2 (์ƒˆ๋กœ ์ดˆ๊ธฐํ™”) : -reconfigure๋Š” init์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— terraform.tfstate ํŒŒ์ผ์„ ์‚ญ์ œํ•ด ํ…Œ๋ผํผ์„ ์ฒ˜์Œ ์‚ฌ์šฉํ•  ๋•Œ์ฒ˜๋Ÿผ ์ด ์ž‘์—… ๊ณต๊ฐ„(๋””๋ ‰ํ„ฐ๋ฆฌ)์„ ์ดˆ๊ธฐํ™” ํ•˜๋Š” ๋™์ž‘์ด๋‹ค.

.tfstate

Terraform์˜ .tfstate ํŒŒ์ผ ๋‚ด์˜ serial ๊ฐ’์€ ์ƒํƒœ ํŒŒ์ผ์˜ ๋ฒ„์ „์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋™์‹œ์„ฑ ์ œ์–ด์™€ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ํ™•์ธ์—๋„ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ Terraform ๋ช…๋ น์ด ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์ฆ๊ฐ€ํ•˜์—ฌ, ์ƒํƒœ ํŒŒ์ผ์˜ ์ตœ์‹ ์„ฑ๊ณผ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— backup ํŒŒ์ผ์ด ํ˜„์žฌ state ํŒŒ์ผ๋ณด๋‹ค serial ๋ฒˆํ˜ธ๊ฐ€ ๋‚ฎ๋‹ค.

๋„์ „๊ณผ์ œ1 (EC2 ์›น ์„œ๋ฒ„ ๋ฐฐํฌ)

์œ„์˜ EC2 ์‹ค์Šต์—์„œ user_data ๋ถ€๋ถ„๋งŒ ๋ณ€๊ฒฝํ–ˆ๋‹ค.

1
2
3
4
5
user_data = <<-EOF
              #!/bin/bash
              echo "T101 Study Kane" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF

๋„์ „๊ณผ์ œ2 (Backend)

AWS S3/DynamoDB ๋ฐฑ์—”๋“œ Backend๋Š” Terraform์˜ ์ƒํƒœํŒŒ์ผ์„ ์›๊ฒฉ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํŒ€ ๋‹จ์œ„์˜ ํ˜‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋งŒ์•ฝ, ๋กœ์ปฌ์— ์ƒํƒœํŒŒ์ผ์„ ์ €์žฅํ•˜๋ฉด ํŒ€์›๋“ค์ด ๋ณ€๊ฒฝํ•  ๋•Œ๋งˆ๋‹ค ์ƒํƒœํŒŒ์ผ์„ ์ฃผ๊ณ  ๋ฐ›์•„์•ผํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, ์ƒํƒœํŒŒ์ผ๊ณผ ์‹ค์ œ ์ธํ”„๋ผ์˜ ์ƒํƒœ๊ฐ€ ๋‹ฌ๋ผ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

Backend๋Š” ๋‹ค๋ฅธ ํŽธ์—์„œ ๋” ์ž์„ธํ•˜๊ฒŒ ๋‹ค๋ฃฌ๋‹ค.

์•„๋ž˜๋Š” ๊ด€๋ จ ์ฝ”๋“œ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
provider "aws" {
  profile = "eks"
  region  = "ap-northeast-2"
}

resource "aws_s3_bucket" "mys3bucket" {
  bucket = "kane-t101study-tfstate"
}

# Enable versioning so you can see the full revision history of your state files
resource "aws_s3_bucket_versioning" "mys3bucket_versioning" {
  bucket = aws_s3_bucket.mys3bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_dynamodb_table" "mydynamodbtable" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

output "s3_bucket_arn" {
  value       = aws_s3_bucket.mys3bucket.arn
  description = "The ARN of the S3 bucket"
}

output "dynamodb_table_name" {
  value       = aws_dynamodb_table.mydynamodbtable.name
  description = "The name of the DynamoDB table"
}

EC2๋ฅผ ๋ฐฐํฌํ•˜๋Š” ์ฝ”๋“œ์— ์•„๋ž˜์™€ ๊ฐ™์€ ์›๊ฒฉ backend๋ฅผ ์„ค์ •ํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
terraform {
  backend "s3" {
    bucket = "kane-t101study-tfstate"
    key    = "dev/terraform.tfstate"
    region = "ap-northeast-2"
    dynamodb_table = "terraform-locks"
    # encrypt        = true
  }
}

๋ฐฐํฌํ•œ ํ›„, AWS ์ฝ˜์†”์— ์ ‘์†ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด table์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ, s3๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋ฉฐ Terraform์„ ๋ฐฐํฌํ•˜์—ฌ state ํŒŒ์ผ์ด ์ •์ƒ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ์ง€ ํ™•์ธํ•œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
while true; do aws s3 ls s3://$NICKNAME-t101study-tfstate --recursive --human-readable --summarize ; echo "------------------------------"; date; sleep 1; done

Total Objects: 0
   Total Size: 0 Bytes
------------------------------
Mon Aug 28 00:50:18 KST 2023

Total Objects: 0
   Total Size: 0 Bytes
------------------------------
...
# ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ
------------------------------
Mon Aug 28 00:53:16 KST 2023
2023-08-28 00:50:56   21.1 KiB dev/terraform.tfstate

Total Objects: 1
   Total Size: 21.1 KiB
------------------------------
Mon Aug 28 00:53:17 KST 2023
2023-08-28 00:53:18   22.4 KiB dev/terraform.tfstate
------------------------------
...
# ๋ฆฌ์†Œ์Šค ์—…๋ฐ์ดํŠธ
------------------------------
Total Objects: 1
   Total Size: 22.4 KiB
------------------------------
# ๋ฆฌ์†Œ์Šค ์‚ญ์ œ
...
------------------------------
Mon Aug 28 00:56:04 KST 2023
2023-08-28 00:56:03  180 Bytes dev/terraform.tfstate

Total Objects: 1
   Total Size: 180 Bytes
------------------------------
Mon Aug 28 00:56:05 KST 2023

์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ˜์†”์—์„œ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ƒ์„ฑ ์ˆœ์„œ๋Š” ์•„๋ž˜์—์„œ๋ถ€ํ„ฐ ์œ„ ๋ฐฉํ–ฅ์ด๋‹ค.

This post is licensed under CC BY 4.0 by the author.