출력값
공식 문서: https://learn.hashicorp.com/tutorials/terraform/aws-outputs?in=terraform/aws-get-started
how 🐳 ~/terraform/01 $ cat output.tf
output "instance_id" {
description = "ID of the EC2 instance"
value = aws_instance.app_server.id
}
how 🐳 ~/terraform/01 $ terraform output
app_server_ip = "3.38.88.206"
로컬값
테라폼 내부에서만 사용하는 변수, 스코프가 테라폼 내부에만 잡혀있다고 생각하면 된다.
input variable 이나 output 과는 다르다.
함수 test(a, b, c) 로 예를 들어보면 input variable 은 함수의 알규먼트인 a,b,c 에 해당하고 output 은 test(a, b, c) 의 리턴값이다. 로컬값은 이제 함수 내부에 정의된 변수들이라고 생각하면 된다.
주로 태그를 붙일 때 사용한다.
locals {
common_tags = {
Name = "My Terraform"
Environment = var.env
AZ = var.aws_availability_zone[var.aws_region]
}
}
resource "aws_instance" "app_server" {
ami = var.aws_amazon_linux_ami[var.aws_region]
instance_type = var.instance.type
availability_zone = var.aws_availability_zone[var.aws_region]
tags = local.common_tags
# 명시적 의존성
depends_on = [
aws_s3_bucket.b
]
}
resource "aws_s3_bucket" "b" {
bucket = "csw-test-bucker"
tags = local.common_tags
}
사용자 데이터(User Data)
user data 는 base64 로 인코딩 해준다.
resource "aws_instance" "app_server" {
ami = var.aws_amazon_linux_ami[var.aws_region]
instance_type = var.instance.type
availability_zone = var.aws_availability_zone[var.aws_region]
user_data = <<-EOF
#!/bin/bash
yum -y install httpd
systemctl enable --now httpd
echo "hello world" > /var/www/html/index.html
EOF
tags = local.common_tags
vpc_security_group_ids = [aws_security_group.app_server_sg.id]
# 명시적 의존성
depends_on = [
aws_s3_bucket.b
]
}
위와 같은 방식으로 user_data 를 명시적으로 작성할 수 있거나
resource "aws_instance" "app_server" {
ami = var.aws_amazon_linux_ami[var.aws_region]
instance_type = var.instance.type
availability_zone = var.aws_availability_zone[var.aws_region]
user_data = file("userdata.sh")
tags = local.common_tags
vpc_security_group_ids = [aws_security_group.app_server_sg.id]
# 명시적 의존성
depends_on = [
aws_s3_bucket.b
]
}
file 함수를 사용하여 특정 파일에서 userdata를 읽을 수 있다.
프로비저너
공식 문서: https://www.terraform.io/language/resources/provisioners/syntax
프로비저너 종류
- 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 연결이 필수이다.(https://www.terraform.io/language/resources/provisioners/syntax#the-self-object)
- file
- remote_exec
# Copies the file as the root user using SSH
provisioner "file" {
source = "conf/myapp.conf"
destination = "/etc/myapp.conf"
connection {
type = "ssh"
user = "root"
password = "${var.root_password}"
host = "${var.host}"
}
}
Tainted
오염되다, 문제있다. 오류
# aws_instance.app_server: (tainted)
resource "aws_instance" "app_server" {
ami = "ami-02de72c5dc79358c9"
arn = "arn:aws:ec2:ap-northeast-2:007442965030:instance/i-01778fddefa71face"
associate_public_ip_address = true
availability_zone = "ap-northeast-2c"
리소스를 생성/변경 하다 오류가 발생하면, 해당 리소스를 Taint 처리한다.
terrform taint <RESOURCE> : 해당 리소스에 Taint 를 걸어준다.
terraform untaint <RESOURCE> : Taint 된 리소스를 untaint 처리를 해준다.
Taint 처리된 리소스는 다음 작업 시 무조건 재생성된다.
Ansible 실행 방법
- AMI 이미지 내에 ansible 을 미리 설치
- file 로 플레이북 및 파일 복사
- remote-exec 로 실행
- ansible-playbook a.yml -c local (자기 자신한테 접속할 때)
- 로컬에서 실행
- 로컬에 ansible 이 설치되어 있어야 함
- local-exec 로 인벤토리 생성
- local-exec 로 ansible-playbook 실행
local-exec 를 사용하여 ansible 사용
resource "aws_key_pair" "app_server_key" {
key_name = "app_server_key"
public_key = file("/Users/csw/.ssh/id_rsa.pub")
}
resource "aws_instance" "app_server" {
ami = var.aws_amazon_linux_ami[var.aws_region]
instance_type = var.instance.type
availability_zone = var.aws_availability_zone[var.aws_region]
key_name = aws_key_pair.app_server_key.key_name
connection {
type = "ssh"
user = "ec2-user"
host = self.public_ip
private_key = file("/Users/csw/.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.yml -b"
}
tags = local.common_tags
vpc_security_group_ids = [aws_security_group.app_server_sg.id]
# 명시적 의존성
depends_on = [
aws_s3_bucket.b
]
}
resource "aws_eip" "app_server_eip" {
# 암시적 의존성
instance = aws_instance.app_server.id
vpc = true
tags = local.common_tags
}
resource "aws_s3_bucket" "b" {
bucket = "csw-test-bucker"
tags = local.common_tags
}
resource "aws_s3_bucket_acl" "example" {
bucket = aws_s3_bucket.b.id
acl = "private"
}
playbook 은 아래와 같다. 단순히 httpd 패키지 다운로드하고 서비스 실행한 뒤에 index.html 파일을 만든다.
- hosts: all
tasks:
- yum:
name: httpd
- service:
name: httpd
state: started
enabled: yes
- copy:
content: "<h1>hello teraform</h1>"
dest: "/var/www/html/index.html"