티스토리 뷰

카테고리 없음

테라폼 기본 테스트진행

미니대왕님 2022. 1. 11. 11:08

GitHub에서 코드 바로 실행해보기

https://www.terraform.io/downloads : 테라폼 다운로드

목차

1. Terraform이란?

2. 실습 환경 설명, terraform 설치

3. IAM User & ACCESS KEY 설정

4. 간단하게 EC2 배포해보기 (+멱등성 체험)

5. Terraform으로 프로비저닝한 리소스들 삭제

 

 

1. Terraform이란?

먼저 IaC(Infrastructure as Code, 코드형 인프라)란? 코드형태로 인프라를 작성, 정의, 배포, 업데이트 함

IaC 도구는 크게 애드 혹 스크립트, 구성 관리 도구, 서버 템플릿 도구, 서버 프로비전 도구 4가지로 나뉜다

  • 구성 관리 도구 : Ansible, Chef, Puppet - 서버를 관리하는 쪽에 좀 더 초점
  • 서버 프로비전 도구 : Terraform, AWS Cloudformation - 서버와 인프라 자체를 구성하는데에 좀 더 초점

 

2. 실습 환경 설명, terraform 설치

사용 에디터 : Sublime Text 3 (Install Package로 Terraform 설치했음)

테라폼 다운 : www.terraform.io/downloads.html 여기에서 본인 OS에 맞는 terraform 다운로드

테라폼을 어느 위치에서도 사용할 수 있게 하기 위해 환경변수 PATH도 설정해주었다

 

 

일단 C:\에 terraform이란 새 폴더를 만들어서 terraform 파일을 넣어둔다

 

 

환경 변수를 검색해서 시스템 환경 변수 편집으로 들어가자

 

 

위와 같은 방법으로 시스템 변수의 Path에 C:\terraform을 추가해주고 확인을 눌러준다

 

 

cmd로 아무 위치에서 terraform을 쳤을 때 위와 같이 나오면 terraform 설치는 끝이다

 

그리고 main.tf를 위치시킬 폴더를 하나 아무데나 생성해주자

난 Terraform이란 폴더를 하나 만들어줬고 cmd에서 그 폴더 내로 이동한 후 진행하겠다

 

해당 폴더에서도 terraform 명령어가 먹히는지 확인

 

3. IAM User & ACCESS KEY 설정

테라폼에서 AWS의 리소스를 프로비저닝 하기 위해서는 해당 계정의 ACCESS KEY와 SECRET KEY가 필요하다

간단한 실습만 진행할거긴 하지만, 그래도 루트 계정으로 진행하는건 위험하기도 하고 보안상으로도 좋지 않기 때문에 최소한의 권한만 있는 IAM User를 만든 후 진행해보겠다

콘솔 > IAM > 사용자 > 사용자 추가

 

 

테라폼으로만 접근할거니까 프로그래밍 방식 액세스만 허용해주자

 

 

EC2만 만들어볼거니까 AmazonEC2FullAccess만 연결해준다

(VPC는 기본 VPC로 진행할 예정)

 

생성을 완료하면 이렇게 ACCESS KEY와 SECRET KEY를 다운받을 수 있는 창이 뜬다

각각의 키를 메모장에 복사해두던지 csv 파일을 다운받든지 하자 (지금 지나면 다시 못받는다)

 

이제 다시 cmd로 돌아와서, 액세스 키와 시크릿 키를 다음과 같이 등록해주자

set AWS_ACCESS_KEY_ID=[본인 계정 액세스 키]
set AWS_SECRET_ACCESS_KEY=[본인 계정 시크릿 키]

 

 set 명령은 일반 변수 등록이라 현재 터미널에서만 유용하다 (다른 cmd 창을 키면 초기화 되어있음)

영구 등록이 필요하면 setx 명령을 사용하면 되고, linux의 경우엔 export를 사용하면 된다

 

4. 간단하게 EC2 배포해보기 (+멱등성 체험)

일단 기본 VPC가 배포되어 있어야 한다 (없으면 작업 > 기본 VPC 생성으로 만들면 됨)

기본 VPC로 진행하면 VPC id나 서브넷 id 등을 지정할 필요가 없다

지금은 맛보기만 하는거기때문에 최대한 간단하게 간단하게 해보겠다

 

 

