nayoungs
항상 끈기있게
nayoungs
  • 분류 전체보기 (274)
    • Cloud (21)
      • AWS (15)
      • Azure (3)
      • NCP (2)
      • GCP (1)
    • DevOps (68)
      • Docker (16)
      • Kubernetes (50)
      • CICD (2)
    • IaC (25)
      • Ansible (17)
      • Terraform (8)
    • Certification (4)
    • 금융 IT (5)
    • AI (3)
    • Linux (47)
    • 미들웨어 (5)
    • Programming (7)
      • GoLang (3)
      • Spring (4)
    • CS (25)
      • 네트워크 (17)
      • 운영체제 (5)
      • Web (1)
      • 개발 상식 (2)
      • 데이터베이스 (0)
    • Algorithm (59)
      • 프로그래머스 (36)
      • 백준 (18)
      • 알고리즘 정리 (5)
    • ETC (5)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
nayoungs

항상 끈기있게

IaC/Terraform

[Terraform] Provisioners (feat.Taint)

2022. 4. 22. 20:44
728x90

 

📌INDEX

  • Provisioners
  • Provisioner 연결
    • 실습해보기
  • Taint란?
  • Ansible 실행 방법



✔️ Provisioners

Provisioners는 terraform에서 제공하는 공통 argument이다.

 

"Provisioners are a Last Resort " : 최후의 수단이라는 뜻으로, 되도록 user-data를 사용하는 것을 권장한다.

 

☁️ 참고

user_data를 먼저 실행할 지 provisioner를 먼저 실행할 지 결정할 수 있는 방법은 없고,

provisioner는 순서대로 실행된다.

 

 

Provisioner 종류

  • file: 파일 복사

새로 생성된 리소스로 파일 또는 디렉토리를 복사하는 데 사용한다.

resource "aws_instance" "web" {
  # ...

  # Copies the myapp.conf file to /etc/myapp.conf
  provisioner "file" {
    source      = "conf/myapp.conf"
    destination = "/etc/myapp.conf"
  }
}
  • local_exec: 로컬 머신에서 명령 실행

참고) self 는 자기 자신의 리소스와 동일

참고) 쌍따옴표 안에서 변수 참조할 때 : "${변수명}"

resource "aws_instance" "web" {
  # ...

  provisioner "local-exec" {
    command = "echo ${self.private_ip} >> private_ips.txt"
  }
}
  • remote_exec: 원격 머신에서 명령 실행
resource "aws_instance" "web" {
  # ...

  # Establishes connection to be used by all
  # generic remote provisioners (i.e. file/remote-exec)
  connection {
    type     = "ssh"
    user     = "root"
    password = var.root_password
    host     = self.public_ip
  }

  provisioner "remote-exec" {
    inline = [
      "puppet apply",
      "consul join ${aws_instance.web.private_ip}",
    ]
  }
}



✔️ Provisioner 연결

Provisioner Connection Setting

file과 remote_exec는 ssh 연결이 필요하고, 이를 connection block으로 정의한다.

 

connection 방법 2가지

 

1. 프로비저너 내부에 정의

  • 해당 프로비저닝에만 적용
  provisioner "file" {        #프로비저너
	  connection {            #커넥션 블록
	    type     = "ssh"
	    user     = "root"
	    password = "${var.root_password}"
	    host     = "${var.host}"
	  }
  }

 

2. 프로비저너와 connection 블록 분리

  • 모든 프로비저닝에 적용
  • 일반적인 방법(더 많이 사용)
  provisioner "file" {       #프로비저너
  }

  provisioner "file" {
  }

  connection {               #커넥션 블록
  }

 

💻 실습

 

여기에서 작성했던 user_data를 provisioner로 작성해보자

 

index.html 파일 작성하기

📝 index.html

<html>
    <head>
        <title>
            hello Terraform
        </title>
    </head>
    <body>
        <h1> Hello Terraform World</h1>
    </body>
</html>

 

connection block 작성하기

  • host : self로 자신의 리소스 참조
  • file function으로 private key 가져오기
 connection {
    user        = "ec2-user"
    host        = self.public_ip
    private_key = file("/home/vagrant/.ssh/id_rsa")
    timeout     = "1m"
  }

 

키 페어 생성하기 : Key Pair

  • file function으로 public 키 가져오기
resource "aws_key_pair" "app_server_key" {
  key_name   = "app_server-key"
  public_key = file("/home/vagrant/.ssh/id_rsa.pub")
}

 

instance argument로 key_name추가

 key_name               = aws_key_pair.app_server_key.key_name

 

ssh 22번 포트 열어주기

📝 security_group.tf

