51/120

김건호·2022년 4월 22일
0

출력값

return 값과 같음
https://www.terraform.io/language/values/outputs
https://learn.hashicorp.com/tutorials/terraform/aws-outputs?in=terraform/aws-get-started

output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.app_server.id
}

output "instance_public_ip" {
  description = "Public IP address of the EC2 instance"
  value       = aws_instance.app_server.public_ip
}

블록추가
리소스가 수십개가 되었을 때, EC2 인스턴스에 Eip부여 Eip가 몇번인지 알고 싶을때

apply 한 이 후에 쉽게 확인할 수 있도록

terrafrom output

value 값은 테라폼 쇼에서 볼 수 있는 특정 속성

sensitive= true 직접적으로 보이지 않음

로컬값

함수 내에서 사용하는 지역 변수

locals {
  service_name = "forum"
  owner        = "Community Team"
}

사용법

resource "aws_instance" "example" {
  # ...

  tags = local.service_name

응용법

변수 정의

# variable.tf
variable "project_name" {
  descriptioin = "Projdect Name"
  type = string
  default = "My first Projdect"
}

variable "project_environment" {
  description = "Project Environment"
  type = string
  default = "Local Develoment"
}

$ code local.tf
locals {
  common_tags = {
	project_name=var.project_name
	project_env=var.project_environment    
  }
}

main.tf
tags = local.common_tags

tag의 관한내용
태그는 맵이들어감
공통 태그를 붙일 수 있는 장점

사용자 데이터

프로비저너를 보기전에 사용자데이터를 살펴보고 넘어가자
Userdata
aws_instance 항목
user_data

resource "aws_instance" "app_web" {
  ...
  # 입력값이 멀티라인 이므로
  user_data = <<-EOF
    #!/bin/sh
    yum -y install httpd
    systemctl enable --now httpd
    echo "hello world" > /var/www/html/index.html
    EOF
  ...
}

EOF
리눅스 시스템에서
vi귀찮거나 멀티라인 작업할때 하는거

[vagrant@controller 01]$ cat <<EOF > a.txt
a
b
c
d
EOF
[vagrant@controller 01]$ cat a.txt 
a
b
c
d

EOF ? -> no 처음과 끝만 맞으면 됨 EOF 대신 ABC 써도 됨

user_data 추가 됨

+ user_data            = "0d55d007af9af29d11ac99333a0050b14927d6df"

user_data 값이 이상한데❓
base64로 인코딩했기때문에 -> 명령어가 중간에서 잘못실행되는 것을 방지하기 위해서

terraform에서 제공하는 file 함수로 작성하는 법

user_data.sh

#!/bin/sh
yum -y install httpd
systemctl enable --now httpd
echo "hello world" > /var/www/html/index.html

main.tf 에서 user_data = file("user_data.sh") 로 선언

terraform은 사용자가 함수로 직접 만들 수는 없음

인스턴스에 보안그룹 연결

security_group.tf

resource "aws_sercurity_group" "app_server_sg" {
    name= "Allow SSh & http"

    ingress {
        from_port        = 80
        to_port          = 80
        protocol         = "tcp"
        cidr_blocks      = ["0.0.0.0/0"]
    }
    egress {
        from_port        = 0
        to_port          = 0
        protocol         = "-1" # -1은 모든 프로토콜을 의미
        cidr_blocks      = ["0.0.0.0/0"]
    }

    tags = local.common.tags
}

인스턴스 리소스에 보안그룹 id 연결

resource "aws_instance" "app_server" {
	...
	vpc_security_group_ids = [aws_secruity_group.app_server_sg.id] # list of
	...
}

Provisioner

로컬이나 원격머신에서 명령어를 실행할 수 있도록 하는 기능
변수를 참조할 땐 ${ name }의 형식으로 참조
self는 리소스 자신 -> 자바의 [this](https://www.terraform.io/language/resources/provisioners/syntax#the-self-object)와 비슷

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

  provisioner "local-exec" {
    command = "echo The server's IP address is ${self.private_ip}"
  }
}

프로비저너 종류

  • 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: 로컬 머신에서 명령 실행
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}",
    ]
  }
}

프로비저너 연결

아래 두 프로비저너는 SSH 연결이 필요함

  • file
  • remote_exec

프로비저너 한 개만 따로 연결 하는 경우

  provisioner "file" {
	  connection {
	    type     = "ssh"
	    user     = "root"
	    password = "${var.root_password}"
	    host     = "${var.host}"
	  }
  }

여러 개의 프로비저너에 대한 공통 연결

  provisioner "file" {
  }

  provisioner "file" {
  }

  connection {
  }
key_pair 리소스

ssh 연결 시 필요한 키를 리소스에 정의

resource "aws_key_pair" "deployer" {
  key_name   = "deployer-key"
  public_key = file("/home/vagrant/.ssh/id_rsa.pub")
}
resosurce "aws_instance" "app_server" {
	connection {
    user = "ec2-user"
    host = self.public_ip

    private_key = file("/home/vagrant/.ssh/id_rsa")
    timeout = "1m" # 타임아웃 1분지나서까지 안되면 실패
  }
  provisioner "file" {
    source = "index.html"
    destination = "/var/www/html/index.html"
  }

  key_name = aws_key_pair.deployer.key_name
"

Taint

오염되다, 문제있다, 오류

리소스를 생성/변경 하다가 오류가 생기면, 해당 리소스를 Taint 처리
terraform taint <RESOURCE>

terraform untaint <RESOURCE>

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

프로비저너는 Last Resort

유저데이터를 사용할 수 있다면 유저데이터 사용
프로비저너는 마지막 수단

예시

유저데이터와 프로비저너를 동시에 쓰는경우
유저데이터 - httpd 패키지설치
프로비저너 - file 프로비저너로 index.html 복사
-> 프로비저너가 먼저 실행되어 httpd패키지가 설치되지 않아 에러

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

유저데이터를 사용하지 않고 구현

Ansible 실행 방법

  1. AMI 이미지 내에 ansible을 미리 설치
    • file로 플레이북 및 파일 복사
    • remote-exec로 실행
    • ansible-playbook a.yaml -c local
  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"
  }

ansible -c Connection 기본값이 ssh -> 키 기반인증을 하려함 -> 자기 자신도 인증이 필요합
ssh-copy-id localhost로 키를 복사하거나
-> -c local 옵션으로 로 하면됨 -> ssh를 쓰지않고 로컬 접속을 하겠다

모듈

앤서블의 역할과 비슷
자주사용되는 리소스 들의 모음

module "myvpc" {
	source = 

	...입력 변수...
}
resource "aws_instance" "web" {

  subnet_id = module.myvpc.<출력값>
}

모듈 초기화

모듈을 사용하여 코드를 짠 경우 초기화를 진행시켜 모듈을 다운받아야 함

terraform init

vpc 모듈

aws의 vpc를 생성하기 위한 모듈

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = true
  enable_vpn_gateway = true

  tags = {
    Terraform = "true"
    Environment = "dev"
  }
}

보안그룹이 같은 VPC에 있는지 확인할 것

profile
Ken, 🔽🔽 거노밥 유튜브(house icon) 🔽🔽

0개의 댓글