일단 만들어둔 폴더에 main.tf 파일을 생성한 다음, 공급자(provider)를 설정해줘야 한다

provider "aws" {
  region = "ap-northeast-2"
}

 

PROVIDER는 AWS, Azure 등 공급자의 이름이다

따라서 위 구문으로 인해 테라폼은 아마존 웹 서비스의 서울 리전에서 인프라를 배포해야 한다는걸 인지하게 된다

이제 EC2를 만들기 위해 아래에 다음 구문을 적어주자

 

resource "aws_instance" "testEC2" {
  ami           = "ami-0e17ad9abf7e5c818"
  instance_type = "t2.micro"
}

aws_instance 자리엔 생성할 리소스 타입을, testEC2 자리엔 가독성을 위해 다른 코드들과 구분될만한 이름을 적어주면 된다

AMI는 서울 리전의 Amazon Linux 2 AMI이다

 

 

간단한 코드가 완성되었으니, 실행을 해보자

cmd에서 아래 명령들을 차례대로 쳐주자

 

terraform init
terraform plan
terraform apply
terraform destroy

 

init : 테라폼을 수행하기 위한 공급자의 최신 플러그인들을 자동 설정 - provider 구문이 설정된 후에 실행할 수 있다

 

 

plan : 테라폼이 실행했을 시, 실제로 생성되거나 변경되는 내역을 보여준다

테라폼은 멱등성(Idempotency)이라는 중요한 개념이 있기 때문에, 같은 코드들을 조금씩 변경하면서 실행했을 때 매번 새롭게 생성되는것이 아니라 변경된 부분만 반영되어 프로비저닝된다

 

 

마지막으로 apply 명령으로 테라폼을 실제로 실행시키게 되는데, 변경 내역을 확인한다고 하기 위해 중간에 yes를 한번 쳐주고 진행하면 끝난다

 

 

완료된 후 콘솔에 가보면

 

 

설정했던 대로의 인스턴스가 만들어져 있다

 

근데 우리는 멱등성을 경험해보고 싶기 때문에, 코드를 아래와 같이 좀 수정해서 다시 실행시켜보겠다

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "testEC2" {
  ami           = "ami-0e17ad9abf7e5c818"
  instance_type = "t2.micro"

  tags = {
    Name = "Web Server"
  }
}

별건 없고 그냥 Tag만 추가해주었다

이러고 다시 apply를 해주면

 

 

아까 그 인스턴스에 그대로 태그만 생긴게 확인되었다

: 멱등성 때문에 변경된 부분만 반영해서 변경된 것

(물론 user data같은걸 바꾸게 된다면 종료하고 다시 만들어야하긴 한다)

 

5. Terraform으로 프로비저닝한 리소스들 삭제

terraform destroy

그냥 그대로 destory 명령만 해주면 삭제될 변경사항들이 쭈루룩 생기면서 yes를 누르라고 나온다

yes만 마저 눌러주면 알아서 전부 삭제된다

 

 

 

6.AWS 보안 그룹(예시)

 

 

VPC를 만들었으니, 이제 보안 그룹을 만들어서 앞으로 만들 EC2나 RDS 등에게 적용할 준비를 해야 합니다.

구성은 단순하며, 이번엔 기본 구성 방법과 Module을 이용한 방법에 대해 소개합니다.

#기본 생성 방식
resource "aws_security_group" "web" {
  vpc_id = "${module.vpc.vpc_id}"     #생성할 위치의 VPC ID
  name = "WEB"                        #그룹 이름
  description = "Terraform WEB SG"    #설명
  ingress {
    from_port = 22                    #인바운드 시작 포트
    to_port = 22                      #인바운드 끝나는 포트
    protocol = "tcp"                  #사용할 프로토콜
    cidr_blocks = ["0.0.0.0/0"]       #허용할 IP 범위
}
  ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
}
 ingress {
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
}
  egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }
}

 

#모듈을 이용한 방식
module "security-group" {
  source  = "terraform-aws-modules/security-group/aws" #사용할 모듈 소스
  version = "3.1.0"                                    #모듈 버전