resource "aws_security_group" "app_server_sg" {
  name = "Allow SSH & HTTP"
  vpc_id = module.app_vpc.vpc_id #output 참조

  ingress { #인바운드 규칙
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress { #인바운드 규칙
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["내 IP/32"]
  }

  egress { #아웃바운드 규칙
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

 

index.html 파일을 복사하기 위한 file privisioner 작성

  • ec2-user로 진행하기 때문에 권한상의 문제로 /tmp/index.html로 복사 후, 이후 /var/www/html/index.html로 복사
provisioner "file" {
  source      = "index.html"
  destination = "/tmp/index.html"
}

 

resource내에 패키지 설치를 위한 romote_exec provisioner 작성

  • ec2-user로 접속되기 때문에 관리자 권한 필요 : sudo
provisioner "remote-exec" {
  inline = [
    "sudo yum install -y httpd",
    "sudo systemctl enable --now httpd",
    "sudo cp /tmp/index.html /var/www/html/index.html"
  ]
}

 

📝 main.tf 최종본

resource "aws_key_pair" "app_server_key" {
  key_name   = "app_server-key"
  public_key = file("/home/vagrant/.ssh/id_rsa.pub")

}

resource "aws_instance" "app_server" {
  ami                    = var.aws_amazon_linux_ami[var.aws_region]
  instance_type          = "t2.micro"
  availability_zone      = var.aws_availability_zone[var.aws_region]
  vpc_security_group_ids = [aws_security_group.app_server_sg.id]
  key_name               = aws_key_pair.app_server_key.key_name

  connection {
    user        = "ec2-user"
    host        = self.public_ip
    private_key = file("/home/vagrant/.ssh/id_rsa")
    timeout     = "1m"
  }

    provisioner "file" {
    source      = "index.html"
    destination = "/tmp/index.html"
  }

  provisioner "remote-exec" {
    inline = [
      "sudo yum install -y httpd",
      "sudo systemctl enable --now httpd",
      "sudo cp /tmp/index.html /var/www/html/index.html"
    ]
  }

  tags = local.common_tags
}

resource "aws_eip" "app_server_eip" {
  vpc      = true
  instance = aws_instance.app_server.id
  tags     = local.common_tags
}

resource "aws_s3_bucket" "app_bucket" {
  bucket = "encore-20220421"
  tags   = local.common_tags
}<br>

 

접속 확인

[vagrant@controller 01]$ curl http://3.35.59.108
<html>
    <head>
        <title>
            hello Terraform
        </title>
    </head>
    <body>
        <h1> Hello Terraform World</h1>
    </body>
</html>



✔️ Taint란?

오염되다, 문제있다, 오류가 있다는 의미로, 

리소스를 생성/변경 하다가 오류가 생기면, 해당 리소스는 Taint 처리된다.

Taint 처리된 리소스는 다음 작업시 무조건 재생성된다.

 

  • untaint 설정하기
$ terraform taint <RESOURCE>
  • taint 설정하기
    • 재생성 시키기 위해 의도적으로 taint시키는 경우도 있음
$ terraform untaint <RESOURCE>
  • tainted 상황 예시
$ terraform show
# aws_instance.app_server: (tainted) 
resource "aws_instance" "app_server" {
    ami                                  = "ami-02e05347a68e9c76f"
    arn                                  = "arn:aws:ec2:ap-northeast-2:556627152554:instance/i-0dd180dfd111fd24c"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-2a"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 1



✔️ Ansible 실행 방법

Terraform은 puppit, salt-masterless 등 다양한 IaC 도구들의 provisioner를 제공하지만, ansible은 제공하지 않는다.

 

Terraform에서 Ansible을 어떻게 실행할까❔ 크게 2가지 방법이 있다.

 

1. AMI 이미지 내에 ansible을 미리 설치

  • file로 플레이북 및 파일 복사
  • remote-exec로 실행
  • ansible-playbook a.yaml -c local
    • 참고) local 접속방식: 자기 자신 한테 접속하는 것 => key 필요없음

 

2. 로컬에서 실행

  • 로컬에 ansible이 설치되어 있어야 함
  • local-exec로 인벤토리 생성
    • self.public_ip
  • local-exec로 ansible-playbook 실행

 

예시

  connection {
    user        = "ec2-user"
    host        = self.public_ip
    private_key = file("/home/vagrant/.ssh/id_rsa")
    timeout     = "1m"
  }

  provisioner "local-exec" {
    command = "echo ${self.public_ip} ansible_user=ec2-user > inven.ini"
  }

  provisioner "local-exec" {
    command = "ansible-playbook -i inven.ini web_install.yaml -b"
  }

 

 

 

728x90
저작자표시 (새창열림)
    'IaC/Terraform' 카테고리의 다른 글
    • [Terraform] Count 반복문 (with length function)
    • [Terraform] 모듈(Module)
    • [Terraform] 사용자 데이터(Userdata)와 보안그룹(Security Group)
    • [Terraform] 출력값(Output)과 로컬값(Local)
    nayoungs
    nayoungs
    안되면 될 때까지

    티스토리툴바