Terraform - Infrastructure as Code

 인프런 송주영님 강의를 듣고 나름대로 요약한 내용 입니다.


Terraform

  • Terraform이란 서버 인프라를 코드로서 관리하는 프로그램이다.
  • 실습은 AWS 리소스를 Terraform 코드로 작성하여 서버 인프라를 구성 하는 내용 입니다.


내 실습 환경

MacOS
AWS CLI 2
Terraform
1
2
3
4
5
curl -sO https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_darwin_amd64.zip
unzip terraform_0.12.24_darwin_amd64.zip
mv terraform /usr/local/bin
terraform --version
Terraform v0.12.24
  • homebrew
1
2
3
brew install terraform
terraform --version
Terraform v0.12.24

Terraform 기본 개념

  • provider : 인프라 제공자. (ex. AWS, AZURE)
  • resource : 실제로 생성할 provider의 인프라 자원. (ex. aws_lb)
  • state: terraform 실행으로 생성된 인프라의 state.
  • output : terraform으로 state 파일을 생서하여 저장하는 것을 의미.
  • backend : terraform 실행으로 생성된 state를 저장할 공간. (ex. S3)
  • module : 공통적으로 사용할 인프라 코드 묶음.
  • remote state : 다른 경로의 state를 참조하는 것을 의미.

Terraform 기본 명령어

  • init : 해당 폴더를 terraform base로 초기화
  • plan : 작성한 코드로 인프라가 어떻게 변경될지 미리 보기
  • apply : 작성한 코드 실행
  • import
  • state
  • destroy


모든 실행은 아래 순서로 진행

1. 해당 폴더를 terraform base로 초기화 하고
$> terraform init
2. 코드 작성 후
3. 코드의 plan을 미리보기
$> terraform plan
4. 코드 적용
$> terraform apply



실습 1

  1. VPC 생성
  2. Subnet 구성
  3. Internet Gateway 생성
  4. Route Table 구성
  5. Private Subnet
  6. NAT Gateway 구성

vpc.tf

cidr_block 필수
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
provider "aws" {
    region = "ap-northeast-2"
}

resource "aws_vpc" "main" {
    cidr_block = "10.0.0.0/16"
    tags = {
        Name = "terraform-101"
    }
}

subnet.tf

cidr_block은 위에 생성한 vpc에 속한 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
provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_vpc" "main" {
  cidr_block       = "10.0.0.0/16"

  tags = {
    Name = "terraform-101"
  }
}

resource "aws_subnet" "first_subnet" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"

  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "101subnet-1"
  }
}

resource "aws_subnet" "second_subnet" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.2.0/24"

  availability_zone = "ap-northeast-2b"

  tags = {
    Name = "101subnet-2"
  }
}

internet_gateway.tf

1
2
3
4
5
6
7
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "main"
  }
}

route.tf

생성된 aws_route_table은 aws_route_table_association으로 연결 한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
resource "aws_route_table" "route_table" {
    vpc_id = aws_vpc.main.id
    tags = {
        Name = "main"
    }
}

resource "aws_route_table_association" "route_talbe_association_1" {
    subnet_id = aws_subnet.first_subnet.id
    route_table_id = aws_route_table.route_table.id
}

resource "aws_route_table_association" "route_talbe_association_2" {
   subnet_id = aws_subnet.second_subnet.id
   route_talbe_id = aws_route_table.route_table.id
}

private_subnet.tf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
resource "aws_subnet" "first_private_subnet" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.3.0/24"

  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "101subnet-private-1"
  }
}

resource "aws_subnet" "second_private_subnet" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.4.0/24"

  availability_zone = "ap-northeast-2b"

  tags = {
    Name = "101subnet-private-2"
  }
}

nat.tf

 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
resource "aws_eip" "nat_1" {
  vpc   = true

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_eip" "nat_2" {
  vpc   = true

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_nat_gateway" "nat_gateway_1" {
  allocation_id = aws_eip.nat_1.id

  # Private subnet이 아니라 public subnet을 연결하셔야 합니다.
  subnet_id = aws_subnet.first_subnet.id

  tags = {
    Name = "NAT-GW-1"
  }
}

resource "aws_nat_gateway" "nat_gateway_2" {
  allocation_id = aws_eip.nat_2.id

  subnet_id = aws_subnet.second_subnet.id

  tags = {
    Name = "NAT-GW-2"
  }
}

nat_association.tf

 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
resource "aws_route_table" "route_table_private_1" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "main-private-1"
  }
}

resource "aws_route_table" "route_table_private_2" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "main-private-2"
  }
}

resource "aws_route_table_association" "route_table_association_private_1" {
  subnet_id      = aws_subnet.first_private_subnet.id
  route_table_id = aws_route_table.route_table_private_1.id
}

resource "aws_route_table_association" "route_table_association_private_2" {
  subnet_id      = aws_subnet.second_private_subnet.id
  route_table_id = aws_route_table.route_table_private_2.id
}

resource "aws_route" "private_nat_1" {
  route_table_id              = aws_route_table.route_table_private_1.id
  destination_cidr_block      = "0.0.0.0/0"
  nat_gateway_id              = aws_nat_gateway.nat_gateway_1.id
}

resource "aws_route" "private_nat_2" {
  route_table_id              = aws_route_table.route_table_private_2.id
  destination_cidr_block      = "0.0.0.0/0"
  nat_gateway_id              = aws_nat_gateway.nat_gateway_2.id
}




실습 2

  1. S3 생성

s3.tf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_s3_bucket" "main" {
  bucket = "devopsart-terraform-101"

  tags = {
    Name        = "devopsart-terraform-101"
  }
}




실습 3

  1. IAM User 생성
  2. IAM Group 생성
  3. User를 Group에 등록
  4. IAM Role 생성
  5. IAM Policy 생성

user.tf

 1
 2
 3
 4
 5
 6
 7
provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_iam_user" "gildong_hong" {
  name = "gildong.hong"
}

group.tf

1
2
3
4
5
6
7
provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_iam_group" "devops_group" {
  name = "devops"
}

register.tf

1
2
3
4
5
6
7
8
9
resource "aws_iam_group_membership" "devops" {
  name = aws_iam_group.devops_group.name

  users = [
    aws_iam_user.gildong_hong.name
  ]

  group = aws_iam_group.devops_group.name
}

s3_role.tf

 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
42
43
44
45
46
47
resource "aws_iam_role" "hello" {
  name               = "hello-iam-role"
  path               = "/"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

}

resource "aws_iam_role_policy" "hello_s3" {
  name   = "hello-s3-download"
  role   = aws_iam_role.hello.id
  policy = <<EOF
{
  "Statement": [
    {
      "Sid": "AllowAppArtifactsReadAccess",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "*"
      ],
      "Effect": "Allow"
    }
  ]
}
EOF

}

resource "aws_iam_instance_profile" "hello" {
  name = "hello-profile"
  role = aws_iam_role.hello.name
}

policy.tf

 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
resource "aws_iam_user" "gildong_hong" {
  name = "gildong.hong"
}

resource "aws_iam_user_policy" "art_devops_black" {
  name  = "super-admin"
  user  = aws_iam_user.gildong_hong.name

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "*"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}
EOF
}



Terraform 고도화


1. Backend 활용하기

2. Variable 활용하기

3. Function 활용하기

4. GitHub로 협업하기


댓글

이 블로그의 인기 게시물

[Protocol] WIEGAND 통신

Orange for Oracle에서 한글 깨짐 해결책

[UI] GNB·LNB·SNB·FNB 용어 설명