  name        = "Web"                                  #그룹이름
  description = "Web"                                  #설명
  vpc_id      = "${module.vpc.vpc_id}"                 #생성할 위치의 VPC ID
  use_name_prefix = "false"                            #해당 옵션을 false 시키지 않을 경우, 그룹이름 뒤에 고유 넘버링이 부착되어 생성됨
  ingress_with_cidr_blocks = [
    {
      from_port   = 443                                #인바운드 시작 포트
      to_port     = 443                                #인바운드 끝나는 포트
      protocol    = "tcp"                              #사용할 프로토콜
      description = "https"                            #설명
      cidr_blocks = "0.0.0.0/0"                        #허용할 IP 범위
    },
    {
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      description = "http"
      cidr_blocks = "0.0.0.0/0"
    },
    {
      from_port   = 22
      to_port     = 22
      protocol    = "tcp"
      description = "ssh"
      cidr_blocks = "0.0.0.0/0"
    }
]
  egress_with_cidr_blocks = [
    {
      from_port   = 0                                #아웃바운드 시작 포트
      to_port     = 0                                #아웃바운드 끝나는 포트
      protocol    = "-1"                             #사용할 프로토콜
      description = "all"                            #설명
      cidr_blocks = "0.0.0.0/0"                      #허용할 IP 범위
    }
]
}

모듈을 사용하더라도 VPC처럼 여러 옵션들이 들어가는 게 아니기 때문에 코드가 절약되고 하지는 않습니다.

문법이 약간 다르기 때문에 편리한 방법을 선택하여 사용하시면 됩니다.

 

이렇게 보면서 궁금하실 만한 점은 WEB서버용은 추가했는데, RDS용은 어떻게 추가하느냐가 될 것 같은데요.

기본 방식으로는 resource "aws_security_group" "web"를 resource "aws_security_group" "rds"라는 식으로 리소스를 추가하여 생성하시면 되고,

 

모듈 또한 module "security-group"에서 module "security-group 2"식으로 리소스를 추가하여 생성하시면 됩니다.

어때요? 단순하죠?

 

코드 기반이라는 선입견 때문에 어렵다고 느껴지실 수 있지만 자세히 보다 보면 일정한 문법이 있기 때문에 그리 어렵지만은 않습니다.

한번 따라 해 보시고 익숙해져 보세요.

 

7. ALB 만들기 (예시)

resource "aws_alb" "terraform-alb1" {
    name                            = "web1"
    internal                        = false
    load_balancer_type              = "application"
    idle_timeout                    = 60
    security_groups                 = ["sg-084b72f3dd7d5480e"]
    subnets                         = ["subnet-0ba04b52302cc82ad","subnet-069242ebff19529f5"]
    enable_deletion_protection      = false
    ####deletion protection 활성화되어 있으면 삭제가 안 된다.
    lifecycle {
        create_before_destroy       = true
    }
    tags = {
        Name                        = "web1"
        Env                         = "stg"
        CreateUser                  = "terraform@email.com"
        Owner                       = "iac"
        Role                        = "alb"
        Service                     = "network"
    }
}
/*
#####################ALB 타겟 그룹 설정
resource "aws_alb_target_group" "tf_alb_target_group-web1" {
    name                            = "web1"
    port                            = 80
    protocol                        = "HTTP"
    vpc_id                          = aws_vpc.tf_vpc99.id
    health_check {
        interval                    = 30
        path                        = "/"
        timeout                     = 3
        healthy_threshold           = 3
        unhealthy_threshold         = 2
        matcher                     = "200"
    }
    tags = {
        Name                        = "web1"
        Env                         = "stg"
        CreateUser                  = "terraform@email.com"
        Owner                       = "iac"
        Role                        = "alb_target_group"
        Service                     = "network"
    }
}
*/
####################ALB listener HTTP service
resource "aws_alb_listener" "tf_alb_listener_80" {
    load_balancer_arn               = aws_alb.terraform-alb1.arn
    port                            = "80"
    protocol                        = "HTTP"
    default_action {
        type                        = "redirect"
        redirect {
            port                    = "443"
            protocol                = "HTTPS"
            status_code             = "HTTP_301"
        }
    }
}
###################ALB listener HTTPS service
resource "aws_alb_listener" "tf_alb_listener_443" {
    load_balancer_arn               = aws_alb.terraform-alb1.arn
    port                            = "443"
    protocol                        = "HTTPS"
    ssl_policy                      = "ELBSecurityPolicy-2016-08"
    #depends_on                     = aws_alb_target_group.tf_alb_target_group-web1
    //certificate_arn                 = aws_acm_certificate.tf4wxyzcom.arn
    default_action {
        type = "forward"
       // target_group_arn = aws_alb_target_group.tf_alb_target_group-web1.arn
    }
}

/*
###ALB target group attachment
resource "aws_alb_target_group_attachment" "tf_attachment-web31" {
//    target_group_arn                = aws_alb_target_group.tf_alb_target_group-web1.arn
    //target_id                       = aws_instance.tf_instance_web31.id
    port                            = 80
}
*/

 

************************************************************************************************************

 

테라폼에서 VPC, Subnet, Gateway, Route 생성하기

 

 
[root@keystone terraform-example]cat vpc-subnet.tf
 
resource "aws_vpc" "kube-vpc" {
  cidr_block = "10.0.0.0/16"
  tags {
    Name = "kube-vpc"
  }
}
 
resource "aws_subnet" "kube-subnet-c" {
  vpc_id = "${aws_vpc.kube-vpc.id}"
  cidr_block = "10.0.1.0/24"
  availability_zone = "ap-northeast-2c"
}


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

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

resource "aws_subnet" "public_subnet" {
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.0.0/24"

  availability_zone = "ap-northeast-2a"

  tags = {
   Name = "terraform-vpc-public-subnet"
  }

}

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

  availability_zone = "ap-northeast-2a"

  tags = {
   Name = "terraform-vpc-private-subnet"
  }
}
 

 

내용은 간단하다. 

 

  1. CIDR가 10.0.0.0/16인 aws_vpc 리소스를 생성하되, kube-vpc라는 이름으로 생성하도록 tags를 준다.
  2. aws_subnet 리소스를 생성하되, CIDR는 10.0.1.0/24 이며 AZ는 ap-northeast-2c 이다. 

 

여기서 흥미로운 점은 aws_subnet의 vpc_id가 ${aws_vpc.kube-vpc.id} 로 설정되었다는 점인데, aws_vpc 리소스 중 kube-vpc라는 이름의 VPC를 선택해 지정하겠다는 뜻이다. 단, ${리소스이름} 으로 참조를 할 때는 AWS에서 보이는 이름이 아닌 테라폼 내에서 고유하게 식별되기 위한 이름을 사용해야 한다. AWS에서 쓰이는 이름을 쓰고 싶다면 ${} 없이 단순 문자열로 이름을 입력한다.

 

 

두 번째로 게이트웨이를 정의하는 gateway.tf 파일을 작성한다. 이번에도 크게 어렵지 않은 내용이다. kube-gateway라는 태그 이름을 가진 게이트웨이를 생성하되, 연결되는 VPC를 kube-vpc로 하겠다는 내용이다.

 

1
2
3
4
5
6
7
8
[root@keystone terraform-example]cat gateway.tf
 
resource "aws_internet_gateway" "kube-gateway" {
  vpc_id = "${aws_vpc.kube-vpc.id}"
tags {
    Name = "kube-gateway"
  }
}
 
cs

 

 

세 번째로 외부 통신을 위한 라우팅 룰인 route.tf 파일을 작성한다. 마찬가지로 크게 어렵지 않다. Subnet, Route, VPC 등을 다른 파일 또는 동일 파일의 테라폼 변수 이름을 통해 참조해 입력했다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@keystone terraform-example]cat routes.tf
 
resource "aws_route_table" "kube-route-table" {
  vpc_id = "${aws_vpc.kube-vpc.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.kube-gateway.id}"
  }
  tags {
    Name = "kube-route-table"
  }
}
 
resource "aws_route_table_association" "my-subnet-association" {
  subnet_id      = "${aws_subnet.kube-subnet-c.id}"
  route_table_id = "${aws_route_table.kube-route-table.id}"
}
 
cs

 

 

모든 파일을 작성했다면 terraform plan 명령어를 입력한다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@keystone terraform-example]# terraform plan
...
 
Terraform will perform the following actions:
 
  + aws_internet_gateway.kube-gateway
      id:                                          <computed>
      owner_id:                                    <computed>
      tags.%:                                      "1"
      tags.Name:                                   "kube-gateway"
      vpc_id:                                      "${aws_vpc.kube-vpc.id}"
 
...
 
 
Plan: 5 to add, 0 to change, 0 to destroy.
 
------------------------------------------------------------------------
 
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
 
cs

 

이것이 테라폼의 다른 특징 중 하나인데, terraform plan 명령어는 현재 디렉터리에서 변경된 사항들을 적용하기 전, 미리 결과를 확인하는 용도로 사용된다. 즉 Dry run과 같은 용도로 사용될 수 있기 때문에 실제로 변경된 사항을 적용하기 전에 한 번쯤은 실행해보는 것을 추천한다.

 

출력의 마지막에 terraform apply를 실행하라고 되어 있으니, 실제로 VPC, Subnet 등을 만들기 위해 이를 실행해보자.

중간에 yes를 입력하라고 뜨는데, 정말로 실행할 것인지를 다시 묻는 것이므로 yes를 입력해야 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@keystone terraform-example]terraform apply
...
 
 
Plan: 5 to add, 0 to change, 0 to destroy.
 
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
 
  Enter a value: yes
 
aws_vpc.kube-vpc: Creating...
....
 
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
cs

 

출력이 너무 많아 적절히 생략하였지만 출력 내용을 자세히 보면 어떠한 속성으로 AWS 오브젝트가 생성되는지를 확인할 수 있다. 어쨌든, AWS 관리 콘솔의 VPC에 가면 실제로 생성된 것을 확인할 수 있다.

 

 

 

현재 파일 구조는 아래와 같다. gateway.tf, routes.tf, vpc-subnet.tf가 추가되었다.

 

1
2
3
4
5
6
7
8
9
10
11
12
[root@keystone terraform-example]tree
.
├── aws-key.pub
├── aws-provider.tf
├── gateway.tf
├── key.tf
├── routes.tf
├── terraform.tfstate
├── terraform.tfstate.backup
└── vpc-subnet.tf
 
0 directories, 8 files
cs

 

테라폼은 terraform apply를 통해 어떠한 변경 사항을 적용할때마다 이전 상태에 대한 백업 파일을 생성한다. 위에서 terraform.tfstate.backup이 바로 그것이며, terraform.tfstate는 현재 테라픔이 인지하고 있는 클라우드 상태를 담고 있다.

 

 

테라폼에서 보안 그룹 및 규칙 생성하기

 

이번에는 보안 그룹과 그에 해당하는 규칙을 생성한다. 

 

먼저, 보안 그룹을 생성하기 위한 파일을 작성한다. 이 보안 그룹의 이름은 kube-sg며, security-group.tf 파일에 저장한다. 보안 그룹을 정의함과 동시에 보안 그룹의 규칙을 인라인(inline) 으로서 정의할 수 있다곤 하는데, 몇 가지 제약사항이 있다고 하여 별도로 분리하였다.4

 

1
2
3
4
5
6
7
8
[root@keystone terraform-example]cat security-group.tf
 
resource "aws_security_group" "kube-sg" {
  vpc_id      = "${aws_vpc.kube-vpc.id}"
  name        = "kube-sg"
  description = "This security group is for kubernetes"
  tags { Name = "kube-sg" }
}
 
cs

 

다음으로 보안 그룹 규칙을 생성한다. sg-rules.tf 라는 파일으로 저장하였으며, 각 규칙의 내용은 아래와 같다.

 

  • 같은 VPC 간의 모든 트래픽 허용 (kube-cluster-traffic)
  • 인스턴스로의 SSH 허용 (instance-ssh)
  • Outbound의 모든 트래픽 허용 (outbound-traffic)

 

참고로 프로토콜을 -1로 설정하면 모든 프로토콜에 대해 허용한다는 의미이며, from_port, to_port = 0 은 모든 포트에 대해서 적용함을 의미한다.5

 

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
[root@keystone terraform-example]cat sg-rules.tf
 
resource "aws_security_group_rule" "kube-cluster-traffic" {
  type              = "ingress"
  from_port         = 0
  to_port           = 0
  protocol = "-1"
  cidr_blocks       = ["10.0.0.0/16"]
  security_group_id = "${aws_security_group.kube-sg.id}"
  lifecycle { create_before_destroy = true }
}
 
resource "aws_security_group_rule" "instance-ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol = "TCP"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = "${aws_security_group.kube-sg.id}"
  lifecycle { create_before_destroy = true }
}
 
resource "aws_security_group_rule" "outbound-traffic" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = "${aws_security_group.kube-sg.id}"
  lifecycle { create_before_destroy = true }
}
 
cs

 

테라폼은 AWS의 오브젝트의 값을 교체할 때, 값을 변경하지 못하는 오브젝트에 대해서는 기존 오브젝트를 삭제한 뒤 새로운 값으로 오브젝트를 생성한다. 그러나 이는 서비스 중단을 발생시킬 수 있기 때문에 테라폼 파일의 설정에서 lifecycle을 설정할 수 있다. 위 예시에서 쓰인 create_before_destroy는 교체되는 오브젝트가 먼저 생성된 뒤 이전 오브젝트를 삭제하는 정책이다. 이러한 옵션들에 대해서는 주석에서 자세히 확인할 수 있으며, 이 옵션 외에도 다양한 설정을 지원하고 있다.6

이전과 마찬가지로, terraform apply 명령어를 통해 보안 그룹과 규칙을 생성한다.

 

1
2
3
4
5
6
7
[root@keystone terraform-example]terraform apply
...
aws_security_group_rule.kube-cluster-traffic: Creation complete after 1s (ID: sgrule-1717961461)
aws_security_group_rule.outbound-traffic: Creation complete after 1s (ID: sgrule-1928217335)
aws_security_group_rule.instance-ssh: Creation complete after 1s (ID: sgrule-3291458000)
 
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
 
cs

 

다시 AWS 관리 콘솔에서 보안 그룹을 확인해보면 잘 생성되었음을 확인할 수 있다.

 

 

여기까지의 파일 구조는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@keystone terraform-example]# tree
.
├── aws-key.pub
├── aws-provider.tf
├── gateway.tf
├── key.tf
├── routes.tf
├── security-group.tf
├── sg-rules.tf
├── terraform.tfstate
├── terraform.tfstate.backup
└── vpc-subnet.tf
 
0 directories, 10 files
cs

 

 

 

 

테라폼에서 tf 파일을 디렉터리로 구성하기

 

위 파일 구조처럼 구성하는것보다는 디렉터리를 새롭게 생성해 관리하면 좀 더 깔끔할 것 같다. 7

먼저 새로운 디렉터리를 생성한다.

 

1
[root@keystone terraform-example]mkdir network-configs
cs

 

지금까지 생성했던 파일들 중, 네트워크에 관련된 파일들을 network-configs 디렉터리로 옮긴다.

 

1
[root@keystone terraform-example]mv {security-group.tf,gateway.tf,sg-rules.tf,vpc-subnet.tf,routes.tf} network-configs/
cs

 

테라폼은 디렉터리를 'module' : 모듈이라는 단위로 구성한다. 지금까지 사용해온 디렉터리는 root 모듈에 해당되며, 이는 별도로 추가하거나 하지 않아도 자동으로 사용할 수 있다. 그러나 별도의 디렉터리를 생성해 파일을 옮겼다면 이를 별도의 모듈로서 추가해 줄 필요가 있다.

 

aws-provider.tf 파일을 아래와 같이 수정한다.

 

1
2
3
4
5
6
7
8
9
10
11
[root@keystone terraform-example] cat aws-provider.tf
 
provider "aws" {
  access_key = "<ACCESS_KEY>"
  secret_key = "<SECRET_KEY>"
  region     = "ap-northeast-2"
}
 
module "aws-network-configs" {
  source = "./network-configs"
}
 
cs

 

새로운 모듈이 추가되었으므로 이를 적용시킬 필요가 있다. terraform get 명령어를 통해 모듈을 갱신할 수 있다.

 

1
2
3
4
[root@keystone terraform-example]# terraform get
 
- module.aws-network-configs
  Getting source "./network-configs"
cs

 

설정 파일이 변경되었으므로 terraform apply로 다시 적용시킨다. 단, 지금까지 생성했던 오브젝트의 설정 파일 위치가 달라졌으므로 -> 모듈 간에 파일이 이동되었으므로 테라폼은 이를 AWS 오브젝트의 삭제와 생성으로 간주한다. 즉, 기존에 생성된 VPC, 보안 그룹 등을 전부 삭제하고 다시 생성함 (9 added, 9 destroyed) 에 주목하자. 실제로는 이러한 습관은 좋지 않을 수도 있기 때문이다.

 

1
2
3
4
5
6
7
8
9
[root@keystone terraform-example]terraform apply
 
aws_vpc.kube-vpc: Refreshing state... (ID: vpc-0cffad358fd03e6e1)
..
aws_internet_gateway.kube-gateway: Destruction complete after 10s
aws_vpc.kube-vpc: Destroying... (ID: vpc-0cffad358fd03e6e1)
aws_vpc.kube-vpc: Destruction complete after 1s
 
Apply complete! Resources: 9 added, 0 changed, 9 destroyed.
cs

 

파일 구조가 좀 더 깔끔해졌다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@keystone terraform-example]tree
.
├── aws-key.pub
├── aws-provider.tf
├── key.tf
├── network-configs
│   ├── gateway.tf
│   ├── routes.tf
│   ├── security-group.tf
│   ├── sg-rules.tf
│   └── vpc-subnet.tf
├── terraform.tfstate
└── terraform.tfstate.backup
cs

 

 

 

 

테라폼에서 EC2 인스턴스 생성하기

 

드디어 EC2 인스턴스를 생성하는 단계에 왔다. 

 

인스턴스 정의 파일을 작성하기 전, 아래의 파일을 작성하자. 다른 모듈끼리는 resource 참조가 불가능한 것 같아, 이를 위한 output 값을 새롭게 작성하였다. 이 값들은 아래의 인스턴스 정의 파일에서 사용된다.8 Output은 아마도.. 테라폼 변수의 출력값을 저장할 수 있는 변수인 것 같다. (추측)

 

1
2
3
4
5
6
7
8
9
[root@keystone terraform-example]cat network-configs/output.tf
 
output "kube-subnet-c-id" {
  value = "${aws_subnet.kube-subnet-c.id}"
}
 
output "kube-sg-id" {
  value = "${aws_security_group.kube-sg.id}"
}
 
cs

 

 

아래의 내용으로 instance.tf 파일을 작성해 저장한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@keystone terraform-example]cat instance.tf
 
variable "key_pair" {
  default = "aws-key"
}
 
resource "aws_instance" "ubuntu-ssh-server" {
    ami = "ami-067c32f3d5b9ace91"
    instance_type = "t2.micro"
    subnet_id = "${module.aws-network-configs.kube-subnet-c-id}"
    vpc_security_group_ids = [
        "${module.aws-network-configs.kube-sg-id}"
    ]
    key_name = "${var.key_pair}"
    count = 1
    tags {
        Name = "test-instance"
    }
    associate_public_ip_address = true
}
 
cs

 

************************************************************************************************************

 

terraform 디렉터리 구조

  • minimal 예제
    ├── README.md
    ├── main.tf
    ├── variables.tf
    ├── outputs.tf
  • complete 예제
    ├── README.md
    ├── main.tf
    ├── variables.tf
    ├── outputs.tf
    ├── ...
    ├── modules/
    │ ├── nestedA/
    │ │ ├── README.md
    │ │ ├── variables.tf
    │ │ ├── main.tf
    │ │ ├── outputs.tf
    │ ├── nestedB/
    │ ├── .../
    ├── examples/
    │ ├── exampleA/
    │ │ ├── main.tf
    │ ├── exampleB/
    │ ├── .../
    ├── provider.tf
    ├── backend.tf
  • main.tf : 테라폼 CLI를 사용하여 apply 명령어를 사용하면 가장 먼저 main소스 코드를 동작시킵니다. 말 그대로 main
  • modules : 자바로 보면 하나의 클래스를 만드는 것과 비슷한 개념입니다. main에서 input 값을 지정하고 해당 모듈을 사용할 수 있습니다.
  • backend.tf : 테라폼은 형상관리를 위해 .tfstate 파일을 생성합니다. 이 파일을 backup하고 형상관리하기위한 설정을 정의합니다.
  • provider.tf : 리소스를 어디서 제공하는지, 버전은 어떤것인지 등을 설정합니다.
  • outputs.tf : 해당 파일에 설정을 통해서 소스코드에 대한 실행 결과를 출력할 수 있습니다.
  • variables.tf : 소스코드에 사용할 변수들을 정의 합니다.

 

 

 

ㅁㅇㄴㄻㄴㅇㄹ

 

 

댓글